static void httpd_output_unbind(struct httpd_output *httpd) { assert(!httpd->open); g_mutex_lock(httpd->mutex); server_socket_close(httpd->server_socket); g_mutex_unlock(httpd->mutex); }
void server_socket_free(struct server_socket *ss) { server_socket_close(ss); while (ss->sockets != NULL) { struct one_socket *s = ss->sockets; ss->sockets = s->next; assert(s->fd < 0); g_free(s->path); g_free(s); } g_free(ss); }
static int server_socket_create (void) { struct sockaddr_un serv_addr; int fd = -1; int rc = -1; if ((rc = assuan_sock_init()) != 0) { common_log (LOG_ERROR,"Cannot init socket %s", gpg_strerror (rc)); goto cleanup; } memset (&serv_addr, 0, sizeof (serv_addr)); serv_addr.sun_family = AF_UNIX; assert (strlen (s_socket_name) + 1 < sizeof (serv_addr.sun_path)); strcpy (serv_addr.sun_path, s_socket_name); if ((fd = assuan_sock_new (AF_UNIX, SOCK_STREAM, 0)) == -1) { common_log (LOG_ERROR, "Cannot create socket", s_socket_name); goto cleanup; } if ((rc = assuan_sock_bind (fd, (struct sockaddr*)&serv_addr, sizeof (serv_addr))) == -1) { common_log (LOG_ERROR, "Cannot bing to socket '%s'", s_socket_name); goto cleanup; } if ((rc = listen (fd, SOMAXCONN)) == -1) { common_log (LOG_ERROR, "Cannot listen to socket '%s'", s_socket_name); goto cleanup; } rc = 0; cleanup: if (rc != 0) { server_socket_close (fd); common_log (LOG_FATAL, "Cannot handle socket"); } common_log (LOG_INFO, "Listening to socket '%s'", s_socket_name); return fd; }
bool server_socket_open(struct server_socket *ss, GError **error_r) { struct one_socket *good = NULL, *bad = NULL; GError *last_error = NULL; for (struct one_socket *s = ss->sockets; s != NULL; s = s->next) { assert(s->serial > 0); assert(good == NULL || s->serial >= good->serial); assert(s->fd < 0); if (bad != NULL && s->serial != bad->serial) { server_socket_close(ss); g_propagate_error(error_r, last_error); return false; } GError *error = NULL; s->fd = socket_bind_listen(s->address.sa_family, SOCK_STREAM, 0, &s->address, s->address_length, 5, &error); if (s->fd < 0) { if (good != NULL && good->serial == s->serial) { char *address_string = one_socket_to_string(s); char *good_string = one_socket_to_string(good); g_warning("bind to '%s' failed: %s " "(continuing anyway, because " "binding to '%s' succeeded)", address_string, error->message, good_string); g_free(address_string); g_free(good_string); g_error_free(error); } else if (bad == NULL) { bad = s; char *address_string = one_socket_to_string(s); g_propagate_prefixed_error(&last_error, error, "Failed to bind to '%s': ", address_string); g_free(address_string); } else g_error_free(error); continue; } /* allow everybody to connect */ if (s->path != NULL) chmod(s->path, 0666); /* register in the GLib main loop */ GIOChannel *channel = g_io_channel_unix_new(s->fd); s->source_id = g_io_add_watch(channel, G_IO_IN, server_socket_in_event, s); g_io_channel_unref(channel); /* mark this socket as "good", and clear previous errors */ good = s; if (bad != NULL) { bad = NULL; g_error_free(last_error); last_error = NULL; } } if (bad != NULL) { server_socket_close(ss); g_propagate_error(error_r, last_error); return false; } return true; }
int main (int argc, char *argv[]) { enum { OPT_SERVER, OPT_MUTLI_SERVER, OPT_DAEMON, OPT_VERBOSE, OPT_QUIET, OPT_SH, OPT_CSH, OPT_OPTIONS, OPT_NO_DETACH, OPT_LOG_FILE, OPT_VERSION, OPT_HELP }; static struct option long_options[] = { { "server", no_argument, NULL, OPT_SERVER }, { "multi-server", no_argument, NULL, OPT_MUTLI_SERVER }, { "daemon", no_argument, NULL, OPT_DAEMON }, { "verbose", no_argument, NULL, OPT_VERBOSE }, { "quiet", no_argument, NULL, OPT_QUIET }, { "sh", no_argument, NULL, OPT_SH }, { "csh", no_argument, NULL, OPT_CSH }, { "options", required_argument, NULL, OPT_OPTIONS }, { "no-detach", no_argument, NULL, OPT_NO_DETACH }, { "log-file", required_argument, NULL, OPT_LOG_FILE }, { "version", no_argument, NULL, OPT_VERSION }, { "help", no_argument, NULL, OPT_HELP }, { NULL, 0, NULL, 0 } }; int long_options_ret; int base_argc = 1; int usage_ok = 1; enum { RUN_MODE_NONE, RUN_MODE_SERVER, RUN_MODE_MULTI_SERVER, RUN_MODE_DAEMON } run_mode = RUN_MODE_NONE; int env_is_csh = 0; int log_verbose = 0; int log_quiet = 0; int no_detach = 0; char *config_file = NULL; char *log_file = NULL; char *home_dir = NULL; int have_at_least_one_provider=0; FILE *fp_log = NULL; int i; CK_RV rv; dconfig_data_t config; const char * CONFIG_SUFFIX = ".conf"; char *default_config_file = NULL; #if !defined(HAVE_W32_SYSTEM) s_parent_pid = getpid (); #endif if ((default_config_file = (char *)malloc (strlen (PACKAGE)+strlen (CONFIG_SUFFIX)+1)) == NULL) { common_log (LOG_FATAL, "malloc failed"); } sprintf (default_config_file, "%s%s", PACKAGE, CONFIG_SUFFIX); common_set_log_stream (stderr); while ((long_options_ret = getopt_long (argc, argv, "vqsc", long_options, NULL)) != -1) { base_argc++; switch (long_options_ret) { case OPT_SERVER: run_mode = RUN_MODE_SERVER; break; case OPT_MUTLI_SERVER: run_mode = RUN_MODE_MULTI_SERVER; break; case OPT_DAEMON: run_mode = RUN_MODE_DAEMON; break; case OPT_VERBOSE: case 'v': log_verbose = 1; break; case OPT_QUIET: case 'q': log_quiet = 1; break; case OPT_SH: case 's': break; case OPT_CSH: case 'c': env_is_csh = 1; break; case OPT_OPTIONS: base_argc++; config_file = strdup (optarg); break; case OPT_NO_DETACH: no_detach = 1; break; case OPT_LOG_FILE: base_argc++; log_file = strdup (optarg); break; case OPT_VERSION: printf ( "%s %s\n" "\n" "Copyright (c) 2006-2007 Zeljko Vrba <*****@*****.**>\n" "Copyright (c) 2006-2011 Alon Bar-Lev <*****@*****.**>\n" "\n" "This is free software; see the source for copying conditions.\n" "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n", PACKAGE, PACKAGE_VERSION ); exit (1); break; case OPT_HELP: usage_ok = 0; break; default: usage_ok = 0; break; } } if (base_argc < argc) { if (!strcmp (argv[base_argc], "--")) { base_argc++; } } if (!usage_ok) { usage (argv[0]); } if (run_mode == RUN_MODE_NONE) { common_log (LOG_FATAL, "please use the option `--daemon' to run the program in the background"); } #if defined(HAVE_W32_SYSTEM) if (run_mode == RUN_MODE_DAEMON) { common_log (LOG_FATAL, "daemon mode is not supported"); } #endif home_dir = get_home_dir (); if (config_file == NULL) { if ((config_file = (char *)malloc (strlen (home_dir) + strlen (default_config_file)+2)) == NULL) { common_log (LOG_FATAL, "malloc failed"); } sprintf (config_file, "%s%c%s", home_dir, CONFIG_PATH_SEPARATOR, default_config_file); } if ( !dconfig_read (config_file, &config) && !dconfig_read (CONFIG_SYSTEM_CONFIG, &config) ) { common_log (LOG_FATAL, "Cannot open configuration file"); } if (log_file != NULL) { if (config.log_file != NULL) { free (config.log_file); } if ((config.log_file = strdup (log_file)) == NULL) { common_log (LOG_FATAL, "strdup failed"); } } if (log_verbose) { config.verbose = 1; } #if !defined(HAVE_W32_SYSTEM) signal (SIGPIPE, SIG_IGN); signal (SIGINT, on_signal); signal (SIGTERM, on_signal); signal (SIGABRT, on_signal); signal (SIGHUP, on_signal); #endif if (log_file != NULL) { if (strcmp (log_file, "stderr")) { if ((fp_log = fopen (log_file, "a")) != NULL) { common_set_log_stream (fp_log); } } } else if (config.log_file != NULL) { if (strcmp (config.log_file, "stderr")) { if ((fp_log = fopen (config.log_file, "a")) != NULL) { common_set_log_stream (fp_log); } } } if (config.debug) { common_log (LOG_DEBUG, "version: %s", PACKAGE_VERSION); dconfig_print (&config); common_log (LOG_DEBUG, "run_mode: %d", run_mode); common_log (LOG_DEBUG, "crypto: %s", #if defined(ENABLE_OPENSSL) "openssl" #elif defined(ENABLE_GNUTLS) "gnutls" #else "invalid" #endif ); } #if !defined(HAVE_W32_SYSTEM) if (run_mode == RUN_MODE_DAEMON || run_mode == RUN_MODE_MULTI_SERVER) { server_socket_create_name (); } /* * fork before doing PKCS#11 stuff * some providers don't behave well */ if (run_mode == RUN_MODE_DAEMON) { pid_t pid; pid = fork (); if (pid == -1) { common_log (LOG_FATAL, "fork failed"); } if (pid != 0) { static const char *key = "SCDAEMON_INFO"; char env[1024]; snprintf (env, sizeof (env), "%s:%lu:1", s_socket_name, (unsigned long)pid); if (argc - base_argc > 0) { setenv(key, env, 1); execvp (argv[base_argc], &(argv[base_argc])); kill (pid, SIGTERM); exit (1); } else { if (env_is_csh) { *strchr (env, '=') = ' '; printf ("setenv %s %s\n", key, env); } else { printf ("%s=%s; export %s\n", key, env, key); } exit (0); } } if (!no_detach) { int i; for (i=0;i<3;i++) { if (fileno (common_get_log_stream ()) != i) { close (i); } } if (setsid () == -1) { common_log (LOG_FATAL, "setsid failed"); } } if (chdir ("/") == -1) { common_log (LOG_FATAL, "chdir failed"); } if (argc - base_argc > 0) { struct sigaction sa; memset (&sa, 0, sizeof (sa)); sigemptyset (&sa.sa_mask); #if defined(SA_INTERRUPT) sa.sa_flags |= SA_INTERRUPT; #endif sa.sa_handler = on_alarm; sigaction (SIGALRM, &sa, NULL); alarm (10); } } #endif /* HAVE_W32_SYSTEM */ assuan_set_assuan_log_prefix (PACKAGE); assuan_set_assuan_log_stream (common_get_log_stream ()); #if defined(USE_GNUTLS) if (gnutls_global_init () != GNUTLS_E_SUCCESS) { common_log (LOG_FATAL, "Cannot initialize gnutls"); } #endif if ((rv = pkcs11h_initialize ()) != CKR_OK) { common_log (LOG_FATAL, "Cannot initialize PKCS#11: %s", pkcs11h_getMessage (rv)); } pkcs11h_setLogLevel (config.verbose ? PKCS11H_LOG_DEBUG2 : PKCS11H_LOG_INFO); pkcs11h_setLogHook (pkcs11_log_hook, NULL); pkcs11h_setTokenPromptHook (pkcs11_token_prompt_hook, NULL); pkcs11h_setPINPromptHook (pkcs11_pin_prompt_hook, NULL); pkcs11h_setProtectedAuthentication (TRUE); for (i=0;i<DCONFIG_MAX_PROVIDERS;i++) { if ( config.providers[i].name != NULL && config.providers[i].library != NULL ) { if ( (rv = pkcs11h_addProvider ( config.providers[i].name, config.providers[i].library, config.providers[i].allow_protected, config.providers[i].private_mask, PKCS11H_SLOTEVENT_METHOD_POLL, 0, config.providers[i].cert_is_private )) != CKR_OK ) { common_log (LOG_WARNING, "Cannot add PKCS#11 provider '%s': %ld-'%s'", config.providers[i].name, rv, pkcs11h_getMessage (rv)); } else { have_at_least_one_provider = 1; } } } if (!have_at_least_one_provider) { common_log (LOG_FATAL, "Could not load any provider"); } #if defined(HAVE_W32_SYSTEM) command_handler (-1, &config); #else { pthread_t accept_thread = 0; int accept_socket = -1; if (run_mode == RUN_MODE_DAEMON || run_mode == RUN_MODE_MULTI_SERVER) { accept_socket = server_socket_create (); server_socket_accept (accept_socket, &accept_thread, &config); } if (run_mode == RUN_MODE_DAEMON) { /* * Emulate assuan behavior */ int fds[2]; char c; if (pipe (fds)==-1) { common_log (LOG_FATAL, "Could not create pipe"); } close (0); dup2 (fds[0], 0); close (fds[0]); while (read (0, &c, 1) == -1 && errno == EINTR); close (fds[1]); } else { command_handler (-1, &config); } if (run_mode == RUN_MODE_DAEMON || run_mode == RUN_MODE_MULTI_SERVER) { server_socket_accept_terminate (accept_thread); server_socket_close (accept_socket); } } #endif pkcs11h_terminate (); #if defined(USE_GNUTLS) gnutls_global_deinit (); #endif dconfig_free (&config); if (log_file != NULL) { free (log_file); log_file = NULL; } if (config_file != NULL) { free (config_file); config_file = NULL; } if (default_config_file != NULL) { free (default_config_file); default_config_file = NULL; } if (home_dir != NULL) { free (home_dir); home_dir = NULL; } if (fp_log != NULL) { fclose (fp_log); fp_log = NULL; } return 0; }