123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533 |
- /*
- This file is part of GNUnet.
- Copyright (C) 2013 GNUnet e.V.
- GNUnet is free software: you can redistribute it and/or modify it
- under the terms of the GNU Affero General Public License as published
- by the Free Software Foundation, either version 3 of the License,
- or (at your option) any later version.
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Affero General Public License for more details.
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- SPDX-License-Identifier: AGPL3.0-or-later
- */
- /**
- * @file gns/gnunet-bcd.c
- * @author Christian Grothoff
- * @brief HTTP server to create GNS business cards
- */
- #include "platform.h"
- #include <microhttpd.h>
- #include "gnunet_util_lib.h"
- #include "gnunet_identity_service.h"
- #include "gnunet_mhd_compat.h"
- /**
- * Error page to display if submitted GNS key is invalid.
- */
- #define INVALID_GNSKEY \
- "<html><head><title>Error</title><body>Invalid GNS public key given.</body></html>"
- /**
- * Error page to display on 404.
- */
- #define NOT_FOUND \
- "<html><head><title>Error</title><body>404 not found</body></html>"
- /**
- * Handle to the HTTP server as provided by libmicrohttpd
- */
- static struct MHD_Daemon *daemon_handle;
- /**
- * Our configuration.
- */
- static const struct GNUNET_CONFIGURATION_Handle *cfg;
- /**
- * Our primary task for the HTTPD.
- */
- static struct GNUNET_SCHEDULER_Task *http_task;
- /**
- * Our main website.
- */
- static struct MHD_Response *main_response;
- /**
- * Error: invalid gns key.
- */
- static struct MHD_Response *invalid_gnskey_response;
- /**
- * Error: 404
- */
- static struct MHD_Response *not_found_response;
- /**
- * Absolute name of the 'gns-bcd.tex' file.
- */
- static char *resfile;
- /**
- * Port number.
- */
- static uint16_t port = 8888;
- struct Entry
- {
- const char *formname;
- const char *texname;
- };
- /**
- * Main request handler.
- */
- static MHD_RESULT
- access_handler_callback (void *cls,
- struct MHD_Connection *connection,
- const char *url,
- const char *method,
- const char *version,
- const char *upload_data,
- size_t *upload_data_size,
- void **con_cls)
- {
- static int dummy;
- static const struct Entry map[] = { { "prefix", "prefix" },
- { "name", "name" },
- { "suffix", "suffix" },
- { "street", "street" },
- { "city", "city" },
- { "phone", "phone" },
- { "fax", "fax" },
- { "email", "email" },
- { "homepage", "homepage" },
- { "orga", "orga" },
- { "departmenti18n", "departmentde" },
- { "departmenten", "departmenten" },
- { "subdepartmenti18n",
- "subdepartmentde" },
- { "subdepartmenten", "subdepartmenten" },
- { "jobtitlei18n", "jobtitlegerman" },
- { "jobtitleen", "jobtitleenglish" },
- { "subdepartmenten", "subdepartmenten" },
- { NULL, NULL } };
- (void) cls;
- (void) version;
- (void) upload_data;
- (void) upload_data_size;
- if (0 != strcmp (method, MHD_HTTP_METHOD_GET))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _ ("Refusing `%s' request to HTTP server\n"),
- method);
- return MHD_NO;
- }
- if (NULL == *con_cls)
- {
- (*con_cls) = &dummy;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending 100 CONTINUE reply\n");
- return MHD_YES; /* send 100 continue */
- }
- if (0 == strcasecmp (url, "/"))
- return MHD_queue_response (connection, MHD_HTTP_OK, main_response);
- if (0 == strcasecmp (url, "/submit.pdf"))
- {
- unsigned int i;
- char *p;
- char *tmp;
- char *deffile;
- struct GNUNET_IDENTITY_PublicKey pub;
- size_t slen;
- FILE *f;
- struct stat st;
- struct MHD_Response *response;
- int fd;
- MHD_RESULT ret;
- const char *gpg_fp = MHD_lookup_connection_value (connection,
- MHD_GET_ARGUMENT_KIND,
- "gpgfingerprint");
- const char *gns_nick = MHD_lookup_connection_value (connection,
- MHD_GET_ARGUMENT_KIND,
- "gnsnick");
- const char *gnskey =
- MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, "gnskey");
- if ((NULL == gnskey) ||
- (GNUNET_OK !=
- GNUNET_IDENTITY_public_key_from_string (gnskey,
- &pub)))
- {
- return MHD_queue_response (connection,
- MHD_HTTP_OK,
- invalid_gnskey_response);
- }
- tmp = GNUNET_DISK_mkdtemp (gnskey);
- if (NULL == tmp)
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "mktemp", gnskey);
- return MHD_NO;
- }
- GNUNET_asprintf (&deffile, "%s%s%s", tmp, DIR_SEPARATOR_STR, "def.tex");
- f = fopen (deffile, "w");
- if (NULL == f)
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", deffile);
- GNUNET_free (deffile);
- GNUNET_DISK_directory_remove (tmp);
- GNUNET_free (tmp);
- return MHD_NO;
- }
- for (i = 0; NULL != map[i].formname; i++)
- {
- const char *val = MHD_lookup_connection_value (connection,
- MHD_GET_ARGUMENT_KIND,
- map[i].formname);
- if (NULL != val)
- fprintf (f, "\\def\\%s{%s}\n", map[i].texname, val);
- else
- fprintf (f, "\\def\\%s{}\n", map[i].texname);
- }
- if (NULL != gpg_fp)
- {
- char *gpg1;
- char *gpg2;
- slen = strlen (gpg_fp);
- gpg1 = GNUNET_strndup (gpg_fp, slen / 2);
- gpg2 = GNUNET_strdup (&gpg_fp[slen / 2]);
- fprintf (f, "\\def\\gpglineone{%s}\n\\def\\gpglinetwo{%s}\n", gpg1, gpg2);
- GNUNET_free (gpg2);
- GNUNET_free (gpg1);
- }
- fprintf (f,
- "\\def\\gns{%s/%s}\n",
- gnskey,
- (NULL == gns_nick) ? "" : gns_nick);
- fclose (f);
- GNUNET_asprintf (
- &p,
- "cd %s; cp %s gns-bcd.tex | pdflatex --enable-write18 gns-bcd.tex > /dev/null 2> /dev/null",
- tmp,
- resfile);
- GNUNET_free (deffile);
- ret = system (p);
- if (WIFSIGNALED (ret) || (0 != WEXITSTATUS (ret)))
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "system", p);
- GNUNET_asprintf (&deffile, "%s%s%s", tmp, DIR_SEPARATOR_STR, "gns-bcd.pdf");
- fd = open (deffile, O_RDONLY);
- if (-1 == fd)
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", deffile);
- GNUNET_free (deffile);
- GNUNET_free (p);
- GNUNET_DISK_directory_remove (tmp);
- GNUNET_free (tmp);
- return MHD_NO;
- }
- GNUNET_break (0 == stat (deffile, &st));
- if (NULL ==
- (response = MHD_create_response_from_fd ((size_t) st.st_size, fd)))
- {
- GNUNET_break (0);
- GNUNET_break (0 == close (fd));
- GNUNET_free (deffile);
- GNUNET_free (p);
- GNUNET_DISK_directory_remove (tmp);
- GNUNET_free (tmp);
- return MHD_NO;
- }
- (void) MHD_add_response_header (response,
- MHD_HTTP_HEADER_CONTENT_TYPE,
- "application/pdf");
- ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
- MHD_destroy_response (response);
- GNUNET_free (deffile);
- GNUNET_free (p);
- GNUNET_DISK_directory_remove (tmp);
- GNUNET_free (tmp);
- return ret;
- }
- return MHD_queue_response (connection,
- MHD_HTTP_NOT_FOUND,
- not_found_response);
- }
- /**
- * Function that queries MHD's select sets and
- * starts the task waiting for them.
- */
- static struct GNUNET_SCHEDULER_Task *
- prepare_daemon (struct MHD_Daemon *daemon_handle);
- /**
- * Call MHD to process pending requests and then go back
- * and schedule the next run.
- */
- static void
- run_daemon (void *cls)
- {
- struct MHD_Daemon *daemon_handle = cls;
- http_task = NULL;
- GNUNET_assert (MHD_YES == MHD_run (daemon_handle));
- http_task = prepare_daemon (daemon_handle);
- }
- /**
- * Function that queries MHD's select sets and
- * starts the task waiting for them.
- */
- static struct GNUNET_SCHEDULER_Task *
- prepare_daemon (struct MHD_Daemon *daemon_handle)
- {
- struct GNUNET_SCHEDULER_Task *ret;
- fd_set rs;
- fd_set ws;
- fd_set es;
- struct GNUNET_NETWORK_FDSet *wrs;
- struct GNUNET_NETWORK_FDSet *wws;
- int max;
- MHD_UNSIGNED_LONG_LONG timeout;
- int haveto;
- struct GNUNET_TIME_Relative tv;
- FD_ZERO (&rs);
- FD_ZERO (&ws);
- FD_ZERO (&es);
- wrs = GNUNET_NETWORK_fdset_create ();
- wws = GNUNET_NETWORK_fdset_create ();
- max = -1;
- GNUNET_assert (MHD_YES == MHD_get_fdset (daemon_handle, &rs, &ws, &es, &max));
- haveto = MHD_get_timeout (daemon_handle, &timeout);
- if (haveto == MHD_YES)
- tv.rel_value_us = (uint64_t) timeout * 1000LL;
- else
- tv = GNUNET_TIME_UNIT_FOREVER_REL;
- GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
- GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
- ret = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
- tv,
- wrs,
- wws,
- &run_daemon,
- daemon_handle);
- GNUNET_NETWORK_fdset_destroy (wrs);
- GNUNET_NETWORK_fdset_destroy (wws);
- return ret;
- }
- /**
- * Start server offering our hostlist.
- *
- * @return #GNUNET_OK on success
- */
- static int
- server_start ()
- {
- if (0 == port)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _ ("Invalid port number %u. Exiting.\n"),
- port);
- return GNUNET_SYSERR;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- _ ("Businesscard HTTP server starts on %u\n"),
- port);
- daemon_handle = MHD_start_daemon (MHD_USE_DUAL_STACK | MHD_USE_DEBUG,
- port,
- NULL /* accept_policy_callback */,
- NULL,
- &access_handler_callback,
- NULL,
- MHD_OPTION_CONNECTION_LIMIT,
- (unsigned int) 512,
- MHD_OPTION_PER_IP_CONNECTION_LIMIT,
- (unsigned int) 2,
- MHD_OPTION_CONNECTION_TIMEOUT,
- (unsigned int) 60,
- MHD_OPTION_CONNECTION_MEMORY_LIMIT,
- (size_t) (16 * 1024),
- MHD_OPTION_END);
- if (NULL == daemon_handle)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _ ("Could not start businesscard HTTP server on port %u\n"),
- (unsigned int) port);
- return GNUNET_SYSERR;
- }
- http_task = prepare_daemon (daemon_handle);
- return GNUNET_OK;
- }
- /**
- * Stop HTTP server.
- */
- static void
- server_stop (void *cls)
- {
- (void) cls;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "HTTP server shutdown\n");
- if (NULL != http_task)
- {
- GNUNET_SCHEDULER_cancel (http_task);
- http_task = NULL;
- }
- if (NULL != daemon_handle)
- {
- MHD_stop_daemon (daemon_handle);
- daemon_handle = NULL;
- }
- if (NULL != main_response)
- {
- MHD_destroy_response (main_response);
- main_response = NULL;
- }
- if (NULL != invalid_gnskey_response)
- {
- MHD_destroy_response (invalid_gnskey_response);
- invalid_gnskey_response = NULL;
- }
- if (NULL != not_found_response)
- {
- MHD_destroy_response (not_found_response);
- not_found_response = NULL;
- }
- if (NULL != resfile)
- {
- GNUNET_free (resfile);
- resfile = NULL;
- }
- }
- /**
- * Main function that will be run.
- *
- * @param cls closure
- * @param args remaining command-line arguments
- * @param cfgfile name of the configuration file used (for saving, can be NULL!)
- * @param c configuration
- */
- static void
- run (void *cls,
- char *const *args,
- const char *cfgfile,
- const struct GNUNET_CONFIGURATION_Handle *c)
- {
- struct stat st;
- char *dir;
- char *fn;
- int fd;
- (void) cls;
- (void) args;
- (void) cfgfile;
- cfg = c;
- dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
- GNUNET_assert (NULL != dir);
- GNUNET_asprintf (&fn, "%s%s%s", dir, DIR_SEPARATOR_STR, "gns-bcd.html");
- GNUNET_asprintf (&resfile, "%s%s%s", dir, DIR_SEPARATOR_STR, "gns-bcd.tex");
- GNUNET_free (dir);
- fd = open (fn, O_RDONLY);
- if (-1 == fd)
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", fn);
- GNUNET_free (fn);
- return;
- }
- if (0 != stat (fn, &st))
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", fn);
- GNUNET_free (fn);
- GNUNET_break (0 == close (fd));
- return;
- }
- GNUNET_free (fn);
- if (NULL ==
- (main_response = MHD_create_response_from_fd ((size_t) st.st_size, fd)))
- {
- GNUNET_break (0);
- GNUNET_break (0 == close (fd));
- return;
- }
- (void) MHD_add_response_header (main_response,
- MHD_HTTP_HEADER_CONTENT_TYPE,
- "text/html");
- invalid_gnskey_response =
- MHD_create_response_from_buffer (strlen (INVALID_GNSKEY),
- INVALID_GNSKEY,
- MHD_RESPMEM_PERSISTENT);
- (void) MHD_add_response_header (invalid_gnskey_response,
- MHD_HTTP_HEADER_CONTENT_TYPE,
- "text/html");
- not_found_response = MHD_create_response_from_buffer (strlen (NOT_FOUND),
- NOT_FOUND,
- MHD_RESPMEM_PERSISTENT);
- (void) MHD_add_response_header (not_found_response,
- MHD_HTTP_HEADER_CONTENT_TYPE,
- "text/html");
- if (GNUNET_OK != server_start ())
- return;
- GNUNET_SCHEDULER_add_shutdown (&server_stop, NULL);
- }
- /**
- * The main function for gnunet-gns.
- *
- * @param argc number of arguments from the command line
- * @param argv command line arguments
- * @return 0 ok, 1 on error
- */
- int
- main (int argc, char *const *argv)
- {
- struct GNUNET_GETOPT_CommandLineOption options[] = {
- GNUNET_GETOPT_option_uint16 ('p',
- "port",
- "PORT",
- gettext_noop (
- "Run HTTP serve on port PORT (default is 8888)"),
- &port),
- GNUNET_GETOPT_OPTION_END
- };
- int ret;
- if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
- return 2;
- GNUNET_log_setup ("gnunet-bcd", "WARNING", NULL);
- ret = (GNUNET_OK ==
- GNUNET_PROGRAM_run (argc,
- argv,
- "gnunet-bcd",
- _ ("GNUnet HTTP server to create business cards"),
- options,
- &run,
- NULL))
- ? 0
- : 1;
- GNUNET_free_nz ((void *) argv);
- return ret;
- }
- /* end of gnunet-bcd.c */
|