GNUnet  0.20.0
gnunet-rest-server.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2012-2015 GNUnet e.V.
4 
5  GNUnet is free software: you can redistribute it and/or modify it
6  under the terms of the GNU Affero General Public License as published
7  by the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  GNUnet is distributed in the hope that it will be useful, but
11  WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Affero General Public License for more details.
14 
15  You should have received a copy of the GNU Affero General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  SPDX-License-Identifier: AGPL3.0-or-later
19  */
26 #include "platform.h"
27 #include <microhttpd.h>
28 #include "gnunet_util_lib.h"
29 #include "gnunet_rest_plugin.h"
30 #include "gnunet_mhd_compat.h"
31 
35 #define GNUNET_REST_SERVICE_PORT 7776
36 
41 #define MAX_HTTP_URI_LENGTH 2048
42 
46 #define HTTP_PORT 80
47 
51 #define HTTPS_PORT 443
52 
56 #define MHD_CACHE_TIMEOUT \
57  GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
58 
59 #define GN_REST_STATE_INIT 0
60 #define GN_REST_STATE_PROCESSING 1
61 
66 
70 static in_addr_t address;
71 
75 static struct in6_addr address6;
76 
80 static unsigned long long port = GNUNET_REST_SERVICE_PORT;
81 
86 
91 
96 
101 
105 static struct MHD_Daemon *httpd;
106 
110 static struct MHD_Response *failure_response;
111 
115 static const struct GNUNET_CONFIGURATION_Handle *cfg;
116 
120 static int echo_origin;
121 
126 
130 static char *basic_auth_secret;
131 
135 char cuser[_POSIX_LOGIN_NAME_MAX];
136 
140 static char *allow_origins;
141 
145 static char *allow_headers;
146 
150 static char *allow_credentials;
151 
156 
161 
166 {
167  /* DLL */
169 
170  /* DLL */
172 
176  char *libname;
177 
182 };
183 
188 {
189  struct MHD_Connection *con;
190 
191  struct MHD_Response *response;
192 
194 
195  struct MHD_PostProcessor *pp;
196 
197  int status;
198 
199  int state;
200 };
201 
206 {
211 
216 
221 
226 
231 };
232 
237 
242 
243 /* ************************* Global helpers ********************* */
244 
245 
251 static void
252 do_httpd (void *cls);
253 
254 
258 static void
260 {
261  if (NULL != httpd_task)
262  {
264  httpd_task = NULL;
265  }
267 }
268 
269 
278 static void
279 plugin_callback (void *cls, struct MHD_Response *resp, int status)
280 {
281  struct MhdConnectionHandle *handle = cls;
282 
283  handle->status = status;
284  handle->response = resp;
285  MHD_resume_connection (handle->con);
286  run_mhd_now ();
287 }
288 
289 
290 static int
291 cleanup_url_map (void *cls, const struct GNUNET_HashCode *key, void *value)
292 {
293  GNUNET_free (value);
294  return GNUNET_YES;
295 }
296 
297 static void
299 {
300  if (NULL != handle->response)
301  MHD_destroy_response (handle->response);
302  if (NULL != handle->data_handle)
303  {
304  if (NULL != handle->data_handle->header_param_map)
305  {
307  ->header_param_map,
309  NULL);
311  handle->data_handle->header_param_map);
312  }
313  if (NULL != handle->data_handle->url_param_map)
314  {
315  GNUNET_CONTAINER_multihashmap_iterate (handle->data_handle->url_param_map,
317  NULL);
319  handle->data_handle->url_param_map);
320  }
321  GNUNET_free (handle->data_handle);
322  }
324 }
325 
326 static void
328 {
329  if (NULL != ar->con_handle)
330  {
332  }
333  if (GNUNET_YES == ar->socket_with_mhd)
334  {
336  }
337  else {
339  }
340  ar->sock = NULL;
343  ar);
344  GNUNET_free (ar);
345 }
346 
347 static int
348 header_iterator (void *cls,
349  enum MHD_ValueKind kind,
350  const char *key,
351  const char *value)
352 {
353  struct GNUNET_REST_RequestHandle *handle = cls;
354  struct GNUNET_HashCode hkey;
355  char *val;
356  char *lowerkey;
357 
358  lowerkey = GNUNET_strdup (key);
359  GNUNET_STRINGS_utf8_tolower (key, lowerkey);
360  GNUNET_CRYPTO_hash (lowerkey, strlen (lowerkey), &hkey);
361  GNUNET_asprintf (&val, "%s", value);
363  handle->header_param_map,
364  &hkey,
365  val,
367  {
369  "Could not load add header `%s'=%s\n",
370  lowerkey,
371  value);
372  }
373  GNUNET_free (lowerkey);
374  return MHD_YES;
375 }
376 
377 
378 static int
379 url_iterator (void *cls,
380  enum MHD_ValueKind kind,
381  const char *key,
382  const char *value)
383 {
384  struct GNUNET_REST_RequestHandle *handle = cls;
385  struct GNUNET_HashCode hkey;
386  char *val;
387 
388  GNUNET_CRYPTO_hash (key, strlen (key), &hkey);
389  GNUNET_asprintf (&val, "%s", value);
391  handle->url_param_map,
392  &hkey,
393  val,
395  {
397  "Could not load add url param `%s'=%s\n",
398  key,
399  value);
400  }
401  return MHD_YES;
402 }
403 
404 
405 static MHD_RESULT
406 post_data_iter (void *cls,
407  enum MHD_ValueKind kind,
408  const char *key,
409  const char *filename,
410  const char *content_type,
411  const char *transfer_encoding,
412  const char *data,
413  uint64_t off,
414  size_t size)
415 {
416  struct GNUNET_REST_RequestHandle *handle = cls;
417  struct GNUNET_HashCode hkey;
418  char *val;
419 
420  if (MHD_POSTDATA_KIND != kind)
421  return MHD_YES;
422 
423  GNUNET_CRYPTO_hash (key, strlen (key), &hkey);
424  val = GNUNET_CONTAINER_multihashmap_get (handle->url_param_map,
425  &hkey);
426  if (NULL == val)
427  {
428  val = GNUNET_malloc (65536);
430  handle->url_param_map,
431  &hkey,
432  val,
434  {
436  "Could not add url param '%s'\n",
437  key);
438  GNUNET_free (val);
439  }
440  }
441  memcpy (val + off, data, size);
442  return MHD_YES;
443 }
444 
445 
446 /* ********************************* MHD response generation ******************* */
447 
471 static MHD_RESULT
472 create_response (void *cls,
473  struct MHD_Connection *con,
474  const char *url,
475  const char *meth,
476  const char *ver,
477  const char *upload_data,
478  size_t *upload_data_size,
479  void **con_cls)
480 {
481  char *origin;
482  char *pw;
483  char *user;
484  struct AcceptedRequest *ar;
485  struct GNUNET_HashCode key;
486  struct MhdConnectionHandle *con_handle;
487  struct GNUNET_REST_RequestHandle *rest_conndata_handle;
488  struct PluginListEntry *ple;
489 
490  ar = *con_cls;
491  if (NULL == ar)
492  {
493  GNUNET_break (0);
494  return MHD_NO;
495  }
496 
497  if (NULL == ar->con_handle)
498  {
499  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New connection %s\n", url);
500  con_handle = GNUNET_new (struct MhdConnectionHandle);
501  con_handle->con = con;
502  con_handle->state = GN_REST_STATE_INIT;
503  ar->con_handle = con_handle;
504  return MHD_YES;
505  }
506  con_handle = ar->con_handle;
507  if (GN_REST_STATE_INIT == con_handle->state)
508  {
509  rest_conndata_handle = GNUNET_new (struct GNUNET_REST_RequestHandle);
510  rest_conndata_handle->method = meth;
511  rest_conndata_handle->url = url;
512  rest_conndata_handle->data = upload_data;
513  rest_conndata_handle->data_size = *upload_data_size;
514  rest_conndata_handle->url_param_map =
516  rest_conndata_handle->header_param_map =
518  con_handle->data_handle = rest_conndata_handle;
519  MHD_get_connection_values (con,
520  MHD_GET_ARGUMENT_KIND,
521  (MHD_KeyValueIterator) & url_iterator,
522  rest_conndata_handle);
523  MHD_get_connection_values (con,
524  MHD_HEADER_KIND,
525  (MHD_KeyValueIterator) & header_iterator,
526  rest_conndata_handle);
528  {
529  pw = NULL;
530  user = MHD_basic_auth_get_username_password (con, &pw);
531  if ((NULL == user) ||
532  (0 != strcmp (user, cuser)))
533  {
535  "Unknown user %s\n", user);
536  MHD_queue_basic_auth_fail_response (con, "gnunet", failure_response);
537  return MHD_YES;
538  }
539  if ((NULL == pw) ||
540  (0 != strcmp (pw, basic_auth_secret)))
541  {
543  "Password incorrect\n");
544  MHD_queue_basic_auth_fail_response (con, "gnunet", failure_response);
545  GNUNET_free (pw);
546  return MHD_YES;
547  }
548  GNUNET_free (pw);
549  }
550 
551  con_handle->pp = MHD_create_post_processor (con,
552  65536,
554  rest_conndata_handle);
555  if (*upload_data_size)
556  {
557  MHD_post_process (con_handle->pp, upload_data, *upload_data_size);
558  }
559  MHD_destroy_post_processor (con_handle->pp);
560 
561  con_handle->state = GN_REST_STATE_PROCESSING;
562  for (ple = plugins_head; NULL != ple; ple = ple->next)
563  {
564  if (GNUNET_YES == ple->plugin->process_request (rest_conndata_handle,
566  con_handle))
567  break; /* Request handled */
568  }
569  if (NULL == ple)
570  {
572  MHD_queue_response (con, MHD_HTTP_NOT_FOUND, failure_response);
573  }
574  *upload_data_size = 0;
575  run_mhd_now ();
576  return MHD_YES;
577  }
578  if (NULL == con_handle->response)
579  {
580  // Suspend connection until plugin is done
581  MHD_suspend_connection (con_handle->con);
582  return MHD_YES;
583  }
584  // MHD_resume_connection (con_handle->con);
586  "Queueing response from plugin with MHD\n");
587  // Handle Preflights for extensions
588  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Checking origin\n");
589  GNUNET_CRYPTO_hash ("origin", strlen ("origin"), &key);
592  &key);
593  if (NULL != origin)
594  {
595  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Origin: %s\n", origin);
596  // Only echo for browser plugins
597  if (GNUNET_YES == echo_origin)
598  {
599  if ((0 ==
600  strncmp ("moz-extension://", origin, strlen ("moz-extension://"))) ||
601  (0 == strncmp ("chrome-extension://",
602  origin,
603  strlen ("chrome-extension://"))))
604  {
605  GNUNET_assert (MHD_NO != MHD_add_response_header (con_handle->response,
606  MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
607  origin));
608  }
609  }
610  if (NULL != allow_origins)
611  {
612  char *tmp = GNUNET_strdup (allow_origins);
613  char *allow_origin = strtok (tmp, ",");
614  while (NULL != allow_origin)
615  {
616  if (0 == strncmp (allow_origin, origin, strlen (allow_origin)))
617  {
618  GNUNET_assert (MHD_NO != MHD_add_response_header (con_handle->response,
619  MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
620  allow_origin));
621  break;
622  }
623  allow_origin = strtok (NULL, ",");
624  }
625  GNUNET_free (tmp);
626  }
627  }
628  if (NULL != allow_credentials)
629  {
630  GNUNET_assert (MHD_NO != MHD_add_response_header (con_handle->response,
631  "Access-Control-Allow-Credentials",
633  }
634  if (NULL != allow_headers)
635  {
636  GNUNET_assert (MHD_NO != MHD_add_response_header (con_handle->response,
637  "Access-Control-Allow-Headers",
638  allow_headers));
639  }
640  run_mhd_now ();
641  {
642  MHD_RESULT ret = MHD_queue_response (con,
643  con_handle->status,
644  con_handle->response);
645  // cleanup_handle (con_handle);
646  return ret;
647  }
648 }
649 
650 
651 /* ******************** MHD HTTP setup and event loop ******************** */
652 
653 
657 static void
659 {
660  if (NULL != httpd)
661  {
662  MHD_stop_daemon (httpd);
663  httpd = NULL;
664  }
665  if (NULL != httpd_task)
666  {
668  httpd_task = NULL;
669  }
670  if (NULL != ltask4)
671  {
673  ltask4 = NULL;
674  }
675  if (NULL != ltask6)
676  {
678  ltask6 = NULL;
679  }
680 
681  if (NULL != lsock4)
682  {
684  lsock4 = NULL;
685  }
686  if (NULL != lsock6)
687  {
689  lsock6 = NULL;
690  }
691 }
692 
693 
701 static void
703 {
704  fd_set rs;
705  fd_set ws;
706  fd_set es;
707  struct GNUNET_NETWORK_FDSet *wrs;
708  struct GNUNET_NETWORK_FDSet *wws;
709  int max;
710  int haveto;
711  MHD_UNSIGNED_LONG_LONG timeout;
712  struct GNUNET_TIME_Relative tv;
713 
714  FD_ZERO (&rs);
715  FD_ZERO (&ws);
716  FD_ZERO (&es);
717  max = -1;
718  if (MHD_YES != MHD_get_fdset (httpd, &rs, &ws, &es, &max))
719  {
720  kill_httpd ();
721  return;
722  }
723  haveto = MHD_get_timeout (httpd, &timeout);
724  if (MHD_YES == haveto)
725  tv.rel_value_us = (uint64_t) timeout * 1000LL;
726  else
728  if (-1 != max)
729  {
732  GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
733  GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
734  }
735  else
736  {
737  wrs = NULL;
738  wws = NULL;
739  }
740  if (NULL != httpd_task)
741  {
743  httpd_task = NULL;
744  }
745  if ((MHD_YES == haveto) || (-1 != max))
746  {
748  tv,
749  wrs,
750  wws,
751  &do_httpd,
752  NULL);
753  }
754  if (NULL != wrs)
756  if (NULL != wws)
758 }
759 
773 static void *
774 mhd_log_callback (void *cls,
775  const char *url,
776  struct MHD_Connection *connection)
777 {
778  struct AcceptedRequest *ar;
779  const union MHD_ConnectionInfo *ci;
780 
781  ci = MHD_get_connection_info (connection,
782  MHD_CONNECTION_INFO_SOCKET_CONTEXT);
783  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing %s\n", url);
784  if (NULL == ci)
785  {
786  GNUNET_break (0);
787  return NULL;
788  }
789  ar = ci->socket_context;
790  return ar;
791 }
792 
793 
794 
804 static void
805 mhd_completed_cb (void *cls,
806  struct MHD_Connection *connection,
807  void **con_cls,
808  enum MHD_RequestTerminationCode toe)
809 {
810  struct AcceptedRequest *ar = *con_cls;
811  if (MHD_REQUEST_TERMINATED_COMPLETED_OK != toe)
813  "MHD encountered error handling request: %d\n",
814  toe);
815  if (NULL == ar)
816  return;
817  if (NULL != ar->con_handle)
818  {
820  ar->con_handle = NULL;
821  }
823  *con_cls = NULL;
824 }
825 
835 static void
836 mhd_connection_cb (void *cls,
837  struct MHD_Connection *connection,
838  void **con_cls,
839  enum MHD_ConnectionNotificationCode cnc)
840 {
841  struct AcceptedRequest *ar;
842  const union MHD_ConnectionInfo *ci;
843  int sock;
844 
845  switch (cnc)
846  {
847  case MHD_CONNECTION_NOTIFY_STARTED:
848  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection started...\n");
849  ci = MHD_get_connection_info (connection,
850  MHD_CONNECTION_INFO_CONNECTION_FD);
851  if (NULL == ci)
852  {
853  GNUNET_break (0);
854  return;
855  }
856  sock = ci->connect_fd;
857  for (ar = req_list_head; NULL != ar; ar = ar->next)
858  {
859  if (GNUNET_NETWORK_get_fd (ar->sock) == sock)
860  {
862  "Context set...\n");
863  *con_cls = ar;
864  break;
865  }
866  }
867  break;
868 
869  case MHD_CONNECTION_NOTIFY_CLOSED:
871  "Connection closed... cleaning up\n");
872  ar = *con_cls;
873  if (NULL == ar)
874  {
876  "Connection stale!\n");
877  return;
878  }
879  cleanup_ar (ar);
880  *con_cls = NULL;
881  break;
882 
883  default:
884  GNUNET_break (0);
885  }
886 }
887 
888 
889 
895 static void
896 do_httpd (void *cls)
897 {
898  httpd_task = NULL;
899  MHD_run (httpd);
900  schedule_httpd ();
901 }
902 
903 
909 static void
910 do_accept (void *cls)
911 {
912  struct GNUNET_NETWORK_Handle *lsock = cls;
913  struct AcceptedRequest *ar;
914  int fd;
915  const struct sockaddr *addr;
916  socklen_t len;
917 
918  GNUNET_assert (NULL != lsock);
919  if (lsock == lsock4)
920  {
922  lsock,
923  &do_accept,
924  lsock);
925  }
926  else if (lsock == lsock6)
927  {
929  lsock,
930  &do_accept,
931  lsock);
932  }
933  else
934  GNUNET_assert (0);
935  ar = GNUNET_new (struct AcceptedRequest);
937  ar->sock = GNUNET_NETWORK_socket_accept (lsock, NULL, NULL);
938  if (NULL == ar->sock)
939  {
940  GNUNET_free (ar);
942  return;
943  }
945  "Got an inbound connection, waiting for data\n");
946  fd = GNUNET_NETWORK_get_fd (ar->sock);
947  addr = GNUNET_NETWORK_get_addr (ar->sock);
951  ar);
952  if (MHD_YES != MHD_add_connection (httpd, fd, addr, len))
953  {
955  GNUNET_free (ar);
957  _ ("Failed to pass client to MHD\n"));
958  return;
959  }
960  schedule_httpd ();
961 }
962 
963 
969 static void
970 do_shutdown (void *cls)
971 {
972  struct PluginListEntry *ple;
973 
974  while (NULL != plugins_head)
975  {
976  ple = plugins_head;
978  plugins_tail,
979  ple);
980  GNUNET_PLUGIN_unload (ple->libname, ple->plugin);
981  GNUNET_free (ple->libname);
982  GNUNET_free (ple);
983  }
984  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down...\n");
985  kill_httpd ();
988 }
989 
990 
996 static struct GNUNET_NETWORK_Handle *
998 {
999  struct GNUNET_NETWORK_Handle *ls;
1000  struct sockaddr_in sa4;
1001  int eno;
1002 
1003  memset (&sa4, 0, sizeof(sa4));
1004  sa4.sin_family = AF_INET;
1005  sa4.sin_port = htons (port);
1006  sa4.sin_addr.s_addr = address;
1007 #if HAVE_SOCKADDR_IN_SIN_LEN
1008  sa4.sin_len = sizeof(sa4);
1009 #endif
1010  ls = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0);
1011  if (NULL == ls)
1012  return NULL;
1014  (const struct sockaddr *) &sa4,
1015  sizeof(sa4)))
1016  {
1017  eno = errno;
1019  errno = eno;
1020  return NULL;
1021  }
1022  return ls;
1023 }
1024 
1025 
1031 static struct GNUNET_NETWORK_Handle *
1033 {
1034  struct GNUNET_NETWORK_Handle *ls;
1035  struct sockaddr_in6 sa6;
1036  int eno;
1037 
1038  memset (&sa6, 0, sizeof(sa6));
1039  sa6.sin6_family = AF_INET6;
1040  sa6.sin6_port = htons (port);
1041  sa6.sin6_addr = address6;
1042 #if HAVE_SOCKADDR_IN_SIN_LEN
1043  sa6.sin6_len = sizeof(sa6);
1044 #endif
1045  ls = GNUNET_NETWORK_socket_create (AF_INET6, SOCK_STREAM, 0);
1046  if (NULL == ls)
1047  return NULL;
1049  (const struct sockaddr *) &sa6,
1050  sizeof(sa6)))
1051  {
1052  eno = errno;
1054  errno = eno;
1055  return NULL;
1056  }
1057  return ls;
1058 }
1059 
1060 
1068 static void
1069 load_plugin (void *cls, const char *libname, void *lib_ret)
1070 {
1071  struct GNUNET_REST_Plugin *plugin = lib_ret;
1072  struct PluginListEntry *ple;
1073 
1074  if (NULL == lib_ret)
1075  {
1077  "Could not load plugin `%s'\n",
1078  libname);
1079  return;
1080  }
1081  GNUNET_assert (1 < strlen (plugin->name));
1082  GNUNET_assert ('/' == *plugin->name);
1083  ple = GNUNET_new (struct PluginListEntry);
1084  ple->libname = GNUNET_strdup (libname);
1085  ple->plugin = plugin;
1087  plugins_tail,
1088  ple);
1089  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loaded plugin `%s'\n", libname);
1090 }
1091 
1092 
1101 static void
1102 run (void *cls,
1103  char *const *args,
1104  const char *cfgfile,
1105  const struct GNUNET_CONFIGURATION_Handle *c)
1106 {
1107  char *addr_str;
1108  char *basic_auth_file;
1109  uint64_t secret;
1110 
1111  cfg = c;
1112  plugins_head = NULL;
1113  plugins_tail = NULL;
1114  /* Get port to bind to */
1115  if (GNUNET_OK !=
1116  GNUNET_CONFIGURATION_get_value_number (cfg, "rest", "HTTP_PORT", &port))
1117  {
1118  // No address specified
1119  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Using default port...\n");
1121  }
1122 
1123  /* Get address to bind to */
1124  if (GNUNET_OK !=
1125  GNUNET_CONFIGURATION_get_value_string (cfg, "rest", "BIND_TO", &addr_str))
1126  {
1127  // No address specified
1128  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Don't know what to bind to...\n");
1130  return;
1131  }
1132  if (1 != inet_pton (AF_INET, addr_str, &address))
1133  {
1135  "Unable to parse address %s\n",
1136  addr_str);
1137  GNUNET_free (addr_str);
1139  return;
1140  }
1141  GNUNET_free (addr_str);
1142  /* Get address to bind to */
1144  "rest",
1145  "BIND_TO6",
1146  &addr_str))
1147  {
1148  // No address specified
1149  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Don't know what to bind6 to...\n");
1151  return;
1152  }
1153  if (1 != inet_pton (AF_INET6, addr_str, &address6))
1154  {
1156  "Unable to parse IPv6 address %s\n",
1157  addr_str);
1158  GNUNET_free (addr_str);
1160  return;
1161  }
1162  GNUNET_free (addr_str);
1163 
1165  "rest",
1166  "BASIC_AUTH_ENABLED");
1167  if (basic_auth_enabled)
1168  {
1170  "rest",
1171  "BASIC_AUTH_SECRET_FILE",
1172  &basic_auth_file))
1173  {
1175  "No basic auth secret file location set...\n");
1177  return;
1178  }
1179  if (GNUNET_YES != GNUNET_DISK_file_test (basic_auth_file))
1180  {
1182  "No basic auth secret found... generating\n");
1184  UINT64_MAX);
1186  sizeof(secret));
1187  if (GNUNET_OK !=
1188  GNUNET_DISK_fn_write (basic_auth_file,
1190  strlen (basic_auth_secret),
1194  "write",
1195  basic_auth_file);
1196  GNUNET_free (basic_auth_file);
1197  }
1198  else
1199  {
1200  char basic_auth_secret_tmp[16]; // Should be more than enough
1201  memset (basic_auth_secret_tmp, 0, 16);
1202  if (GNUNET_SYSERR == GNUNET_DISK_fn_read (basic_auth_file,
1203  basic_auth_secret_tmp,
1204  sizeof (basic_auth_secret_tmp) - 1))
1205  {
1207  "Unable to read basic auth secret file.\n");
1209  GNUNET_free (basic_auth_file);
1210  return;
1211  }
1212  GNUNET_free (basic_auth_file);
1213  if (0 != getlogin_r (cuser, _POSIX_LOGIN_NAME_MAX))
1214  {
1216  "Unable to get user.\n");
1218  return;
1219  }
1220  basic_auth_secret = GNUNET_strdup (basic_auth_secret_tmp);
1221  }
1222  }
1223 
1224  /* Get CORS data from cfg */
1225  echo_origin =
1227  "rest",
1228  "REST_ECHO_ORIGIN_WEBEXT");
1229  allow_origins = NULL;
1231  "rest",
1232  "REST_ALLOW_ORIGIN",
1233  &allow_origins))
1234  {
1236  "No CORS Access-Control-Allow-Origin header will be sent...\n");
1237  }
1238  if (GNUNET_OK !=
1240  "rest",
1241  "REST_ALLOW_CREDENTIALS",
1243  {
1244  // No origin specified
1246  "No CORS Credential Header will be sent...\n");
1247  }
1248 
1250  "rest",
1251  "REST_ALLOW_HEADERS",
1252  &allow_headers))
1253  {
1254  // No origin specified
1256  "No CORS Access-Control-Allow-Headers Header will be sent...\n");
1257  }
1258 
1259 /* Open listen socket proxy */
1260  lsock6 = bind_v6 ();
1261  if (NULL == lsock6)
1262  {
1264  }
1265  else
1266  {
1268  {
1271  lsock6 = NULL;
1272  }
1273  else
1274  {
1276  lsock6,
1277  &do_accept,
1278  lsock6);
1279  }
1280  }
1281  lsock4 = bind_v4 ();
1282  if (NULL == lsock4)
1283  {
1285  }
1286  else
1287  {
1289  {
1292  lsock4 = NULL;
1293  }
1294  else
1295  {
1297  lsock4,
1298  &do_accept,
1299  lsock4);
1300  }
1301  }
1302  if ((NULL == lsock4) && (NULL == lsock6))
1303  {
1305  return;
1306  }
1307  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service listens on port %llu\n",
1308  port);
1309  httpd = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_NO_LISTEN_SOCKET
1310  | MHD_ALLOW_SUSPEND_RESUME,
1311  0,
1312  NULL,
1313  NULL,
1314  &create_response,
1315  NULL,
1316  MHD_OPTION_CONNECTION_TIMEOUT,
1317  (unsigned int) 16,
1318  MHD_OPTION_NOTIFY_CONNECTION,
1320  NULL,
1321  MHD_OPTION_URI_LOG_CALLBACK,
1323  NULL,
1324  MHD_OPTION_NOTIFY_COMPLETED,
1326  NULL,
1327  MHD_OPTION_END);
1328  if (NULL == httpd)
1329  {
1331  return;
1332  }
1333 /* Load plugins */
1335  "libgnunet_plugin_rest",
1336  (void *) cfg,
1337  &load_plugin,
1338  NULL);
1340 }
1341 
1342 
1352 int
1353 main (int argc, char *const *argv)
1354 {
1357  static const char *err_page = "{}";
1358  int ret;
1359 
1360  if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
1361  return 2;
1362  GNUNET_log_setup ("gnunet-rest-server", "WARNING", NULL);
1363  failure_response = MHD_create_response_from_buffer (strlen (err_page),
1364  (void *) err_page,
1365  MHD_RESPMEM_PERSISTENT);
1366  ret = (GNUNET_OK == GNUNET_PROGRAM_run (argc,
1367  argv,
1368  "gnunet-rest-server",
1369  _ ("GNUnet REST server"),
1370  options,
1371  &run,
1372  NULL))
1373  ? 0
1374  : 1;
1375  MHD_destroy_response (failure_response);
1376  GNUNET_free_nz ((char *) argv);
1377  return ret;
1378 }
1379 
1380 
1381 /* end of gnunet-rest-server.c */
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_OPTION_END
Definition: 002.c:13
struct GNUNET_GETOPT_CommandLineOption options[]
Definition: 002.c:5
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
static struct GNUNET_TIME_Relative timeout
Desired timeout for the lookup (default is no timeout).
Definition: gnunet-abd.c:61
struct TestcasePlugin * plugin
The process handle to the testbed service.
struct GNUNET_HashCode key
The key used in the DHT.
static struct GNUNET_DNS_Handle * handle
Handle to transport service.
static char * filename
uint32_t data
The data value.
uint16_t status
See PRISM_STATUS_*-constants.
uint16_t len
length of data (which is always a uint32_t, but presumably this can be used to specify that fewer byt...
static char origin[GNUNET_DNSPARSER_MAX_NAME_LENGTH]
Current origin.
static char * value
Value of the record to add/remove.
static struct GNUNET_NETWORK_Handle * ls
Listen socket for STUN processing.
Definition: gnunet-nat.c:85
static char * allow_origins
Allowed Origins (CORS)
static void plugin_callback(void *cls, struct MHD_Response *resp, int status)
Plugin result callback.
#define GNUNET_REST_SERVICE_PORT
Default Socks5 listen port.
static struct AcceptedRequest * req_list_head
AcceptedRequest list head.
static void * mhd_log_callback(void *cls, const char *url, struct MHD_Connection *connection)
Function called when MHD first processes an incoming connection.
static int basic_auth_enabled
Do basic auth of user.
static struct GNUNET_NETWORK_Handle * bind_v6()
Create an IPv6 listen socket bound to our port.
static void run_mhd_now()
Run MHD now, we have extra data ready for the callback.
static struct MHD_Daemon * httpd
Daemon for HTTP.
char cuser[_POSIX_LOGIN_NAME_MAX]
User of the service.
static MHD_RESULT post_data_iter(void *cls, enum MHD_ValueKind kind, const char *key, const char *filename, const char *content_type, const char *transfer_encoding, const char *data, uint64_t off, size_t size)
static struct GNUNET_NETWORK_Handle * lsock6
The listen socket of the service for IPv6.
#define GN_REST_STATE_INIT
static const struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
static char * allow_headers
Allowed Headers (CORS)
static char * basic_auth_secret
Basic auth secret.
static MHD_RESULT create_response(void *cls, struct MHD_Connection *con, const char *url, const char *meth, const char *ver, const char *upload_data, size_t *upload_data_size, void **con_cls)
Main MHD callback for handling requests.
static struct GNUNET_NETWORK_Handle * lsock4
The listen socket of the service for IPv4.
static void kill_httpd()
Kill the MHD daemon.
static struct in6_addr address6
The IPv6 address to bind to.
static unsigned long long port
The port the service is running on (default 7776)
#define GN_REST_STATE_PROCESSING
static void do_shutdown(void *cls)
Task run on shutdown.
static void cleanup_ar(struct AcceptedRequest *ar)
static void mhd_completed_cb(void *cls, struct MHD_Connection *connection, void **con_cls, enum MHD_RequestTerminationCode toe)
Function called when MHD decides that we are done with a connection.
static int url_iterator(void *cls, enum MHD_ValueKind kind, const char *key, const char *value)
static int cleanup_url_map(void *cls, const struct GNUNET_HashCode *key, void *value)
static void run(void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c)
Main function that will be run.
static void do_httpd(void *cls)
Task run whenever HTTP server operations are pending.
static void do_accept(void *cls)
Accept new incoming connections.
static int header_iterator(void *cls, enum MHD_ValueKind kind, const char *key, const char *value)
static struct PluginListEntry * plugins_tail
Plugin list tail.
static struct GNUNET_SCHEDULER_Task * httpd_task
The task ID.
static int echo_origin
Echo request Origin in CORS.
static struct AcceptedRequest * req_list_tail
AcceptedRequest list tail.
static void load_plugin(void *cls, const char *libname, void *lib_ret)
Callback for plugin load.
int main(int argc, char *const *argv)
The main function for gnunet-rest-service.
static char * allow_credentials
Allowed Credentials (CORS)
static void schedule_httpd()
Schedule MHD.
static struct MHD_Response * failure_response
Response we return on failures.
static in_addr_t address
The address to bind to.
static void mhd_connection_cb(void *cls, struct MHD_Connection *connection, void **con_cls, enum MHD_ConnectionNotificationCode cnc)
Function called when MHD connection is opened or closed.
static struct PluginListEntry * plugins_head
Plugin list head.
static void cleanup_handle(struct MhdConnectionHandle *handle)
static struct GNUNET_SCHEDULER_Task * ltask6
The listen task ID for IPv6.
static struct GNUNET_SCHEDULER_Task * ltask4
The listen task ID for IPv4.
static struct GNUNET_NETWORK_Handle * bind_v4()
Create an IPv4 listen socket bound to our port.
#define MHD_RESULT
GNUnet service REST plugin header.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_filename(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be the name of a file or directory.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_number(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, unsigned long long *number)
Get a configuration value that should be a number.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_yesno(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option)
Get a configuration value that should be in a set of "YES" or "NO".
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_string(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be a string.
uint64_t GNUNET_CRYPTO_random_u64(enum GNUNET_CRYPTO_Quality mode, uint64_t max)
Generate a random unsigned 64-bit value.
@ GNUNET_CRYPTO_QUALITY_WEAK
No good quality of the operation is needed (i.e., random numbers can be pseudo-random).
enum GNUNET_GenericReturnValue GNUNET_DISK_file_test(const char *fil)
Check that fil corresponds to a filename (of a file that exists and that is not a directory).
Definition: disk.c:482
enum GNUNET_GenericReturnValue GNUNET_DISK_fn_write(const char *fn, const void *buf, size_t buf_size, enum GNUNET_DISK_AccessPermissions mode)
Write a buffer to a file atomically.
Definition: disk.c:725
ssize_t GNUNET_DISK_fn_read(const char *fn, void *result, size_t len)
Read the contents of a binary file into a buffer.
Definition: disk.c:664
@ GNUNET_DISK_PERM_USER_READ
Owner can read.
@ GNUNET_DISK_PERM_USER_WRITE
Owner can write.
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
void GNUNET_CRYPTO_hash(const void *block, size_t size, struct GNUNET_HashCode *ret)
Compute hash of a given block.
Definition: crypto_hash.c:41
enum GNUNET_GenericReturnValue GNUNET_CONTAINER_multihashmap_put(struct GNUNET_CONTAINER_MultiHashMap *map, const struct GNUNET_HashCode *key, void *value, enum GNUNET_CONTAINER_MultiHashMapOption opt)
Store a key-value pair in the map.
struct GNUNET_CONTAINER_MultiHashMap * GNUNET_CONTAINER_multihashmap_create(unsigned int len, int do_not_copy_keys)
Create a multi hash map.
void GNUNET_CONTAINER_multihashmap_destroy(struct GNUNET_CONTAINER_MultiHashMap *map)
Destroy a hash map.
enum GNUNET_GenericReturnValue GNUNET_CONTAINER_multihashmap_iterate(struct GNUNET_CONTAINER_MultiHashMap *map, GNUNET_CONTAINER_MultiHashMapIteratorCallback it, void *it_cls)
Iterate over all entries in the map.
void * GNUNET_CONTAINER_multihashmap_get(const struct GNUNET_CONTAINER_MultiHashMap *map, const struct GNUNET_HashCode *key)
Given a key find a value in the map matching the key.
@ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY
There must only be one value per key; storing a value should fail if a value under the same key alrea...
#define GNUNET_log(kind,...)
@ GNUNET_SCHEDULER_PRIORITY_DEFAULT
Run with the default priority (normal P2P operations).
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
int GNUNET_log_setup(const char *comp, const char *loglevel, const char *logfile)
Setup logging.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
#define GNUNET_log_strerror(level, cmd)
Log an error message at log-level 'level' that indicates a failure of the command 'cmd' with the mess...
#define GNUNET_log_strerror_file(level, cmd, filename)
Log an error message at log-level 'level' that indicates a failure of the command 'cmd' with the mess...
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
@ GNUNET_ERROR_TYPE_INFO
int int GNUNET_asprintf(char **buf, const char *format,...) __attribute__((format(printf
Like asprintf, just portable.
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_free(ptr)
Wrapper around free.
#define GNUNET_free_nz(ptr)
Wrapper around free.
struct sockaddr * GNUNET_NETWORK_get_addr(const struct GNUNET_NETWORK_Handle *desc)
Return the sockaddr for this network handle.
Definition: network.c:1014
struct GNUNET_NETWORK_FDSet * GNUNET_NETWORK_fdset_create(void)
Creates an fd set.
Definition: network.c:1171
enum GNUNET_GenericReturnValue GNUNET_NETWORK_socket_close(struct GNUNET_NETWORK_Handle *desc)
Close a socket.
Definition: network.c:509
void GNUNET_NETWORK_fdset_destroy(struct GNUNET_NETWORK_FDSet *fds)
Releases the associated memory of an fd set.
Definition: network.c:1187
socklen_t GNUNET_NETWORK_get_addrlen(const struct GNUNET_NETWORK_Handle *desc)
Return sockaddr length for this network handle.
Definition: network.c:1027
int GNUNET_NETWORK_get_fd(const struct GNUNET_NETWORK_Handle *desc)
Return file descriptor for this network handle.
Definition: network.c:1001
void GNUNET_NETWORK_fdset_copy_native(struct GNUNET_NETWORK_FDSet *to, const fd_set *from, int nfds)
Copy a native fd set into the GNUnet representation.
Definition: network.c:1041
struct GNUNET_NETWORK_Handle * GNUNET_NETWORK_socket_accept(const struct GNUNET_NETWORK_Handle *desc, struct sockaddr *address, socklen_t *address_len)
Accept a new connection on a socket.
Definition: network.c:393
struct GNUNET_NETWORK_Handle * GNUNET_NETWORK_socket_create(int domain, int type, int protocol)
Create a new socket.
Definition: network.c:833
void GNUNET_NETWORK_socket_free_memory_only_(struct GNUNET_NETWORK_Handle *desc)
Only free memory of a socket, keep the file descriptor untouched.
Definition: network.c:566
enum GNUNET_GenericReturnValue GNUNET_NETWORK_socket_bind(struct GNUNET_NETWORK_Handle *desc, const struct sockaddr *address, socklen_t address_len)
Bind a socket to a particular address.
Definition: network.c:440
enum GNUNET_GenericReturnValue GNUNET_NETWORK_socket_listen(const struct GNUNET_NETWORK_Handle *desc, int backlog)
Listen on a socket.
Definition: network.c:652
const struct GNUNET_OS_ProjectData * GNUNET_OS_project_data_default(void)
Return default project data used by 'libgnunetutil' for GNUnet.
void * GNUNET_PLUGIN_unload(const char *library_name, void *arg)
Unload plugin (runs the "done" callback and returns whatever "done" returned).
Definition: plugin.c:242
void GNUNET_PLUGIN_load_all_in_context(const struct GNUNET_OS_ProjectData *ctx, const char *basename, void *arg, GNUNET_PLUGIN_LoaderCallback cb, void *cb_cls)
Load all compatible plugins with the given base name while inside the given context (i....
Definition: plugin.c:386
enum GNUNET_GenericReturnValue GNUNET_PROGRAM_run(int argc, char *const *argv, const char *binaryName, const char *binaryHelp, const struct GNUNET_GETOPT_CommandLineOption *options, GNUNET_PROGRAM_Main task, void *task_cls)
Run a standard GNUnet command startup sequence (initialize loggers and configuration,...
Definition: program.c:400
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition: scheduler.c:562
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_now(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run as soon as possible.
Definition: scheduler.c:1299
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_select(enum GNUNET_SCHEDULER_Priority prio, struct GNUNET_TIME_Relative delay, const struct GNUNET_NETWORK_FDSet *rs, const struct GNUNET_NETWORK_FDSet *ws, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when any of the specified file descriptor set...
Definition: scheduler.c:1830
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_read_net(struct GNUNET_TIME_Relative delay, struct GNUNET_NETWORK_Handle *rfd, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when the specified file descriptor is ready f...
Definition: scheduler.c:1506
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_shutdown(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run on shutdown, that is when a CTRL-C signal is received,...
Definition: scheduler.c:1334
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:975
char * GNUNET_STRINGS_data_to_string_alloc(const void *buf, size_t size)
Return the base32crockford encoding of the given buffer.
Definition: strings.c:763
enum GNUNET_GenericReturnValue GNUNET_STRINGS_get_utf8_args(int argc, char *const *argv, int *u8argc, char *const **u8argv)
Returns utf-8 encoded arguments.
Definition: strings.c:1222
enum GNUNET_GenericReturnValue GNUNET_STRINGS_utf8_tolower(const char *input, char *output)
Convert the utf-8 input string to lower case.
Definition: strings.c:449
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
@ MHD_HTTP_NOT_FOUND
Not Found [RFC7231, Section 6.5.4].
#define max(x, y)
static unsigned int size
Size of the "table".
Definition: peer.c:68
#define _(String)
GNU gettext support macro.
Definition: platform.h:178
Accepted requests.
struct AcceptedRequest * prev
DLL.
struct MhdConnectionHandle * con_handle
Connection.
struct GNUNET_NETWORK_Handle * sock
Socket.
struct AcceptedRequest * next
DLL.
Definition of a command line option.
A 512-bit hashcode.
collection of IO descriptors
handle to a socket
Definition: network.c:54
struct returned by the initialization function of the plugin
enum GNUNET_GenericReturnValue(* process_request)(struct GNUNET_REST_RequestHandle *handle, GNUNET_REST_ResultProcessor proc, void *proc_cls)
Function to process a REST call.
struct GNUNET_CONTAINER_MultiHashMap * header_param_map
Map of headers.
const char * data
The POST data.
const char * url
The url as string.
const char * method
The HTTP method as MHD value (see microhttpd.h)
struct GNUNET_CONTAINER_MultiHashMap * url_param_map
Map of url parameters.
size_t data_size
The POST data size.
Entry in list of pending tasks.
Definition: scheduler.c:136
Time for relative time used by GNUnet, in microseconds.
uint64_t rel_value_us
The actual value.
MHD Connection handle.
struct GNUNET_REST_RequestHandle * data_handle
struct MHD_PostProcessor * pp
struct MHD_Response * response
struct MHD_Connection * con
A plugin list entry.
struct PluginListEntry * prev
struct GNUNET_REST_Plugin * plugin
The plugin.
char * libname
libname (to cleanup)
struct PluginListEntry * next