GNUnet 0.22.2
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
221{
226
231
236
241
246};
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_strdup (key);
394 GNUNET_CRYPTO_hash (lowerkey, strlen (lowerkey), &hkey);
395 GNUNET_asprintf (&val, "%s", value);
397 handle->header_param_map,
398 &hkey,
399 val,
401 {
403 "Could not load add header `%s'=%s\n",
404 lowerkey,
405 value);
406 }
407 GNUNET_free (lowerkey);
408 return MHD_YES;
409}
410
411
412static int
413url_iterator (void *cls,
414 enum MHD_ValueKind kind,
415 const char *key,
416 const char *value)
417{
418 struct GNUNET_REST_RequestHandle *handle = cls;
419 struct GNUNET_HashCode hkey;
420 char *val;
421
422 GNUNET_CRYPTO_hash (key, strlen (key), &hkey);
423 GNUNET_asprintf (&val, "%s", value);
425 handle->url_param_map,
426 &hkey,
427 val,
429 {
431 "Could not load add url param `%s'=%s\n",
432 key,
433 value);
434 }
435 return MHD_YES;
436}
437
438
439static MHD_RESULT
440post_data_iter (void *cls,
441 enum MHD_ValueKind kind,
442 const char *key,
443 const char *filename,
444 const char *content_type,
445 const char *transfer_encoding,
446 const char *data,
447 uint64_t off,
448 size_t size)
449{
450 struct GNUNET_REST_RequestHandle *handle = cls;
451 struct GNUNET_HashCode hkey;
452 char *val;
453
454 if (MHD_POSTDATA_KIND != kind)
455 return MHD_YES;
456
457 GNUNET_CRYPTO_hash (key, strlen (key), &hkey);
458 val = GNUNET_CONTAINER_multihashmap_get (handle->url_param_map,
459 &hkey);
460 if (NULL == val)
461 {
462 val = GNUNET_malloc (65536);
464 handle->url_param_map,
465 &hkey,
466 val,
468 {
470 "Could not add url param '%s'\n",
471 key);
472 GNUNET_free (val);
473 }
474 }
475 memcpy (val + off, data, size);
476 return MHD_YES;
477}
478
479
480/* ********************************* MHD response generation ******************* */
481
505static MHD_RESULT
507 struct MHD_Connection *con,
508 const char *url,
509 const char *meth,
510 const char *ver,
511 const char *upload_data,
512 size_t *upload_data_size,
513 void **con_cls)
514{
515 char *origin;
516 char *pw;
517 char *user;
518 struct AcceptedRequest *ar;
519 struct GNUNET_HashCode key;
520 struct MhdConnectionHandle *con_handle;
521 struct GNUNET_REST_RequestHandle *rest_conndata_handle;
522 struct PluginListEntry *ple;
523
524 ar = *con_cls;
525 if (NULL == ar)
526 {
527 GNUNET_break (0);
528 return MHD_NO;
529 }
530
531 if (NULL == ar->con_handle)
532 {
533 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New connection %s\n", url);
534 con_handle = GNUNET_new (struct MhdConnectionHandle);
535 con_handle->con = con;
536 con_handle->state = GN_REST_STATE_INIT;
537 ar->con_handle = con_handle;
538 return MHD_YES;
539 }
540 con_handle = ar->con_handle;
541 if (GN_REST_STATE_INIT == con_handle->state)
542 {
543 rest_conndata_handle = GNUNET_new (struct GNUNET_REST_RequestHandle);
544 rest_conndata_handle->method = meth;
545 rest_conndata_handle->url = url;
546 rest_conndata_handle->data = upload_data;
547 rest_conndata_handle->data_size = *upload_data_size;
548 rest_conndata_handle->url_param_map =
550 rest_conndata_handle->header_param_map =
552 con_handle->data_handle = rest_conndata_handle;
553 MHD_get_connection_values (con,
554 MHD_GET_ARGUMENT_KIND,
555 (MHD_KeyValueIterator) & url_iterator,
556 rest_conndata_handle);
557 MHD_get_connection_values (con,
558 MHD_HEADER_KIND,
559 (MHD_KeyValueIterator) & header_iterator,
560 rest_conndata_handle);
562 {
563 pw = NULL;
564 user = MHD_basic_auth_get_username_password (con, &pw);
565 if ((NULL == user) ||
566 (0 != strcmp (user, cuser)))
567 {
569 "Unknown user %s\n", user);
570 MHD_queue_basic_auth_fail_response (con, "gnunet", failure_response);
571 return MHD_YES;
572 }
573 if ((NULL == pw) ||
574 (0 != strcmp (pw, basic_auth_secret)))
575 {
577 "Password incorrect\n");
578 MHD_queue_basic_auth_fail_response (con, "gnunet", failure_response);
579 GNUNET_free (pw);
580 return MHD_YES;
581 }
582 GNUNET_free (pw);
583 }
584
585 con_handle->pp = MHD_create_post_processor (con,
586 65536,
588 rest_conndata_handle);
589 if (*upload_data_size)
590 {
591 MHD_post_process (con_handle->pp, upload_data, *upload_data_size);
592 }
593 MHD_destroy_post_processor (con_handle->pp);
594
595 con_handle->state = GN_REST_STATE_PROCESSING;
596 for (ple = plugins_head; NULL != ple; ple = ple->next)
597 {
598 if (GNUNET_YES == ple->process_request (ple->plugin,
599 rest_conndata_handle,
601 con_handle))
602 break; /* Request handled */
603 }
604 if (NULL == ple)
605 {
607 MHD_queue_response (con, MHD_HTTP_NOT_FOUND, failure_response);
608 }
609 *upload_data_size = 0;
610 run_mhd_now ();
611 return MHD_YES;
612 }
613 if (NULL == con_handle->response)
614 {
615 // Suspend connection until plugin is done
616 MHD_suspend_connection (con_handle->con);
617 return MHD_YES;
618 }
619 // MHD_resume_connection (con_handle->con);
621 "Queueing response from plugin with MHD\n");
622 // Handle Preflights for extensions
623 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Checking origin\n");
624 GNUNET_CRYPTO_hash ("origin", strlen ("origin"), &key);
627 &key);
628 if (NULL != origin)
629 {
630 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Origin: %s\n", origin);
631 // Only echo for browser plugins
632 if (GNUNET_YES == echo_origin)
633 {
634 if ((0 ==
635 strncmp ("moz-extension://", origin, strlen ("moz-extension://"))) ||
636 (0 == strncmp ("chrome-extension://",
637 origin,
638 strlen ("chrome-extension://"))))
639 {
640 GNUNET_assert (MHD_NO != MHD_add_response_header (con_handle->response,
641 MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
642 origin));
643 }
644 }
645 if (NULL != allow_origins)
646 {
647 char *tmp = GNUNET_strdup (allow_origins);
648 char *allow_origin = strtok (tmp, ",");
649 while (NULL != allow_origin)
650 {
651 if (0 == strncmp (allow_origin, origin, strlen (allow_origin)))
652 {
653 GNUNET_assert (MHD_NO != MHD_add_response_header (
654 con_handle->response,
655 MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
656 allow_origin));
657 break;
658 }
659 allow_origin = strtok (NULL, ",");
660 }
661 GNUNET_free (tmp);
662 }
663 }
664 if (NULL != allow_credentials)
665 {
666 GNUNET_assert (MHD_NO != MHD_add_response_header (con_handle->response,
667 "Access-Control-Allow-Credentials",
669 }
670 if (NULL != allow_headers)
671 {
672 GNUNET_assert (MHD_NO != MHD_add_response_header (con_handle->response,
673 "Access-Control-Allow-Headers",
675 }
676 run_mhd_now ();
677 {
678 MHD_RESULT ret = MHD_queue_response (con,
679 con_handle->status,
680 con_handle->response);
681 // cleanup_handle (con_handle);
682 return ret;
683 }
684}
685
686
687/* ******************** MHD HTTP setup and event loop ******************** */
688
689
693static void
695{
696 if (NULL != httpd)
697 {
698 MHD_stop_daemon (httpd);
699 httpd = NULL;
700 }
701 if (NULL != httpd_task)
702 {
704 httpd_task = NULL;
705 }
706 if (NULL != ltask4)
707 {
709 ltask4 = NULL;
710 }
711 if (NULL != ltask6)
712 {
714 ltask6 = NULL;
715 }
716
717 if (NULL != lsock4)
718 {
720 lsock4 = NULL;
721 }
722 if (NULL != lsock6)
723 {
725 lsock6 = NULL;
726 }
727}
728
729
737static void
739{
740 fd_set rs;
741 fd_set ws;
742 fd_set es;
743 struct GNUNET_NETWORK_FDSet *wrs;
744 struct GNUNET_NETWORK_FDSet *wws;
745 int max;
746 int haveto;
747 MHD_UNSIGNED_LONG_LONG timeout;
748 struct GNUNET_TIME_Relative tv;
749
750 FD_ZERO (&rs);
751 FD_ZERO (&ws);
752 FD_ZERO (&es);
753 max = -1;
754 if (MHD_YES != MHD_get_fdset (httpd, &rs, &ws, &es, &max))
755 {
756 kill_httpd ();
757 return;
758 }
759 haveto = MHD_get_timeout (httpd, &timeout);
760 if (MHD_YES == haveto)
761 tv.rel_value_us = (uint64_t) timeout * 1000LL;
762 else
764 if (-1 != max)
765 {
770 }
771 else
772 {
773 wrs = NULL;
774 wws = NULL;
775 }
776 if (NULL != httpd_task)
777 {
779 httpd_task = NULL;
780 }
781 if ((MHD_YES == haveto) || (-1 != max))
782 {
784 tv,
785 wrs,
786 wws,
787 &do_httpd,
788 NULL);
789 }
790 if (NULL != wrs)
792 if (NULL != wws)
794}
795
796
810static void *
812 const char *url,
813 struct MHD_Connection *connection)
814{
815 struct AcceptedRequest *ar;
816 const union MHD_ConnectionInfo *ci;
817
818 ci = MHD_get_connection_info (connection,
819 MHD_CONNECTION_INFO_SOCKET_CONTEXT);
820 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing %s\n", url);
821 if (NULL == ci)
822 {
823 GNUNET_break (0);
824 return NULL;
825 }
826 ar = ci->socket_context;
827 return ar;
828}
829
830
840static void
842 struct MHD_Connection *connection,
843 void **con_cls,
844 enum MHD_RequestTerminationCode toe)
845{
846 struct AcceptedRequest *ar = *con_cls;
847 if (MHD_REQUEST_TERMINATED_COMPLETED_OK != toe)
849 "MHD encountered error handling request: %d\n",
850 toe);
851 if (NULL == ar)
852 return;
853 if (NULL != ar->con_handle)
854 {
856 ar->con_handle = NULL;
857 }
859 *con_cls = NULL;
860}
861
862
872static void
874 struct MHD_Connection *connection,
875 void **con_cls,
876 enum MHD_ConnectionNotificationCode cnc)
877{
878 struct AcceptedRequest *ar;
879 const union MHD_ConnectionInfo *ci;
880 int sock;
881
882 switch (cnc)
883 {
884 case MHD_CONNECTION_NOTIFY_STARTED:
885 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection started...\n");
886 ci = MHD_get_connection_info (connection,
887 MHD_CONNECTION_INFO_CONNECTION_FD);
888 if (NULL == ci)
889 {
890 GNUNET_break (0);
891 return;
892 }
893 sock = ci->connect_fd;
894 for (ar = req_list_head; NULL != ar; ar = ar->next)
895 {
896 if (GNUNET_NETWORK_get_fd (ar->sock) == sock)
897 {
899 "Context set...\n");
900 *con_cls = ar;
901 break;
902 }
903 }
904 break;
905
906 case MHD_CONNECTION_NOTIFY_CLOSED:
908 "Connection closed... cleaning up\n");
909 ar = *con_cls;
910 if (NULL == ar)
911 {
913 "Connection stale!\n");
914 return;
915 }
916 cleanup_ar (ar);
917 *con_cls = NULL;
918 break;
919
920 default:
921 GNUNET_break (0);
922 }
923}
924
925
931static void
932do_httpd (void *cls)
933{
934 httpd_task = NULL;
935 MHD_run (httpd);
937}
938
939
945static void
946do_accept (void *cls)
947{
948 struct GNUNET_NETWORK_Handle *lsock = cls;
949 struct AcceptedRequest *ar;
950 int fd;
951 const struct sockaddr *addr;
952 socklen_t len;
953
954 GNUNET_assert (NULL != lsock);
955 if (lsock == lsock4)
956 {
958 lsock,
959 &do_accept,
960 lsock);
961 }
962 else if (lsock == lsock6)
963 {
965 lsock,
966 &do_accept,
967 lsock);
968 }
969 else
970 GNUNET_assert (0);
971 ar = GNUNET_new (struct AcceptedRequest);
973 ar->sock = GNUNET_NETWORK_socket_accept (lsock, NULL, NULL);
974 if (NULL == ar->sock)
975 {
976 GNUNET_free (ar);
978 return;
979 }
981 "Got an inbound connection, waiting for data\n");
982 fd = GNUNET_NETWORK_get_fd (ar->sock);
983 addr = GNUNET_NETWORK_get_addr (ar->sock);
987 ar);
988 if (MHD_YES != MHD_add_connection (httpd, fd, addr, len))
989 {
991 GNUNET_free (ar);
993 _ ("Failed to pass client to MHD\n"));
994 return;
995 }
997}
998
999
1005static void
1006do_shutdown (void *cls)
1007{
1008 struct PluginListEntry *ple;
1009
1010 while (NULL != plugins_head)
1011 {
1012 ple = plugins_head;
1015 ple);
1016 GNUNET_free (ple->libname);
1017 GNUNET_free (ple);
1018 }
1024#if HAVE_JOSE
1025 REST_openid_done (openid_plugin);
1026#endif
1028 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down...\n");
1029 kill_httpd ();
1032 MHD_destroy_response (failure_response);
1033}
1034
1035
1041static struct GNUNET_NETWORK_Handle *
1043{
1044 struct GNUNET_NETWORK_Handle *ls;
1045 struct sockaddr_in sa4;
1046 int eno;
1047
1048 memset (&sa4, 0, sizeof(sa4));
1049 sa4.sin_family = AF_INET;
1050 sa4.sin_port = htons (port);
1051 sa4.sin_addr.s_addr = address;
1052#if HAVE_SOCKADDR_IN_SIN_LEN
1053 sa4.sin_len = sizeof(sa4);
1054#endif
1055 ls = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0);
1056 if (NULL == ls)
1057 return NULL;
1059 (const struct sockaddr *) &sa4,
1060 sizeof(sa4)))
1061 {
1062 eno = errno;
1064 errno = eno;
1065 return NULL;
1066 }
1067 return ls;
1068}
1069
1070
1076static struct GNUNET_NETWORK_Handle *
1078{
1079 struct GNUNET_NETWORK_Handle *ls;
1080 struct sockaddr_in6 sa6;
1081 int eno;
1082
1083 memset (&sa6, 0, sizeof(sa6));
1084 sa6.sin6_family = AF_INET6;
1085 sa6.sin6_port = htons (port);
1086 sa6.sin6_addr = address6;
1087#if HAVE_SOCKADDR_IN_SIN_LEN
1088 sa6.sin6_len = sizeof(sa6);
1089#endif
1090 ls = GNUNET_NETWORK_socket_create (AF_INET6, SOCK_STREAM, 0);
1091 if (NULL == ls)
1092 return NULL;
1094 (const struct sockaddr *) &sa6,
1095 sizeof(sa6)))
1096 {
1097 eno = errno;
1099 errno = eno;
1100 return NULL;
1101 }
1102 return ls;
1103}
1104
1105
1113static enum GNUNET_GenericReturnValue
1114setup_plugin (const char *name,
1116 void *plugin_cls)
1117{
1118 struct PluginListEntry *ple;
1119
1120 if (NULL == plugin_cls)
1121 {
1123 "Could not load plugin\n");
1124 return GNUNET_SYSERR;
1125 }
1126 GNUNET_assert (1 < strlen (name));
1127 GNUNET_assert ('/' == *name);
1128 ple = GNUNET_new (struct PluginListEntry);
1129 ple->libname = GNUNET_strdup (name);
1130 ple->plugin = plugin_cls;
1131 ple->process_request = proc;
1134 ple);
1135 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loaded plugin `%s'\n", name);
1136 return GNUNET_OK;
1137}
1138
1139
1148static void
1149run (void *cls,
1150 char *const *args,
1151 const char *cfgfile,
1152 const struct GNUNET_CONFIGURATION_Handle *c)
1153{
1154 static const char *err_page = "{}";
1155 char *addr_str;
1156 char *basic_auth_file;
1157 uint64_t secret;
1158
1159 cfg = c;
1160 plugins_head = NULL;
1161 plugins_tail = NULL;
1162 failure_response = MHD_create_response_from_buffer (strlen (err_page),
1163 (void *) err_page,
1164 MHD_RESPMEM_PERSISTENT);
1165 /* Get port to bind to */
1166 if (GNUNET_OK !=
1167 GNUNET_CONFIGURATION_get_value_number (cfg, "rest", "HTTP_PORT", &port))
1168 {
1169 // No address specified
1170 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Using default port...\n");
1172 }
1173
1174 /* Get address to bind to */
1175 if (GNUNET_OK !=
1176 GNUNET_CONFIGURATION_get_value_string (cfg, "rest", "BIND_TO", &addr_str))
1177 {
1178 // No address specified
1179 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Don't know what to bind to...\n");
1181 return;
1182 }
1183 if (1 != inet_pton (AF_INET, addr_str, &address))
1184 {
1186 "Unable to parse address %s\n",
1187 addr_str);
1188 GNUNET_free (addr_str);
1190 return;
1191 }
1192 GNUNET_free (addr_str);
1193 /* Get address to bind to */
1195 "rest",
1196 "BIND_TO6",
1197 &addr_str))
1198 {
1199 // No address specified
1200 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Don't know what to bind6 to...\n");
1202 return;
1203 }
1204 if (1 != inet_pton (AF_INET6, addr_str, &address6))
1205 {
1207 "Unable to parse IPv6 address %s\n",
1208 addr_str);
1209 GNUNET_free (addr_str);
1211 return;
1212 }
1213 GNUNET_free (addr_str);
1214
1216 "rest",
1217 "BASIC_AUTH_ENABLED");
1219 {
1221 "rest",
1222 "BASIC_AUTH_SECRET_FILE",
1223 &basic_auth_file))
1224 {
1226 "No basic auth secret file location set...\n");
1228 return;
1229 }
1230 if (GNUNET_YES != GNUNET_DISK_file_test (basic_auth_file))
1231 {
1233 "No basic auth secret found... generating\n");
1235 UINT64_MAX);
1237 sizeof(secret));
1238 if (GNUNET_OK !=
1239 GNUNET_DISK_fn_write (basic_auth_file,
1241 strlen (basic_auth_secret),
1245 "write",
1246 basic_auth_file);
1247 GNUNET_free (basic_auth_file);
1248 }
1249 else
1250 {
1251 char basic_auth_secret_tmp[16]; // Should be more than enough
1252 memset (basic_auth_secret_tmp, 0, 16);
1253 if (GNUNET_SYSERR == GNUNET_DISK_fn_read (basic_auth_file,
1254 basic_auth_secret_tmp,
1255 sizeof (basic_auth_secret_tmp)
1256 - 1))
1257 {
1259 "Unable to read basic auth secret file.\n");
1261 GNUNET_free (basic_auth_file);
1262 return;
1263 }
1264 GNUNET_free (basic_auth_file);
1265 if (0 != getlogin_r (cuser, _POSIX_LOGIN_NAME_MAX))
1266 {
1268 "Unable to get user.\n");
1270 return;
1271 }
1272 basic_auth_secret = GNUNET_strdup (basic_auth_secret_tmp);
1273 }
1274 }
1275
1276 /* Get CORS data from cfg */
1277 echo_origin =
1279 "rest",
1280 "REST_ECHO_ORIGIN_WEBEXT");
1281 allow_origins = NULL;
1283 "rest",
1284 "REST_ALLOW_ORIGIN",
1285 &allow_origins))
1286 {
1288 "No CORS Access-Control-Allow-Origin header will be sent...\n");
1289 }
1290 if (GNUNET_OK !=
1292 "rest",
1293 "REST_ALLOW_CREDENTIALS",
1295 {
1296 // No origin specified
1298 "No CORS Credential Header will be sent...\n");
1299 }
1300
1302 "rest",
1303 "REST_ALLOW_HEADERS",
1304 &allow_headers))
1305 {
1306 // No origin specified
1308 "No CORS Access-Control-Allow-Headers Header will be sent...\n");
1309 }
1310
1311/* Open listen socket proxy */
1312 lsock6 = bind_v6 ();
1313 if (NULL == lsock6)
1314 {
1316 }
1317 else
1318 {
1320 {
1323 lsock6 = NULL;
1324 }
1325 else
1326 {
1328 lsock6,
1329 &do_accept,
1330 lsock6);
1331 }
1332 }
1333 lsock4 = bind_v4 ();
1334 if (NULL == lsock4)
1335 {
1337 }
1338 else
1339 {
1341 {
1344 lsock4 = NULL;
1345 }
1346 else
1347 {
1349 lsock4,
1350 &do_accept,
1351 lsock4);
1352 }
1353 }
1354 if ((NULL == lsock4) && (NULL == lsock6))
1355 {
1357 return;
1358 }
1359 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service listens on port %llu\n",
1360 port);
1361 httpd = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_NO_LISTEN_SOCKET
1362 | MHD_ALLOW_SUSPEND_RESUME,
1363 0,
1364 NULL,
1365 NULL,
1367 NULL,
1368 MHD_OPTION_CONNECTION_TIMEOUT,
1369 (unsigned int) 16,
1370 MHD_OPTION_NOTIFY_CONNECTION,
1372 NULL,
1373 MHD_OPTION_URI_LOG_CALLBACK,
1375 NULL,
1376 MHD_OPTION_NOTIFY_COMPLETED,
1378 NULL,
1379 MHD_OPTION_END);
1380 if (NULL == httpd)
1381 {
1383 return;
1384 }
1385 /* Load plugins */
1386 // FIXME: Use per-plugin rest plugin structs
1390 {
1392 }
1396 {
1398 }
1403 {
1405 }
1410 {
1412 }
1415 gns_plugin))
1416 {
1418 }
1419#if HAVE_JOSE
1420 openid_plugin = REST_openid_init (cfg);
1421 if (GNUNET_OK != setup_plugin (openid_plugin->name,
1422 &REST_openid_process_request, openid_plugin))
1423 {
1425 }
1426#endif
1430 {
1432 }
1434}
1435
1436
1437GNUNET_DAEMON_MAIN ("rest", _ ("GNUnet REST service"), &run)
1438
1439/* 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 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 do_shutdown(void *cls)
Task run on shutdown.
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:506
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:722
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:660
@ 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:787
enum GNUNET_GenericReturnValue GNUNET_STRINGS_utf8_tolower(const char *input, char *output)
Convert the utf-8 input string to lower case.
Definition: strings.c:459
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
@ MHD_HTTP_NOT_FOUND
Not Found [RFC7231, Section 6.5.4].
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:178
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.