GNUnet 0.26.2
 
Loading...
Searching...
No Matches
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
32#include "config_plugin.h"
33#include "copying_plugin.h"
34#include "identity_plugin.h"
35#include "namestore_plugin.h"
36#include "gns_plugin.h"
37#if HAVE_JOSE
38#include "openid_plugin.h"
39#endif
40#include "reclaim_plugin.h"
41
45#define GNUNET_REST_SERVICE_PORT 7776
46
51#define MAX_HTTP_URI_LENGTH 2048
52
56#define HTTP_PORT 80
57
61#define HTTPS_PORT 443
62
66#define MHD_CACHE_TIMEOUT \
67 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
68
69#define GN_REST_STATE_INIT 0
70#define GN_REST_STATE_PROCESSING 1
71
76
80static in_addr_t address;
81
85static struct in6_addr address6;
86
90static unsigned long long port = GNUNET_REST_SERVICE_PORT;
91
96
101
106
111
115static struct MHD_Daemon *httpd;
116
120static struct MHD_Response *failure_response;
121
125static const struct GNUNET_CONFIGURATION_Handle *cfg;
126
130static int echo_origin;
131
136
140static char *basic_auth_secret;
141
145char cuser[_POSIX_LOGIN_NAME_MAX];
146
150static char *allow_origins;
151
155static char *allow_headers;
156
160static char *allow_credentials;
161
166
171
176{
177 /* DLL */
179
180 /* DLL */
182
186 char *libname;
187
191 void *plugin;
192
197};
198
203{
204 struct MHD_Connection *con;
205
206 struct MHD_Response *response;
207
209
210 struct MHD_PostProcessor *pp;
211
213
214 int state;
215};
216
247
252
257
258
268#if HAVE_JOSE
269struct GNUNET_REST_Plugin *openid_plugin;
270#endif
272
273/* ************************* Global helpers ********************* */
274
275
281static void
282do_httpd (void *cls);
283
284
288static void
290{
291 if (NULL != httpd_task)
292 {
294 httpd_task = NULL;
295 }
297}
298
299
308static void
309plugin_callback (void *cls, struct MHD_Response *resp, int status)
310{
311 struct MhdConnectionHandle *handle = cls;
312
313 handle->status = status;
314 handle->response = resp;
315 MHD_resume_connection (handle->con);
316 run_mhd_now ();
317}
318
319
320static int
321cleanup_url_map (void *cls, const struct GNUNET_HashCode *key, void *value)
322{
324 return GNUNET_YES;
325}
326
327
328static void
330{
331 if (NULL != handle->response)
332 MHD_destroy_response (handle->response);
333 if (NULL != handle->data_handle)
334 {
335 if (NULL != handle->data_handle->header_param_map)
336 {
338 ->header_param_map,
340 NULL);
342 handle->data_handle->header_param_map);
343 }
344 if (NULL != handle->data_handle->url_param_map)
345 {
346 GNUNET_CONTAINER_multihashmap_iterate (handle->data_handle->url_param_map,
348 NULL);
350 handle->data_handle->url_param_map);
351 }
352 GNUNET_free (handle->data_handle);
353 }
355}
356
357
358static void
360{
361 if (NULL != ar->con_handle)
362 {
364 }
365 if (GNUNET_YES == ar->socket_with_mhd)
366 {
368 }
369 else
370 {
372 }
373 ar->sock = NULL;
376 ar);
377 GNUNET_free (ar);
378}
379
380
381static int
383 enum MHD_ValueKind kind,
384 const char *key,
385 const char *value)
386{
387 struct GNUNET_REST_RequestHandle *handle = cls;
388 struct GNUNET_HashCode hkey;
389 char *val;
390 char *lowerkey;
391
392 lowerkey = GNUNET_STRINGS_utf8_tolower (key);
393 GNUNET_CRYPTO_hash (lowerkey,
394 strlen (lowerkey),
395 &hkey);
396 GNUNET_asprintf (&val,
397 "%s",
398 value);
399 if (GNUNET_OK !=
401 handle->header_param_map,
402 &hkey,
403 val,
405 {
407 "Could not load add header `%s'=%s\n",
408 lowerkey,
409 value);
410 }
411 GNUNET_free (lowerkey);
412 return MHD_YES;
413}
414
415
416static int
417url_iterator (void *cls,
418 enum MHD_ValueKind kind,
419 const char *key,
420 const char *value)
421{
422 struct GNUNET_REST_RequestHandle *handle = cls;
423 struct GNUNET_HashCode hkey;
424 char *val;
425
426 GNUNET_CRYPTO_hash (key, strlen (key), &hkey);
427 GNUNET_asprintf (&val, "%s", value);
429 handle->url_param_map,
430 &hkey,
431 val,
433 {
435 "Could not load add url param `%s'=%s\n",
436 key,
437 value);
438 }
439 return MHD_YES;
440}
441
442
443static MHD_RESULT
444post_data_iter (void *cls,
445 enum MHD_ValueKind kind,
446 const char *key,
447 const char *filename,
448 const char *content_type,
449 const char *transfer_encoding,
450 const char *data,
451 uint64_t off,
452 size_t size)
453{
454 struct GNUNET_REST_RequestHandle *handle = cls;
455 struct GNUNET_HashCode hkey;
456 char *val;
457
458 if (MHD_POSTDATA_KIND != kind)
459 return MHD_YES;
460
461 GNUNET_CRYPTO_hash (key, strlen (key), &hkey);
462 val = GNUNET_CONTAINER_multihashmap_get (handle->url_param_map,
463 &hkey);
464 if (NULL == val)
465 {
466 val = GNUNET_malloc (65536);
468 handle->url_param_map,
469 &hkey,
470 val,
472 {
474 "Could not add url param '%s'\n",
475 key);
476 GNUNET_free (val);
477 }
478 }
479 memcpy (val + off, data, size);
480 return MHD_YES;
481}
482
483
484/* ********************************* MHD response generation ******************* */
485
509static MHD_RESULT
511 struct MHD_Connection *con,
512 const char *url,
513 const char *meth,
514 const char *ver,
515 const char *upload_data,
516 size_t *upload_data_size,
517 void **con_cls)
518{
519 char *origin;
520 char *pw;
521 char *user;
522 struct AcceptedRequest *ar;
523 struct GNUNET_HashCode key;
524 struct MhdConnectionHandle *con_handle;
525 struct GNUNET_REST_RequestHandle *rest_conndata_handle;
526 struct PluginListEntry *ple;
527
528 ar = *con_cls;
529 if (NULL == ar)
530 {
531 GNUNET_break (0);
532 return MHD_NO;
533 }
534
535 if (NULL == ar->con_handle)
536 {
537 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New connection %s\n", url);
538 con_handle = GNUNET_new (struct MhdConnectionHandle);
539 con_handle->con = con;
540 con_handle->state = GN_REST_STATE_INIT;
541 ar->con_handle = con_handle;
542 return MHD_YES;
543 }
544 con_handle = ar->con_handle;
545 if (GN_REST_STATE_INIT == con_handle->state)
546 {
547 rest_conndata_handle = GNUNET_new (struct GNUNET_REST_RequestHandle);
548 rest_conndata_handle->method = meth;
549 rest_conndata_handle->url = url;
550 rest_conndata_handle->data = upload_data;
551 rest_conndata_handle->data_size = *upload_data_size;
552 rest_conndata_handle->url_param_map =
554 rest_conndata_handle->header_param_map =
556 con_handle->data_handle = rest_conndata_handle;
557 MHD_get_connection_values (con,
558 MHD_GET_ARGUMENT_KIND,
559 (MHD_KeyValueIterator) & url_iterator,
560 rest_conndata_handle);
561 MHD_get_connection_values (con,
562 MHD_HEADER_KIND,
563 (MHD_KeyValueIterator) & header_iterator,
564 rest_conndata_handle);
566 {
567 pw = NULL;
568 user = MHD_basic_auth_get_username_password (con, &pw);
569 if ((NULL == user) ||
570 (0 != strcmp (user, cuser)))
571 {
573 "Unknown user %s\n", user);
574 MHD_queue_basic_auth_fail_response (con, "gnunet", failure_response);
575 return MHD_YES;
576 }
577 if ((NULL == pw) ||
578 (0 != strcmp (pw, basic_auth_secret)))
579 {
581 "Password incorrect\n");
582 MHD_queue_basic_auth_fail_response (con, "gnunet", failure_response);
583 GNUNET_free (pw);
584 return MHD_YES;
585 }
586 GNUNET_free (pw);
587 }
588
589 con_handle->pp = MHD_create_post_processor (con,
590 65536,
592 rest_conndata_handle);
593 if (*upload_data_size)
594 {
595 MHD_post_process (con_handle->pp, upload_data, *upload_data_size);
596 }
597 MHD_destroy_post_processor (con_handle->pp);
598
599 con_handle->state = GN_REST_STATE_PROCESSING;
600 for (ple = plugins_head; NULL != ple; ple = ple->next)
601 {
602 if (GNUNET_YES == ple->process_request (ple->plugin,
603 rest_conndata_handle,
605 con_handle))
606 break; /* Request handled */
607 }
608 if (NULL == ple)
609 {
611 MHD_queue_response (con, MHD_HTTP_NOT_FOUND, failure_response);
612 }
613 *upload_data_size = 0;
614 run_mhd_now ();
615 return MHD_YES;
616 }
617 if (NULL == con_handle->response)
618 {
619 // Suspend connection until plugin is done
620 MHD_suspend_connection (con_handle->con);
621 return MHD_YES;
622 }
623 // MHD_resume_connection (con_handle->con);
625 "Queueing response from plugin with MHD\n");
626 // Handle Preflights for extensions
627 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Checking origin\n");
628 GNUNET_CRYPTO_hash ("origin", strlen ("origin"), &key);
631 &key);
632 if (NULL != origin)
633 {
634 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Origin: %s\n", origin);
635 // Only echo for browser plugins
636 if (GNUNET_YES == echo_origin)
637 {
638 if ((0 ==
639 strncmp ("moz-extension://", origin, strlen ("moz-extension://"))) ||
640 (0 == strncmp ("chrome-extension://",
641 origin,
642 strlen ("chrome-extension://"))))
643 {
644 GNUNET_assert (MHD_NO != MHD_add_response_header (con_handle->response,
645 MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
646 origin));
647 }
648 }
649 if (NULL != allow_origins)
650 {
651 char *tmp = GNUNET_strdup (allow_origins);
652 char *allow_origin = strtok (tmp, ",");
653 while (NULL != allow_origin)
654 {
655 if (0 == strncmp (allow_origin, origin, strlen (allow_origin)))
656 {
657 GNUNET_assert (MHD_NO != MHD_add_response_header (
658 con_handle->response,
659 MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
660 allow_origin));
661 break;
662 }
663 allow_origin = strtok (NULL, ",");
664 }
665 GNUNET_free (tmp);
666 }
667 }
668 if (NULL != allow_credentials)
669 {
670 GNUNET_assert (MHD_NO != MHD_add_response_header (con_handle->response,
671 "Access-Control-Allow-Credentials",
673 }
674 if (NULL != allow_headers)
675 {
676 GNUNET_assert (MHD_NO != MHD_add_response_header (con_handle->response,
677 "Access-Control-Allow-Headers",
679 }
680 run_mhd_now ();
681 {
682 MHD_RESULT ret = MHD_queue_response (con,
683 con_handle->status,
684 con_handle->response);
685 // cleanup_handle (con_handle);
686 return ret;
687 }
688}
689
690
691/* ******************** MHD HTTP setup and event loop ******************** */
692
693
697static void
699{
700 if (NULL != httpd)
701 {
702 MHD_stop_daemon (httpd);
703 httpd = NULL;
704 }
705 if (NULL != httpd_task)
706 {
708 httpd_task = NULL;
709 }
710 if (NULL != ltask4)
711 {
713 ltask4 = NULL;
714 }
715 if (NULL != ltask6)
716 {
718 ltask6 = NULL;
719 }
720
721 if (NULL != lsock4)
722 {
724 lsock4 = NULL;
725 }
726 if (NULL != lsock6)
727 {
729 lsock6 = NULL;
730 }
731}
732
733
741static void
743{
744 fd_set rs;
745 fd_set ws;
746 fd_set es;
747 struct GNUNET_NETWORK_FDSet *wrs;
748 struct GNUNET_NETWORK_FDSet *wws;
749 int max;
750 int haveto;
751 MHD_UNSIGNED_LONG_LONG timeout;
752 struct GNUNET_TIME_Relative tv;
753
754 FD_ZERO (&rs);
755 FD_ZERO (&ws);
756 FD_ZERO (&es);
757 max = -1;
758 if (MHD_YES != MHD_get_fdset (httpd, &rs, &ws, &es, &max))
759 {
760 kill_httpd ();
761 return;
762 }
763 haveto = MHD_get_timeout (httpd, &timeout);
764 if (MHD_YES == haveto)
765 tv.rel_value_us = (uint64_t) timeout * 1000LL;
766 else
768 if (-1 != max)
769 {
774 }
775 else
776 {
777 wrs = NULL;
778 wws = NULL;
779 }
780 if (NULL != httpd_task)
781 {
783 httpd_task = NULL;
784 }
785 if ((MHD_YES == haveto) || (-1 != max))
786 {
788 tv,
789 wrs,
790 wws,
791 &do_httpd,
792 NULL);
793 }
794 if (NULL != wrs)
796 if (NULL != wws)
798}
799
800
814static void *
816 const char *url,
817 struct MHD_Connection *connection)
818{
819 struct AcceptedRequest *ar;
820 const union MHD_ConnectionInfo *ci;
821
822 ci = MHD_get_connection_info (connection,
823 MHD_CONNECTION_INFO_SOCKET_CONTEXT);
824 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing %s\n", url);
825 if (NULL == ci)
826 {
827 GNUNET_break (0);
828 return NULL;
829 }
830 ar = ci->socket_context;
831 return ar;
832}
833
834
844static void
846 struct MHD_Connection *connection,
847 void **con_cls,
848 enum MHD_RequestTerminationCode toe)
849{
850 struct AcceptedRequest *ar = *con_cls;
851 if (MHD_REQUEST_TERMINATED_COMPLETED_OK != toe)
853 "MHD encountered error handling request: %d\n",
854 toe);
855 if (NULL == ar)
856 return;
857 if (NULL != ar->con_handle)
858 {
860 ar->con_handle = NULL;
861 }
863 *con_cls = NULL;
864}
865
866
876static void
878 struct MHD_Connection *connection,
879 void **con_cls,
880 enum MHD_ConnectionNotificationCode cnc)
881{
882 struct AcceptedRequest *ar;
883 const union MHD_ConnectionInfo *ci;
884 int sock;
885
886 switch (cnc)
887 {
888 case MHD_CONNECTION_NOTIFY_STARTED:
889 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection started...\n");
890 ci = MHD_get_connection_info (connection,
891 MHD_CONNECTION_INFO_CONNECTION_FD);
892 if (NULL == ci)
893 {
894 GNUNET_break (0);
895 return;
896 }
897 sock = ci->connect_fd;
898 for (ar = req_list_head; NULL != ar; ar = ar->next)
899 {
900 if (GNUNET_NETWORK_get_fd (ar->sock) == sock)
901 {
903 "Context set...\n");
904 *con_cls = ar;
905 break;
906 }
907 }
908 break;
909
910 case MHD_CONNECTION_NOTIFY_CLOSED:
912 "Connection closed... cleaning up\n");
913 ar = *con_cls;
914 if (NULL == ar)
915 {
917 "Connection stale!\n");
918 return;
919 }
920 cleanup_ar (ar);
921 *con_cls = NULL;
922 break;
923
924 default:
925 GNUNET_break (0);
926 }
927}
928
929
935static void
936do_httpd (void *cls)
937{
938 httpd_task = NULL;
939 MHD_run (httpd);
941}
942
943
949static void
950do_accept (void *cls)
951{
952 struct GNUNET_NETWORK_Handle *lsock = cls;
953 struct AcceptedRequest *ar;
954 int fd;
955 const struct sockaddr *addr;
956 socklen_t len;
957
958 GNUNET_assert (NULL != lsock);
959 if (lsock == lsock4)
960 {
962 lsock,
963 &do_accept,
964 lsock);
965 }
966 else if (lsock == lsock6)
967 {
969 lsock,
970 &do_accept,
971 lsock);
972 }
973 else
974 GNUNET_assert (0);
975 ar = GNUNET_new (struct AcceptedRequest);
977 ar->sock = GNUNET_NETWORK_socket_accept (lsock, NULL, NULL);
978 if (NULL == ar->sock)
979 {
980 GNUNET_free (ar);
982 return;
983 }
985 "Got an inbound connection, waiting for data\n");
986 fd = GNUNET_NETWORK_get_fd (ar->sock);
987 addr = GNUNET_NETWORK_get_addr (ar->sock);
991 ar);
992 if (MHD_YES != MHD_add_connection (httpd, fd, addr, len))
993 {
995 GNUNET_free (ar);
997 _ ("Failed to pass client to MHD\n"));
998 return;
999 }
1000 schedule_httpd ();
1001}
1002
1003
1009static void
1010do_shutdown (void *cls)
1011{
1012 struct PluginListEntry *ple;
1013
1014 while (NULL != plugins_head)
1015 {
1016 ple = plugins_head;
1019 ple);
1020 GNUNET_free (ple->libname);
1021 GNUNET_free (ple);
1022 }
1028#if HAVE_JOSE
1029 REST_openid_done (openid_plugin);
1030#endif
1032 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down...\n");
1033 kill_httpd ();
1036 MHD_destroy_response (failure_response);
1037}
1038
1039
1045static struct GNUNET_NETWORK_Handle *
1047{
1048 struct GNUNET_NETWORK_Handle *ls;
1049 struct sockaddr_in sa4;
1050 int eno;
1051
1052 memset (&sa4, 0, sizeof(sa4));
1053 sa4.sin_family = AF_INET;
1054 sa4.sin_port = htons (port);
1055 sa4.sin_addr.s_addr = address;
1056#if HAVE_SOCKADDR_IN_SIN_LEN
1057 sa4.sin_len = sizeof(sa4);
1058#endif
1059 ls = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0);
1060 if (NULL == ls)
1061 return NULL;
1063 (const struct sockaddr *) &sa4,
1064 sizeof(sa4)))
1065 {
1066 eno = errno;
1068 errno = eno;
1069 return NULL;
1070 }
1071 return ls;
1072}
1073
1074
1080static struct GNUNET_NETWORK_Handle *
1082{
1083 struct GNUNET_NETWORK_Handle *ls;
1084 struct sockaddr_in6 sa6;
1085 int eno;
1086
1087 memset (&sa6, 0, sizeof(sa6));
1088 sa6.sin6_family = AF_INET6;
1089 sa6.sin6_port = htons (port);
1090 sa6.sin6_addr = address6;
1091#if HAVE_SOCKADDR_IN_SIN_LEN
1092 sa6.sin6_len = sizeof(sa6);
1093#endif
1094 ls = GNUNET_NETWORK_socket_create (AF_INET6, SOCK_STREAM, 0);
1095 if (NULL == ls)
1096 return NULL;
1098 (const struct sockaddr *) &sa6,
1099 sizeof(sa6)))
1100 {
1101 eno = errno;
1103 errno = eno;
1104 return NULL;
1105 }
1106 return ls;
1107}
1108
1109
1117static enum GNUNET_GenericReturnValue
1118setup_plugin (const char *name,
1120 void *plugin_cls)
1121{
1122 struct PluginListEntry *ple;
1123
1124 if (NULL == plugin_cls)
1125 {
1127 "Could not load plugin\n");
1128 return GNUNET_SYSERR;
1129 }
1130 GNUNET_assert (1 < strlen (name));
1131 GNUNET_assert ('/' == *name);
1132 ple = GNUNET_new (struct PluginListEntry);
1133 ple->libname = GNUNET_strdup (name);
1134 ple->plugin = plugin_cls;
1135 ple->process_request = proc;
1138 ple);
1139 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loaded plugin `%s'\n", name);
1140 return GNUNET_OK;
1141}
1142
1143
1152static void
1153run (void *cls,
1154 char *const *args,
1155 const char *cfgfile,
1156 const struct GNUNET_CONFIGURATION_Handle *c)
1157{
1158 static const char *err_page = "{}";
1159 char *addr_str;
1160 char *basic_auth_file;
1161 uint64_t secret;
1162
1163 cfg = c;
1164 plugins_head = NULL;
1165 plugins_tail = NULL;
1166 failure_response = MHD_create_response_from_buffer (strlen (err_page),
1167 (void *) err_page,
1168 MHD_RESPMEM_PERSISTENT);
1169 /* Get port to bind to */
1170 if (GNUNET_OK !=
1171 GNUNET_CONFIGURATION_get_value_number (cfg, "rest", "HTTP_PORT", &port))
1172 {
1173 // No address specified
1174 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Using default port...\n");
1176 }
1177
1178 /* Get address to bind to */
1179 if (GNUNET_OK !=
1180 GNUNET_CONFIGURATION_get_value_string (cfg, "rest", "BIND_TO", &addr_str))
1181 {
1182 // No address specified
1183 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Don't know what to bind to...\n");
1185 return;
1186 }
1187 if (1 != inet_pton (AF_INET, addr_str, &address))
1188 {
1190 "Unable to parse address %s\n",
1191 addr_str);
1192 GNUNET_free (addr_str);
1194 return;
1195 }
1196 GNUNET_free (addr_str);
1197 /* Get address to bind to */
1199 "rest",
1200 "BIND_TO6",
1201 &addr_str))
1202 {
1203 // No address specified
1204 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Don't know what to bind6 to...\n");
1206 return;
1207 }
1208 if (1 != inet_pton (AF_INET6, addr_str, &address6))
1209 {
1211 "Unable to parse IPv6 address %s\n",
1212 addr_str);
1213 GNUNET_free (addr_str);
1215 return;
1216 }
1217 GNUNET_free (addr_str);
1218
1220 "rest",
1221 "BASIC_AUTH_ENABLED");
1223 {
1225 "rest",
1226 "BASIC_AUTH_SECRET_FILE",
1227 &basic_auth_file))
1228 {
1230 "No basic auth secret file location set...\n");
1232 return;
1233 }
1234 if (GNUNET_YES != GNUNET_DISK_file_test (basic_auth_file))
1235 {
1237 "No basic auth secret found... generating\n");
1239 UINT64_MAX);
1241 sizeof(secret));
1242 if (GNUNET_OK !=
1243 GNUNET_DISK_fn_write (basic_auth_file,
1245 strlen (basic_auth_secret),
1249 "write",
1250 basic_auth_file);
1251 GNUNET_free (basic_auth_file);
1252 }
1253 else
1254 {
1255 char basic_auth_secret_tmp[16]; // Should be more than enough
1256 memset (basic_auth_secret_tmp, 0, 16);
1257 if (GNUNET_SYSERR == GNUNET_DISK_fn_read (basic_auth_file,
1258 basic_auth_secret_tmp,
1259 sizeof (basic_auth_secret_tmp)
1260 - 1))
1261 {
1263 "Unable to read basic auth secret file.\n");
1265 GNUNET_free (basic_auth_file);
1266 return;
1267 }
1268 GNUNET_free (basic_auth_file);
1269 if (0 != getlogin_r (cuser, _POSIX_LOGIN_NAME_MAX))
1270 {
1272 "Unable to get user.\n");
1274 return;
1275 }
1276 basic_auth_secret = GNUNET_strdup (basic_auth_secret_tmp);
1277 }
1278 }
1279
1280 /* Get CORS data from cfg */
1281 echo_origin =
1283 "rest",
1284 "REST_ECHO_ORIGIN_WEBEXT");
1285 allow_origins = NULL;
1287 "rest",
1288 "REST_ALLOW_ORIGIN",
1289 &allow_origins))
1290 {
1292 "No CORS Access-Control-Allow-Origin header will be sent...\n");
1293 }
1294 if (GNUNET_OK !=
1296 "rest",
1297 "REST_ALLOW_CREDENTIALS",
1299 {
1300 // No origin specified
1302 "No CORS Credential Header will be sent...\n");
1303 }
1304
1306 "rest",
1307 "REST_ALLOW_HEADERS",
1308 &allow_headers))
1309 {
1310 // No origin specified
1312 "No CORS Access-Control-Allow-Headers Header will be sent...\n")
1313 ;
1314 }
1315
1316/* Open listen socket proxy */
1317 lsock6 = bind_v6 ();
1318 if (NULL == lsock6)
1319 {
1321 }
1322 else
1323 {
1325 {
1328 lsock6 = NULL;
1329 }
1330 else
1331 {
1333 lsock6,
1334 &do_accept,
1335 lsock6);
1336 }
1337 }
1338 lsock4 = bind_v4 ();
1339 if (NULL == lsock4)
1340 {
1342 }
1343 else
1344 {
1346 {
1349 lsock4 = NULL;
1350 }
1351 else
1352 {
1354 lsock4,
1355 &do_accept,
1356 lsock4);
1357 }
1358 }
1359 if ((NULL == lsock4) && (NULL == lsock6))
1360 {
1362 return;
1363 }
1364 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service listens on port %llu\n",
1365 port);
1366 httpd = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_NO_LISTEN_SOCKET
1367 | MHD_ALLOW_SUSPEND_RESUME,
1368 0,
1369 NULL,
1370 NULL,
1372 NULL,
1373 MHD_OPTION_CONNECTION_TIMEOUT,
1374 (unsigned int) 16,
1375 MHD_OPTION_NOTIFY_CONNECTION,
1377 NULL,
1378 MHD_OPTION_URI_LOG_CALLBACK,
1380 NULL,
1381 MHD_OPTION_NOTIFY_COMPLETED,
1383 NULL,
1384 MHD_OPTION_END);
1385 if (NULL == httpd)
1386 {
1388 return;
1389 }
1390 /* Load plugins */
1391 // FIXME: Use per-plugin rest plugin structs
1395 {
1397 }
1401 {
1403 }
1408 {
1410 }
1415 {
1417 }
1420 gns_plugin))
1421 {
1423 }
1424#if HAVE_JOSE
1425 openid_plugin = REST_openid_init (cfg);
1426 if (GNUNET_OK != setup_plugin (openid_plugin->name,
1427 &REST_openid_process_request, openid_plugin))
1428 {
1430 }
1431#endif
1435 {
1437 }
1439}
1440
1441
1442GNUNET_DAEMON_MAIN ("rest", _ ("GNUnet REST service"), &run)
1443
1444/* end of gnunet-rest-server.c */
void * REST_config_init(const struct GNUNET_CONFIGURATION_Handle *c)
Entry point for the plugin.
enum GNUNET_GenericReturnValue REST_config_process_request(void *plugin, struct GNUNET_REST_RequestHandle *conndata_handle, GNUNET_REST_ResultProcessor proc, void *proc_cls)
Function processing the REST call.
void REST_config_done(struct GNUNET_REST_Plugin *api)
Exit point from the plugin.
enum GNUNET_GenericReturnValue REST_copying_process_request(void *plugin, struct GNUNET_REST_RequestHandle *conndata_handle, GNUNET_REST_ResultProcessor proc, void *proc_cls)
Function processing the REST call.
void REST_copying_done(struct GNUNET_REST_Plugin *api)
Exit point from the plugin.
void * REST_copying_init(const struct GNUNET_CONFIGURATION_Handle *c)
Entry point for the plugin.
void * REST_gns_init(const struct GNUNET_CONFIGURATION_Handle *c)
Entry point for the plugin.
Definition gns_plugin.c:431
void REST_gns_done(struct GNUNET_REST_Plugin *api)
Exit point from the plugin.
Definition gns_plugin.c:463
enum GNUNET_GenericReturnValue REST_gns_process_request(void *plugin, struct GNUNET_REST_RequestHandle *rest_handle, GNUNET_REST_ResultProcessor proc, void *proc_cls)
Function processing the REST call.
Definition gns_plugin.c:386
static int ret
Final status code.
Definition gnunet-arm.c:93
static struct GNUNET_TIME_Relative timeout
User defined timestamp for completing operations.
Definition gnunet-arm.c:118
static int do_shutdown
Set to GNUNET_YES if we are shutting down.
static char * data
The data to insert into the dht.
struct GNUNET_HashCode key
The key used in the DHT.
static char * filename
static char * name
Name (label) of the records to list.
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 int status
The program status; 0 for success.
Definition gnunet-nse.c:39
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 int basic_auth_enabled
Do basic auth of user.
static struct GNUNET_NETWORK_Handle * bind_v4()
Create an IPv4 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 * bind_v6()
Create an IPv6 listen socket bound to our port.
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)
struct GNUNET_REST_Plugin * copying_plugin
#define GN_REST_STATE_PROCESSING
static void cleanup_ar(struct AcceptedRequest *ar)
static void * mhd_log_callback(void *cls, const char *url, struct MHD_Connection *connection)
Function called when MHD first processes an incoming connection.
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.
struct GNUNET_REST_Plugin * reclaim_plugin
static enum GNUNET_GenericReturnValue setup_plugin(const char *name, GNUNET_REST_ProcessingFunction proc, void *plugin_cls)
Callback for plugin load.
struct GNUNET_REST_Plugin * namestore_plugin
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.
struct GNUNET_REST_Plugin * gns_plugin
static struct AcceptedRequest * req_list_tail
AcceptedRequest list tail.
static char * allow_credentials
Allowed Credentials (CORS)
struct GNUNET_REST_Plugin * config_plugin
plugins
static void schedule_httpd()
Schedule MHD.
static struct MHD_Response * failure_response
Response we return on failures.
struct GNUNET_REST_Plugin * identity_plugin
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_VPN_Handle * handle
Handle to vpn service.
Definition gnunet-vpn.c:35
#define MHD_RESULT
Data type to use for functions return an "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:533
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:750
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:687
@ 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
int 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.
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.
void GNUNET_CONTAINER_multihashmap_destroy(struct GNUNET_CONTAINER_MultiHashMap *map)
Destroy a hash map.
struct GNUNET_CONTAINER_MultiHashMap * GNUNET_CONTAINER_multihashmap_create(unsigned int len, int do_not_copy_keys)
Create a multi hash map.
@ 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_GenericReturnValue
Named constants for return values.
@ GNUNET_SCHEDULER_PRIORITY_DEFAULT
Run with the default priority (normal P2P operations).
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
#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.
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_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:392
enum GNUNET_GenericReturnValue GNUNET_NETWORK_socket_close(struct GNUNET_NETWORK_Handle *desc)
Close a socket.
Definition network.c:508
void GNUNET_NETWORK_fdset_destroy(struct GNUNET_NETWORK_FDSet *fds)
Releases the associated memory of an fd set.
Definition network.c:1185
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_FDSet * GNUNET_NETWORK_fdset_create(void)
Creates an fd set.
Definition network.c:1169
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:439
enum GNUNET_GenericReturnValue GNUNET_NETWORK_socket_listen(const struct GNUNET_NETWORK_Handle *desc, int backlog)
Listen on a socket.
Definition network.c:652
#define GNUNET_DAEMON_MAIN(daemon_name, daemon_help, init_cb)
enum GNUNET_GenericReturnValue(* GNUNET_REST_ProcessingFunction)(void *plugin, struct GNUNET_REST_RequestHandle *handle, GNUNET_REST_ResultProcessor proc, void *proc_cls)
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition scheduler.c:567
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:1511
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:1835
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:1339
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition scheduler.c:980
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:1304
char * GNUNET_STRINGS_data_to_string_alloc(const void *buf, size_t size)
Return the base32crockford encoding of the given buffer.
Definition strings.c:812
char * GNUNET_STRINGS_utf8_tolower(const char *input)
Convert the utf-8 input string to lower case.
Definition strings.c:475
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
void REST_identity_done(struct GNUNET_REST_Plugin *api)
Exit point from the plugin.
void * REST_identity_init(const struct GNUNET_CONFIGURATION_Handle *c)
Entry point for the plugin.
enum GNUNET_GenericReturnValue REST_identity_process_request(void *plugin, struct GNUNET_REST_RequestHandle *rest_handle, GNUNET_REST_ResultProcessor proc, void *proc_cls)
Function processing the REST call.
#define max(x, y)
void REST_namestore_done(struct GNUNET_REST_Plugin *api)
Exit point from the plugin.
void * REST_namestore_init(const struct GNUNET_CONFIGURATION_Handle *c)
Entry point for the plugin.
enum GNUNET_GenericReturnValue REST_namestore_process_request(void *plugin, struct GNUNET_REST_RequestHandle *rest_handle, GNUNET_REST_ResultProcessor proc, void *proc_cls)
Function processing the REST call.
void REST_openid_done(struct GNUNET_REST_Plugin *api)
Exit point from the plugin.
enum GNUNET_GenericReturnValue REST_openid_process_request(void *plugin, struct GNUNET_REST_RequestHandle *rest_handle, GNUNET_REST_ResultProcessor proc, void *proc_cls)
Function processing the REST call.
void * REST_openid_init(const struct GNUNET_CONFIGURATION_Handle *c)
Entry point for the plugin.
static unsigned int size
Size of the "table".
Definition peer.c:68
#define _(String)
GNU gettext support macro.
Definition platform.h:179
void * REST_reclaim_init(const struct GNUNET_CONFIGURATION_Handle *c)
Entry point for the plugin.
void REST_reclaim_done(struct GNUNET_REST_Plugin *api)
Exit point from the plugin.
enum GNUNET_GenericReturnValue REST_reclaim_process_request(void *plugin, struct GNUNET_REST_RequestHandle *rest_handle, GNUNET_REST_ResultProcessor proc, void *proc_cls)
Function processing the REST call.
Accepted requests.
struct AcceptedRequest * prev
DLL.
struct MhdConnectionHandle * con_handle
Connection.
struct GNUNET_NETWORK_Handle * sock
Socket.
struct AcceptedRequest * next
DLL.
A 512-bit hashcode.
collection of IO descriptors
handle to a socket
Definition network.c:53
struct returned by the initialization function of the plugin
void * cls
The closure of the plugin.
const char * name
Plugin name.
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
char * libname
libname (to cleanup)
GNUNET_REST_ProcessingFunction process_request
Request function.
struct PluginListEntry * next
void * plugin
The plugin.