/* Takes ownership of startup */ static gboolean infinoted_main_run(InfinotedStartup* startup, GError** error) { InfinotedRun* run; InfinotedSignal* sig; #ifdef LIBINFINITY_HAVE_LIBDAEMON mode_t prev_umask; pid_t pid; int saved_errno; #endif /* infinoted_run_new() takes ownership of startup */ run = infinoted_run_new(startup, error); if(run == NULL) { infinoted_startup_free(startup); return FALSE; } #ifdef LIBINFINITY_HAVE_LIBDAEMON if(startup->options->daemonize) { prev_umask = umask(0777); if(daemon_retval_init() == -1) { infinoted_run_free(run); return FALSE; /* libdaemon already wrote an error message */ } pid = daemon_fork(); if(pid < 0) { /* Translators: fork as in "fork into the background" */ infinoted_util_set_errno_error(error, errno, _("Failed to fork")); infinoted_run_free(run); daemon_retval_done(); return FALSE; } else if(pid > 0) { infinoted_run_free(run); saved_errno = daemon_retval_wait(5); if(saved_errno == 0) { return TRUE; } if(saved_errno == -1) { infinoted_util_set_errno_error(error, errno, _("Failed to wait for daemonized child's return value")); return FALSE; } else { /* on -1, the child process would have subtracted one from * errno before passing it back to us. */ if(saved_errno < 0) ++saved_errno; infinoted_util_set_errno_error( error, saved_errno, _("Failed to create PID file")); return FALSE; } } else { infinoted_util_daemon_set_global_pid_file_proc(); if(daemon_pid_file_create() != 0) { infinoted_util_daemon_set_local_pid_file_proc(); if(daemon_pid_file_create() != 0) { if(daemon_pid_file_create() != 0) { saved_errno = errno; infinoted_util_set_errno_error( error, saved_errno, _("Failed to create PID file") ); if(saved_errno < 0) --saved_errno; daemon_retval_send(saved_errno); infinoted_run_free(run); return FALSE; } } } daemon_retval_send(0); } /* libdaemon sets the umask to either 0777 (< 0.14) or 0077 (>= 0.14). * We don't want either of that, to make sure the directory tree is * always readable by us and potentially by others (for example, a * webserver providing read access to the documents). Therefore, reset * the umask here to what it previously was, so the system administrator * can define the umask by setting it before launching infinoted. * See also http://gobby.0x539.de/trac/ticket/617. */ umask(prev_umask); } #endif sig = infinoted_signal_register(run); /* Now start the server. It can later be stopped by signals. */ infinoted_run_start(run); infinoted_signal_unregister(sig); #ifdef LIBINFINITY_HAVE_LIBDAEMON /* startup might be invalid at this point in case a config reload happened, * so use run->startup instead (which is revalidated by config reload). */ if(run->startup->options->daemonize) daemon_pid_file_remove(); #endif infinoted_run_free(run); return TRUE; }
static gboolean infinoted_options_load(InfinotedOptions* options, const gchar* const* config_files, int* argc, char*** argv, GError** error) { const gchar* const* file; gchar* security_policy; gint port_number; gboolean display_version; #ifdef LIBINFINITY_HAVE_LIBDAEMON gboolean kill_daemon; #endif gint autosave_interval; gint sync_interval; guint i; gboolean result; GOptionContext *context; gchar* desc; GOptionEntry entries[] = { { "key-file", 'k', 0, G_OPTION_ARG_FILENAME, NULL, N_("The server's private key"), N_("KEY-FILE") }, { "certificate-file", 'c', 0, G_OPTION_ARG_FILENAME, NULL, N_("The server's certificate"), N_("CERTIFICATE-FILE") }, { "certificate-chain", 0, 0, G_OPTION_ARG_FILENAME, NULL, N_("The certificates chain down to the root certificate"), NULL }, { "create-key", 0, G_OPTION_FLAG_NO_CONFIG_FILE, G_OPTION_ARG_NONE, NULL, N_("Creates a new random private key"), NULL }, { "create-certificate", 0, G_OPTION_FLAG_NO_CONFIG_FILE, G_OPTION_ARG_NONE, NULL, N_("Creates a new self-signed certificate using the given key"), NULL }, { "port-number", 'p', 0, G_OPTION_ARG_INT, NULL, N_("The port number to listen on"), N_("PORT") }, { "security-policy", 0, 0, G_OPTION_ARG_STRING, NULL, N_("How to decide whether to use TLS"), "no-tls|allow-tls|require-tls" }, { "root-directory", 'r', 0, G_OPTION_ARG_FILENAME, NULL, N_("The directory to store documents into"), N_("DIRECTORY") }, { "autosave-interval", 0, 0, G_OPTION_ARG_INT, NULL, N_("Interval within which to save documents, in seconds, or 0 to " "disable autosave"), N_("INTERVAL") }, { "password", 'P', 0, G_OPTION_ARG_STRING, NULL, N_("Require given password on connections"), N_("PASSWORD") }, #ifdef LIBINFINITY_HAVE_PAM { "pam-service", 0, 0, G_OPTION_ARG_STRING, NULL, N_("Authenticate clients against given pam service on connection"), N_("SERVICE") }, { "allow-user", 0, 0, G_OPTION_ARG_STRING_ARRAY, NULL, N_("User allowed to connect after pam authentication"), N_("USER") }, { "allow-group", 0, 0, G_OPTION_ARG_STRING_ARRAY, NULL, N_("Group allowed to connect after pam authentication"), N_("GROUP") }, #endif /* LIBINFINITY_HAVE_PAM */ { "sync-directory", 0, 0, G_OPTION_ARG_FILENAME, NULL, N_("A directory into which to periodically store a copy of the " "document tree"), N_("DIRECTORY") }, { "sync-interval", 0, 0, G_OPTION_ARG_INT, NULL, N_("Interval within which to store documents to the specified " "sync-directory, or 0 to disable directory synchronization"), N_("INTERVAL") }, #ifdef LIBINFINITY_HAVE_LIBDAEMON { "daemonize", 'd', 0, G_OPTION_ARG_NONE, NULL, N_("Daemonize the server"), NULL }, { "kill-daemon", 'D', 0, G_OPTION_ARG_NONE, NULL, N_("Kill a running daemon"), NULL }, #endif { "version", 'v', G_OPTION_FLAG_NO_CONFIG_FILE, G_OPTION_ARG_NONE, NULL, N_("Display version information and exit"), NULL }, { NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, 0 } }; /* C90 does not allow non-compile-time-constant initializers for structs */ i = 0; entries[i++].arg_data = &options->key_file; entries[i++].arg_data = &options->certificate_file; entries[i++].arg_data = &options->certificate_chain_file; entries[i++].arg_data = &options->create_key; entries[i++].arg_data = &options->create_certificate; entries[i++].arg_data = &port_number; entries[i++].arg_data = &security_policy; entries[i++].arg_data = &options->root_directory; entries[i++].arg_data = &autosave_interval; entries[i++].arg_data = &options->password; #ifdef LIBINFINITY_HAVE_PAM entries[i++].arg_data = &options->pam_service; entries[i++].arg_data = &options->pam_allowed_users; entries[i++].arg_data = &options->pam_allowed_groups; #endif /* LIBINFINITY_HAVE_PAM */ entries[i++].arg_data = &options->sync_directory; entries[i++].arg_data = &sync_interval; #ifdef LIBINFINITY_HAVE_LIBDAEMON entries[i++].arg_data = &options->daemonize; entries[i++].arg_data = &kill_daemon; #endif entries[i++].arg_data = &display_version; display_version = FALSE; #ifdef LIBINFINITY_HAVE_LIBDAEMON kill_daemon = FALSE; #endif security_policy = NULL; port_number = infinoted_options_port_to_integer(options->port); autosave_interval = options->autosave_interval; sync_interval = options->sync_interval; if(config_files) { for(file = config_files; *file != NULL; ++ file) { if(infinoted_options_load_file(entries, *file, error) == FALSE) { g_prefix_error(error, "%s: ", *file); g_free(security_policy); return FALSE; } } } if(argc != NULL && argv != NULL) { desc = g_strdup_printf("- %s", _("infinote dedicated server")); context = g_option_context_new(desc); g_free(desc); g_option_context_add_main_entries(context, entries, GETTEXT_PACKAGE); if(g_option_context_parse(context, argc, argv, error) == FALSE) { g_option_context_free(context); g_free(security_policy); return FALSE; } if(display_version) { printf("infinoted %s\n", PACKAGE_VERSION); exit(0); } #ifdef LIBINFINITY_HAVE_LIBDAEMON if(kill_daemon) { g_free(security_policy); infinoted_util_daemon_set_global_pid_file_proc(); if(infinoted_util_daemon_pid_file_kill(SIGTERM) != 0) { infinoted_util_daemon_set_local_pid_file_proc(); if(infinoted_util_daemon_pid_file_kill(SIGTERM) != 0) { infinoted_util_set_errno_error(error, errno, _("Could not kill daemon")); return FALSE; } } exit(0); } #endif g_option_context_free(context); } if(security_policy != NULL) { result = infinoted_options_policy_from_string( security_policy, &options->security_policy, error ); g_free(security_policy); if(!result) return FALSE; } /* TODO: Do we leak security_policy at this point? */ result = infinoted_options_port_from_integer( port_number, &options->port, error ); if(!result) return FALSE; result = infinoted_options_interval_from_integer( autosave_interval, &options->autosave_interval, error ); if(!result) return FALSE; result = infinoted_options_interval_from_integer( sync_interval, &options->sync_interval, error ); if(!result) return FALSE; if(options->password != NULL && strcmp(options->password, "") == 0) { g_free(options->password); options->password = NULL; } #ifdef LIBINFINITY_HAVE_PAM if(options->pam_service != NULL && strcmp(options->pam_service, "") == 0) { g_free(options->pam_service); options->pam_service = NULL; } /* treat it as undefining the option if only one entry, which is empty, * is given */ if(options->pam_allowed_users != NULL && strcmp(options->pam_allowed_users[0], "") == 0 && options->pam_allowed_users[1] == NULL) { g_free(options->pam_allowed_users[0]); g_free(options->pam_allowed_users); } if(options->pam_allowed_groups != NULL && strcmp(options->pam_allowed_groups[0], "") == 0 && options->pam_allowed_groups[1] == NULL) { g_free(options->pam_allowed_groups[0]); g_free(options->pam_allowed_groups); } #endif /* LIBINFINITY_HAVE_PAM */ if(options->sync_directory != NULL && strcmp(options->sync_directory, "") == 0) { g_free(options->sync_directory); options->sync_directory = NULL; } return infinoted_options_validate(options, error); }