indentation
[oweals/gnunet.git] / src / util / service.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 2, or (at your
8      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      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file util/service.c
23  * @brief functions related to starting services
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_common.h"
28 #include "gnunet_configuration_lib.h"
29 #include "gnunet_crypto_lib.h"
30 #include "gnunet_directories.h"
31 #include "gnunet_disk_lib.h"
32 #include "gnunet_getopt_lib.h"
33 #include "gnunet_os_lib.h"
34 #include "gnunet_protocols.h"
35 #include "gnunet_resolver_service.h"
36 #include "gnunet_server_lib.h"
37 #include "gnunet_service_lib.h"
38
39 #define DEBUG_SERVICE GNUNET_NO
40
41 /* ******************* access control ******************** */
42
43 /**
44  * @brief IPV4 network in CIDR notation.
45  */
46 struct IPv4NetworkSet
47 {
48   struct in_addr network;
49   struct in_addr netmask;
50 };
51
52 /**
53  * @brief network in CIDR notation for IPV6.
54  */
55 struct IPv6NetworkSet
56 {
57   struct in6_addr network;
58   struct in6_addr netmask;
59 };
60
61
62 /**
63  * Parse a network specification. The argument specifies
64  * a list of networks. The format is
65  * <tt>[network/netmask;]*</tt> (no whitespace, must be terminated
66  * with a semicolon). The network must be given in dotted-decimal
67  * notation. The netmask can be given in CIDR notation (/16) or
68  * in dotted-decimal (/255.255.0.0).
69  * <p>
70  * @param routeList a string specifying the forbidden networks
71  * @return the converted list, NULL if the synatx is flawed
72  */
73 static struct IPv4NetworkSet *
74 parse_ipv4_specification (const char *routeList)
75 {
76   unsigned int count;
77   unsigned int i;
78   unsigned int j;
79   unsigned int len;
80   int cnt;
81   unsigned int pos;
82   unsigned int temps[8];
83   int slash;
84   struct IPv4NetworkSet *result;
85
86   if (routeList == NULL)
87     return NULL;
88   len = strlen (routeList);
89   if (len == 0)
90     return NULL;
91   count = 0;
92   for (i = 0; i < len; i++)
93     if (routeList[i] == ';')
94       count++;
95   result = GNUNET_malloc (sizeof (struct IPv4NetworkSet) * (count + 1));
96   /* add termination */
97   memset (result, 0, sizeof (struct IPv4NetworkSet) * (count + 1));
98   i = 0;
99   pos = 0;
100   while (i < count)
101   {
102     cnt = sscanf (&routeList[pos],
103                   "%u.%u.%u.%u/%u.%u.%u.%u;",
104                   &temps[0],
105                   &temps[1],
106                   &temps[2],
107                   &temps[3], &temps[4], &temps[5], &temps[6], &temps[7]);
108     if (cnt == 8)
109     {
110       for (j = 0; j < 8; j++)
111         if (temps[j] > 0xFF)
112         {
113           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
114                       _("Invalid format for IP: `%s'\n"), &routeList[pos]);
115           GNUNET_free (result);
116           return NULL;
117         }
118       result[i].network.s_addr
119           =
120           htonl ((temps[0] << 24) + (temps[1] << 16) + (temps[2] << 8) +
121                  temps[3]);
122       result[i].netmask.s_addr =
123           htonl ((temps[4] << 24) + (temps[5] << 16) + (temps[6] << 8) +
124                  temps[7]);
125       while (routeList[pos] != ';')
126         pos++;
127       pos++;
128       i++;
129       continue;
130     }
131     /* try second notation */
132     cnt = sscanf (&routeList[pos],
133                   "%u.%u.%u.%u/%u;",
134                   &temps[0], &temps[1], &temps[2], &temps[3], &slash);
135     if (cnt == 5)
136     {
137       for (j = 0; j < 4; j++)
138         if (temps[j] > 0xFF)
139         {
140           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
141                       _("Invalid format for IP: `%s'\n"), &routeList[pos]);
142           GNUNET_free (result);
143           return NULL;
144         }
145       result[i].network.s_addr
146           =
147           htonl ((temps[0] << 24) + (temps[1] << 16) + (temps[2] << 8) +
148                  temps[3]);
149       if ((slash <= 32) && (slash >= 0))
150       {
151         result[i].netmask.s_addr = 0;
152         while (slash > 0)
153         {
154           result[i].netmask.s_addr
155               = (result[i].netmask.s_addr >> 1) + 0x80000000;
156           slash--;
157         }
158         result[i].netmask.s_addr = htonl (result[i].netmask.s_addr);
159         while (routeList[pos] != ';')
160           pos++;
161         pos++;
162         i++;
163         continue;
164       }
165       else
166       {
167         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
168                     _
169                     ("Invalid network notation ('/%d' is not legal in IPv4 CIDR)."),
170                     slash);
171         GNUNET_free (result);
172         return NULL;            /* error */
173       }
174     }
175     /* try third notation */
176     slash = 32;
177     cnt = sscanf (&routeList[pos],
178                   "%u.%u.%u.%u;", &temps[0], &temps[1], &temps[2], &temps[3]);
179     if (cnt == 4)
180     {
181       for (j = 0; j < 4; j++)
182         if (temps[j] > 0xFF)
183         {
184           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
185                       _("Invalid format for IP: `%s'\n"), &routeList[pos]);
186           GNUNET_free (result);
187           return NULL;
188         }
189       result[i].network.s_addr
190           =
191           htonl ((temps[0] << 24) + (temps[1] << 16) + (temps[2] << 8) +
192                  temps[3]);
193       result[i].netmask.s_addr = 0;
194       while (slash > 0)
195       {
196         result[i].netmask.s_addr = (result[i].netmask.s_addr >> 1) + 0x80000000;
197         slash--;
198       }
199       result[i].netmask.s_addr = htonl (result[i].netmask.s_addr);
200       while (routeList[pos] != ';')
201         pos++;
202       pos++;
203       i++;
204       continue;
205     }
206     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
207                 _("Invalid format for IP: `%s'\n"), &routeList[pos]);
208     GNUNET_free (result);
209     return NULL;                /* error */
210   }
211   if (pos < strlen (routeList))
212   {
213     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
214                 _("Invalid format for IP: `%s'\n"), &routeList[pos]);
215     GNUNET_free (result);
216     return NULL;                /* oops */
217   }
218   return result;                /* ok */
219 }
220
221
222 /**
223  * Parse a network specification. The argument specifies
224  * a list of networks. The format is
225  * <tt>[network/netmask;]*</tt> (no whitespace, must be terminated
226  * with a semicolon). The network must be given in colon-hex
227  * notation.  The netmask must be given in CIDR notation (/16) or
228  * can be omitted to specify a single host.
229  * <p>
230  * @param routeListX a string specifying the forbidden networks
231  * @return the converted list, NULL if the synatx is flawed
232  */
233 static struct IPv6NetworkSet *
234 parse_ipv6_specification (const char *routeListX)
235 {
236   unsigned int count;
237   unsigned int i;
238   unsigned int len;
239   unsigned int pos;
240   int start;
241   int slash;
242   int ret;
243   char *routeList;
244   struct IPv6NetworkSet *result;
245   unsigned int bits;
246   unsigned int off;
247   int save;
248
249   if (routeListX == NULL)
250     return NULL;
251   len = strlen (routeListX);
252   if (len == 0)
253     return NULL;
254   routeList = GNUNET_strdup (routeListX);
255   count = 0;
256   for (i = 0; i < len; i++)
257     if (routeList[i] == ';')
258       count++;
259   if (routeList[len - 1] != ';')
260   {
261     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
262                 _
263                 ("Invalid network notation (does not end with ';': `%s')\n"),
264                 routeList);
265     GNUNET_free (routeList);
266     return NULL;
267   }
268
269   result = GNUNET_malloc (sizeof (struct IPv6NetworkSet) * (count + 1));
270   memset (result, 0, sizeof (struct IPv6NetworkSet) * (count + 1));
271   i = 0;
272   pos = 0;
273   while (i < count)
274   {
275     start = pos;
276     while (routeList[pos] != ';')
277       pos++;
278     slash = pos;
279     while ((slash >= start) && (routeList[slash] != '/'))
280       slash--;
281     if (slash < start)
282     {
283       memset (&result[i].netmask, 0xFF, sizeof (struct in6_addr));
284       slash = pos;
285     }
286     else
287     {
288       routeList[pos] = '\0';
289       ret = inet_pton (AF_INET6, &routeList[slash + 1], &result[i].netmask);
290       if (ret <= 0)
291       {
292         save = errno;
293         if ((1 != SSCANF (&routeList[slash + 1], "%u", &bits)) || (bits >= 128))
294         {
295           if (ret == 0)
296             GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
297                         _("Wrong format `%s' for netmask\n"),
298                         &routeList[slash + 1]);
299           else
300           {
301             errno = save;
302             GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "inet_pton");
303           }
304           GNUNET_free (result);
305           GNUNET_free (routeList);
306           return NULL;
307         }
308         off = 0;
309         while (bits > 8)
310         {
311           result[i].netmask.s6_addr[off++] = 0xFF;
312           bits -= 8;
313         }
314         while (bits > 0)
315         {
316           result[i].netmask.s6_addr[off]
317               = (result[i].netmask.s6_addr[off] >> 1) + 0x80;
318           bits--;
319         }
320       }
321     }
322     routeList[slash] = '\0';
323     ret = inet_pton (AF_INET6, &routeList[start], &result[i].network);
324     if (ret <= 0)
325     {
326       if (ret == 0)
327         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
328                     _("Wrong format `%s' for network\n"),
329                     &routeList[slash + 1]);
330       else
331         GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "inet_pton");
332       GNUNET_free (result);
333       GNUNET_free (routeList);
334       return NULL;
335     }
336     pos++;
337     i++;
338   }
339   GNUNET_free (routeList);
340   return result;
341 }
342
343
344 /**
345  * Check if the given IP address is in the list of IP addresses.
346  *
347  * @param list a list of networks
348  * @param add the IP to check (in network byte order)
349  * @return GNUNET_NO if the IP is not in the list, GNUNET_YES if it it is
350  */
351 static int
352 check_ipv4_listed (const struct IPv4NetworkSet *list, const struct in_addr *add)
353 {
354   int i;
355
356   i = 0;
357   if (list == NULL)
358     return GNUNET_NO;
359
360   while ((list[i].network.s_addr != 0) || (list[i].netmask.s_addr != 0))
361   {
362     if ((add->s_addr & list[i].netmask.s_addr) ==
363         (list[i].network.s_addr & list[i].netmask.s_addr))
364       return GNUNET_YES;
365     i++;
366   }
367   return GNUNET_NO;
368 }
369
370 /**
371  * Check if the given IP address is in the list of IP addresses.
372  *
373  * @param list a list of networks
374  * @param ip the IP to check (in network byte order)
375  * @return GNUNET_NO if the IP is not in the list, GNUNET_YES if it it is
376  */
377 static int
378 check_ipv6_listed (const struct IPv6NetworkSet *list, const struct in6_addr *ip)
379 {
380   unsigned int i;
381   unsigned int j;
382   struct in6_addr zero;
383
384   if (list == NULL)
385     return GNUNET_NO;
386
387   memset (&zero, 0, sizeof (struct in6_addr));
388   i = 0;
389 NEXT:
390   while (memcmp (&zero, &list[i].network, sizeof (struct in6_addr)) != 0)
391   {
392     for (j = 0; j < sizeof (struct in6_addr) / sizeof (int); j++)
393       if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) !=
394           (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j]))
395       {
396         i++;
397         goto NEXT;
398       }
399     return GNUNET_YES;
400   }
401   return GNUNET_NO;
402 }
403
404
405 /* ****************** service struct ****************** */
406
407
408 /**
409  * Context for "service_task".
410  */
411 struct GNUNET_SERVICE_Context
412 {
413   /**
414    * Our configuration.
415    */
416   const struct GNUNET_CONFIGURATION_Handle *cfg;
417
418   /**
419    * Handle for the server.
420    */
421   struct GNUNET_SERVER_Handle *server;
422
423   /**
424    * NULL-terminated array of addresses to bind to, NULL if we got pre-bound
425    * listen sockets.
426    */
427   struct sockaddr **addrs;
428
429   /**
430    * Name of our service.
431    */
432   const char *serviceName;
433
434   /**
435    * Main service-specific task to run.
436    */
437   GNUNET_SERVICE_Main task;
438
439   /**
440    * Closure for task.
441    */
442   void *task_cls;
443
444   /**
445    * IPv4 addresses that are not allowed to connect.
446    */
447   struct IPv4NetworkSet *v4_denied;
448
449   /**
450    * IPv6 addresses that are not allowed to connect.
451    */
452   struct IPv6NetworkSet *v6_denied;
453
454   /**
455    * IPv4 addresses that are allowed to connect (if not
456    * set, all are allowed).
457    */
458   struct IPv4NetworkSet *v4_allowed;
459
460   /**
461    * IPv6 addresses that are allowed to connect (if not
462    * set, all are allowed).
463    */
464   struct IPv6NetworkSet *v6_allowed;
465
466   /**
467    * My (default) message handlers.  Adjusted copy
468    * of "defhandlers".
469    */
470   struct GNUNET_SERVER_MessageHandler *my_handlers;
471
472   /**
473    * Array of the lengths of the entries in addrs.
474    */
475   socklen_t *addrlens;
476
477   /**
478    * NULL-terminated array of listen sockets we should take over.
479    */
480   struct GNUNET_NETWORK_Handle **lsocks;
481
482   /**
483    * Idle timeout for server.
484    */
485   struct GNUNET_TIME_Relative timeout;
486
487   /**
488    * Overall success/failure of the service start.
489    */
490   int ret;
491
492   /**
493    * If we are daemonizing, this FD is set to the
494    * pipe to the parent.  Send '.' if we started
495    * ok, '!' if not.  -1 if we are not daemonizing.
496    */
497   int ready_confirm_fd;
498
499   /**
500    * Do we close connections if we receive messages
501    * for which we have no handler?
502    */
503   int require_found;
504
505   /**
506    * Do we require a matching UID for UNIX domain socket
507    * connections?
508    */
509   int match_uid;
510
511   /**
512    * Do we require a matching GID for UNIX domain socket
513    * connections?
514    */
515   int match_gid;
516
517   /**
518    * Our options.
519    */
520   enum GNUNET_SERVICE_Options options;
521
522 };
523
524
525 /* ****************** message handlers ****************** */
526
527 static size_t
528 write_test (void *cls, size_t size, void *buf)
529 {
530   struct GNUNET_SERVER_Client *client = cls;
531   struct GNUNET_MessageHeader *msg;
532
533   if (size < sizeof (struct GNUNET_MessageHeader))
534   {
535     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
536     return 0;                   /* client disconnected */
537   }
538   msg = (struct GNUNET_MessageHeader *) buf;
539   msg->type = htons (GNUNET_MESSAGE_TYPE_TEST);
540   msg->size = htons (sizeof (struct GNUNET_MessageHeader));
541   GNUNET_SERVER_receive_done (client, GNUNET_OK);
542   return sizeof (struct GNUNET_MessageHeader);
543 }
544
545 /**
546  * Handler for TEST message.
547  *
548  * @param cls closure (refers to service)
549  * @param client identification of the client
550  * @param message the actual message
551  */
552 static void
553 handle_test (void *cls,
554              struct GNUNET_SERVER_Client *client,
555              const struct GNUNET_MessageHeader *message)
556 {
557   /* simply bounce message back to acknowledge */
558   if (NULL == GNUNET_SERVER_notify_transmit_ready (client,
559                                                    sizeof (struct
560                                                            GNUNET_MessageHeader),
561                                                    GNUNET_TIME_UNIT_FOREVER_REL,
562                                                    &write_test, client))
563     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
564 }
565
566
567 /**
568  * Default handlers for all services.  Will be copied and the
569  * "callback_cls" fields will be replaced with the specific service
570  * struct.
571  */
572 static const struct GNUNET_SERVER_MessageHandler defhandlers[] = {
573   {&handle_test, NULL, GNUNET_MESSAGE_TYPE_TEST,
574    sizeof (struct GNUNET_MessageHeader)},
575   {NULL, NULL, 0, 0}
576 };
577
578
579
580 /* ****************** service core routines ************** */
581
582
583 /**
584  * Check if access to the service is allowed from the given address.
585  *
586  * @param cls closure
587  * @param uc credentials, if available, otherwise NULL
588  * @param addr address
589  * @param addrlen length of address
590  * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR
591  *   for unknown address family (will be denied).
592  */
593 static int
594 check_access (void *cls,
595               const struct GNUNET_CONNECTION_Credentials *uc,
596               const struct sockaddr *addr, socklen_t addrlen)
597 {
598   struct GNUNET_SERVICE_Context *sctx = cls;
599   const struct sockaddr_in *i4;
600   const struct sockaddr_in6 *i6;
601   int ret;
602
603   switch (addr->sa_family)
604   {
605   case AF_INET:
606     GNUNET_assert (addrlen == sizeof (struct sockaddr_in));
607     i4 = (const struct sockaddr_in *) addr;
608     ret = ((sctx->v4_allowed == NULL) ||
609            (check_ipv4_listed (sctx->v4_allowed,
610                                &i4->sin_addr)))
611         && ((sctx->v4_denied == NULL) ||
612             (!check_ipv4_listed (sctx->v4_denied, &i4->sin_addr)));
613     break;
614   case AF_INET6:
615     GNUNET_assert (addrlen == sizeof (struct sockaddr_in6));
616     i6 = (const struct sockaddr_in6 *) addr;
617     ret = ((sctx->v6_allowed == NULL) ||
618            (check_ipv6_listed (sctx->v6_allowed,
619                                &i6->sin6_addr)))
620         && ((sctx->v6_denied == NULL) ||
621             (!check_ipv6_listed (sctx->v6_denied, &i6->sin6_addr)));
622     break;
623 #ifndef WINDOWS
624   case AF_UNIX:
625     ret = GNUNET_OK;            /* always OK for now */
626     if ((sctx->match_uid == GNUNET_YES) || (sctx->match_gid == GNUNET_YES))
627       ret = GNUNET_NO;
628     if ((uc != NULL) &&
629         ((sctx->match_uid != GNUNET_YES) ||
630          (uc->uid == geteuid ()) ||
631          (uc->uid == getuid ())) &&
632         ((sctx->match_gid != GNUNET_YES) ||
633          (uc->gid == getegid ()) || (uc->gid == getgid ())))
634       ret = GNUNET_YES;
635     else
636       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
637                   _("Access denied to UID %d / GID %d\n"),
638                   (uc == NULL) ? -1 : uc->uid, (uc == NULL) ? -1 : uc->gid);
639     break;
640 #endif
641   default:
642     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
643                 _("Unknown address family %d\n"), addr->sa_family);
644     return GNUNET_SYSERR;
645   }
646   if (ret != GNUNET_OK)
647   {
648     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
649                 _("Access from `%s' denied to service `%s'\n"),
650                 GNUNET_a2s (addr, addrlen), sctx->serviceName);
651   }
652   return ret;
653 }
654
655
656 /**
657  * Get the name of the file where we will
658  * write the PID of the service.
659  */
660 static char *
661 get_pid_file_name (struct GNUNET_SERVICE_Context *sctx)
662 {
663
664   char *pif;
665
666   if (GNUNET_OK !=
667       GNUNET_CONFIGURATION_get_value_filename (sctx->cfg,
668                                                sctx->serviceName,
669                                                "PIDFILE", &pif))
670     return NULL;
671   return pif;
672 }
673
674
675 /**
676  * Parse an IPv4 access control list.
677  */
678 static int
679 process_acl4 (struct IPv4NetworkSet **ret,
680               struct GNUNET_SERVICE_Context *sctx, const char *option)
681 {
682   char *opt;
683
684   if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->serviceName, option))
685     return GNUNET_OK;
686   GNUNET_break (GNUNET_OK ==
687                 GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
688                                                        sctx->serviceName,
689                                                        option, &opt));
690   if (NULL == (*ret = parse_ipv4_specification (opt)))
691   {
692     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
693                 _
694                 ("Could not parse IPv4 network specification `%s' for `%s:%s'\n"),
695                 opt, sctx->serviceName, option);
696     GNUNET_free (opt);
697     return GNUNET_SYSERR;
698   }
699   GNUNET_free (opt);
700   return GNUNET_OK;
701 }
702
703
704 /**
705  * Parse an IPv4 access control list.
706  */
707 static int
708 process_acl6 (struct IPv6NetworkSet **ret,
709               struct GNUNET_SERVICE_Context *sctx, const char *option)
710 {
711   char *opt;
712
713   if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->serviceName, option))
714     return GNUNET_OK;
715   GNUNET_break (GNUNET_OK ==
716                 GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
717                                                        sctx->serviceName,
718                                                        option, &opt));
719   if (NULL == (*ret = parse_ipv6_specification (opt)))
720   {
721     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
722                 _
723                 ("Could not parse IPv6 network specification `%s' for `%s:%s'\n"),
724                 opt, sctx->serviceName, option);
725     GNUNET_free (opt);
726     return GNUNET_SYSERR;
727   }
728   GNUNET_free (opt);
729   return GNUNET_OK;
730 }
731
732 /**
733  * Add the given UNIX domain path as an address to the
734  * list (as the first entry).
735  *
736  * @param saddrs array to update
737  * @param saddrlens where to store the address length
738  * @param unixpath path to add
739  */
740 static void
741 add_unixpath (struct sockaddr **saddrs,
742               socklen_t * saddrlens, const char *unixpath)
743 {
744 #ifdef AF_UNIX
745   struct sockaddr_un *un;
746   size_t slen;
747
748   un = GNUNET_malloc (sizeof (struct sockaddr_un));
749   un->sun_family = AF_UNIX;
750   slen = strlen (unixpath) + 1;
751   if (slen >= sizeof (un->sun_path))
752     slen = sizeof (un->sun_path) - 1;
753   memcpy (un->sun_path, unixpath, slen);
754   un->sun_path[slen] = '\0';
755   slen = sizeof (struct sockaddr_un);
756 #if LINUX
757   un->sun_path[0] = '\0';
758 #endif
759 #if HAVE_SOCKADDR_IN_SIN_LEN
760   un->sun_len = (u_char) slen;
761 #endif
762   *saddrs = (struct sockaddr *) un;
763   *saddrlens = slen;
764 #else
765   /* this function should never be called 
766    * unless AF_UNIX is defined! */
767   GNUNET_assert (0);
768 #endif
769 }
770
771
772 /**
773  * Get the list of addresses that a server for the given service
774  * should bind to.
775  *
776  * @param serviceName name of the service
777  * @param cfg configuration (which specifies the addresses)
778  * @param addrs set (call by reference) to an array of pointers to the
779  *              addresses the server should bind to and listen on; the
780  *              array will be NULL-terminated (on success)
781  * @param addr_lens set (call by reference) to an array of the lengths
782  *              of the respective 'struct sockaddr' struct in the 'addrs'
783  *              array (on success)
784  * @return number of addresses found on success,
785  *              GNUNET_SYSERR if the configuration
786  *              did not specify reasonable finding information or
787  *              if it specified a hostname that could not be resolved;
788  *              GNUNET_NO if the number of addresses configured is
789  *              zero (in this case, '*addrs' and '*addr_lens' will be
790  *              set to NULL).
791  */
792 int
793 GNUNET_SERVICE_get_server_addresses (const char *serviceName,
794                                      const struct GNUNET_CONFIGURATION_Handle
795                                      *cfg, struct sockaddr ***addrs,
796                                      socklen_t ** addr_lens)
797 {
798   int disablev6;
799   struct GNUNET_NETWORK_Handle *desc;
800   unsigned long long port;
801   char *unixpath;
802   struct addrinfo hints;
803   struct addrinfo *res;
804   struct addrinfo *pos;
805   struct addrinfo *next;
806   unsigned int i;
807   int resi;
808   int ret;
809   struct sockaddr **saddrs;
810   socklen_t *saddrlens;
811   char *hostname;
812
813   *addrs = NULL;
814   *addr_lens = NULL;
815   desc = NULL;
816   if (GNUNET_CONFIGURATION_have_value (cfg, serviceName, "DISABLEV6"))
817   {
818     if (GNUNET_SYSERR ==
819         (disablev6 = GNUNET_CONFIGURATION_get_value_yesno (cfg,
820                                                            serviceName,
821                                                            "DISABLEV6")))
822       return GNUNET_SYSERR;
823   }
824   else
825     disablev6 = GNUNET_NO;
826
827   if (!disablev6)
828   {
829     /* probe IPv6 support */
830     desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
831     if (NULL == desc)
832     {
833       if ((errno == ENOBUFS) ||
834           (errno == ENOMEM) || (errno == ENFILE) || (errno == EACCES))
835       {
836         GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
837         return GNUNET_SYSERR;
838       }
839       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
840                   _
841                   ("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
842                   serviceName, STRERROR (errno));
843       disablev6 = GNUNET_YES;
844     }
845     else
846     {
847       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
848       desc = NULL;
849     }
850   }
851
852   port = 0;
853   if (GNUNET_CONFIGURATION_have_value (cfg, serviceName, "PORT"))
854   {
855     GNUNET_break (GNUNET_OK ==
856                   GNUNET_CONFIGURATION_get_value_number (cfg,
857                                                          serviceName,
858                                                          "PORT", &port));
859     if (port > 65535)
860     {
861       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
862                   _
863                   ("Require valid port number for service `%s' in configuration!\n"),
864                   serviceName);
865       return GNUNET_SYSERR;
866     }
867   }
868
869   if (GNUNET_CONFIGURATION_have_value (cfg, serviceName, "BINDTO"))
870   {
871     GNUNET_break (GNUNET_OK ==
872                   GNUNET_CONFIGURATION_get_value_string (cfg,
873                                                          serviceName,
874                                                          "BINDTO", &hostname));
875   }
876   else
877     hostname = NULL;
878
879   unixpath = NULL;
880 #ifdef AF_UNIX
881   if ((GNUNET_YES == GNUNET_CONFIGURATION_have_value (cfg,
882                                                       serviceName, "UNIXPATH"))
883       && (GNUNET_OK ==
884           GNUNET_CONFIGURATION_get_value_string (cfg, serviceName, "UNIXPATH",
885                                                  &unixpath)) &&
886       (0 < strlen (unixpath)))
887   {
888     /* probe UNIX support */
889     struct sockaddr_un s_un;
890
891     if (strlen (unixpath) >= sizeof (s_un.sun_path))
892     {
893       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
894                   _("UNIXPATH `%s' too long, maximum length is %llu\n"),
895                   unixpath, sizeof (s_un.sun_path));
896       GNUNET_free_non_null (hostname);
897       GNUNET_free (unixpath);
898       return GNUNET_SYSERR;
899     }
900
901     desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
902     if (NULL == desc)
903     {
904       if ((errno == ENOBUFS) ||
905           (errno == ENOMEM) || (errno == ENFILE) || (errno == EACCES))
906       {
907         GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
908         GNUNET_free_non_null (hostname);
909         GNUNET_free (unixpath);
910         return GNUNET_SYSERR;
911       }
912       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
913                   _
914                   ("Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
915                   serviceName, STRERROR (errno));
916       GNUNET_free (unixpath);
917       unixpath = NULL;
918     }
919     else
920     {
921       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
922       desc = NULL;
923     }
924   }
925 #endif
926
927   if ((port == 0) && (unixpath == NULL))
928   {
929     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
930                 _
931                 ("Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
932                 serviceName);
933     GNUNET_free_non_null (hostname);
934     return GNUNET_SYSERR;
935   }
936   if (port == 0)
937   {
938     saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *));
939     saddrlens = GNUNET_malloc (2 * sizeof (socklen_t));
940     add_unixpath (saddrs, saddrlens, unixpath);
941     GNUNET_free_non_null (unixpath);
942     GNUNET_free_non_null (hostname);
943     *addrs = saddrs;
944     *addr_lens = saddrlens;
945     return 1;
946   }
947
948   if (hostname != NULL)
949   {
950 #if DEBUG_SERVICE
951     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
952                 "Resolving `%s' since that is where `%s' will bind to.\n",
953                 hostname, serviceName);
954 #endif
955     memset (&hints, 0, sizeof (struct addrinfo));
956     if (disablev6)
957       hints.ai_family = AF_INET;
958     if ((0 != (ret = getaddrinfo (hostname,
959                                   NULL, &hints, &res))) || (res == NULL))
960     {
961       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
962                   _("Failed to resolve `%s': %s\n"),
963                   hostname, gai_strerror (ret));
964       GNUNET_free (hostname);
965       GNUNET_free_non_null (unixpath);
966       return GNUNET_SYSERR;
967     }
968     next = res;
969     i = 0;
970     while (NULL != (pos = next))
971     {
972       next = pos->ai_next;
973       if ((disablev6) && (pos->ai_family == AF_INET6))
974         continue;
975       i++;
976     }
977     if (0 == i)
978     {
979       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
980                   _("Failed to find %saddress for `%s'.\n"),
981                   disablev6 ? "IPv4 " : "", hostname);
982       freeaddrinfo (res);
983       GNUNET_free (hostname);
984       GNUNET_free_non_null (unixpath);
985       return GNUNET_SYSERR;
986     }
987     resi = i;
988     if (NULL != unixpath)
989       resi++;
990     saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
991     saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
992     i = 0;
993     if (NULL != unixpath)
994     {
995       add_unixpath (saddrs, saddrlens, unixpath);
996       i++;
997     }
998     next = res;
999     while (NULL != (pos = next))
1000     {
1001       next = pos->ai_next;
1002       if ((disablev6) && (pos->ai_family == AF_INET6))
1003         continue;
1004       if ((pos->ai_protocol != IPPROTO_TCP) && (pos->ai_protocol != 0))
1005         continue;               /* not TCP */
1006       if ((pos->ai_socktype != SOCK_STREAM) && (pos->ai_socktype != 0))
1007         continue;               /* huh? */
1008 #if DEBUG_SERVICE
1009       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1010                   "Service `%s' will bind to `%s'\n",
1011                   serviceName, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
1012 #endif
1013       if (pos->ai_family == AF_INET)
1014       {
1015         GNUNET_assert (pos->ai_addrlen == sizeof (struct sockaddr_in));
1016         saddrlens[i] = pos->ai_addrlen;
1017         saddrs[i] = GNUNET_malloc (saddrlens[i]);
1018         memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1019         ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1020       }
1021       else
1022       {
1023         GNUNET_assert (pos->ai_family == AF_INET6);
1024         GNUNET_assert (pos->ai_addrlen == sizeof (struct sockaddr_in6));
1025         saddrlens[i] = pos->ai_addrlen;
1026         saddrs[i] = GNUNET_malloc (saddrlens[i]);
1027         memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1028         ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1029       }
1030       i++;
1031     }
1032     GNUNET_free (hostname);
1033     freeaddrinfo (res);
1034     resi = i;
1035   }
1036   else
1037   {
1038     /* will bind against everything, just set port */
1039     if (disablev6)
1040     {
1041       /* V4-only */
1042       resi = 1;
1043       if (NULL != unixpath)
1044         resi++;
1045       i = 0;
1046       saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1047       saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1048       if (NULL != unixpath)
1049       {
1050         add_unixpath (saddrs, saddrlens, unixpath);
1051         i++;
1052       }
1053       saddrlens[i] = sizeof (struct sockaddr_in);
1054       saddrs[i] = GNUNET_malloc (saddrlens[i]);
1055 #if HAVE_SOCKADDR_IN_SIN_LEN
1056       ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
1057 #endif
1058       ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1059       ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1060     }
1061     else
1062     {
1063       /* dual stack */
1064       resi = 2;
1065       if (NULL != unixpath)
1066         resi++;
1067       saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
1068       saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
1069       i = 0;
1070       if (NULL != unixpath)
1071       {
1072         add_unixpath (saddrs, saddrlens, unixpath);
1073         i++;
1074       }
1075       saddrlens[i] = sizeof (struct sockaddr_in6);
1076       saddrs[i] = GNUNET_malloc (saddrlens[i]);
1077 #if HAVE_SOCKADDR_IN_SIN_LEN
1078       ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
1079 #endif
1080       ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
1081       ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1082       i++;
1083       saddrlens[i] = sizeof (struct sockaddr_in);
1084       saddrs[i] = GNUNET_malloc (saddrlens[i]);
1085 #if HAVE_SOCKADDR_IN_SIN_LEN
1086       ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
1087 #endif
1088       ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1089       ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1090     }
1091   }
1092   GNUNET_free_non_null (unixpath);
1093   *addrs = saddrs;
1094   *addr_lens = saddrlens;
1095   return resi;
1096 }
1097
1098
1099 /**
1100  * Setup addr, addrlen, idle_timeout
1101  * based on configuration!
1102  *
1103  * Configuration may specify:
1104  * - PORT (where to bind to for TCP)
1105  * - UNIXPATH (where to bind to for UNIX domain sockets)
1106  * - TIMEOUT (after how many ms does an inactive service timeout);
1107  * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack)
1108  * - BINDTO (hostname or IP address to bind to, otherwise we take everything)
1109  * - ACCEPT_FROM  (only allow connections from specified IPv4 subnets)
1110  * - ACCEPT_FROM6 (only allow connections from specified IPv6 subnets)
1111  * - REJECT_FROM  (disallow allow connections from specified IPv4 subnets)
1112  * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets)
1113  *
1114  * @return GNUNET_OK if configuration succeeded
1115  */
1116 static int
1117 setup_service (struct GNUNET_SERVICE_Context *sctx)
1118 {
1119   struct GNUNET_TIME_Relative idleout;
1120   int tolerant;
1121
1122 #ifndef MINGW
1123   const char *lpid;
1124   unsigned int pid;
1125   const char *nfds;
1126   unsigned int cnt;
1127   int flags;
1128 #endif
1129
1130   if (GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->serviceName, "TIMEOUT"))
1131   {
1132     if (GNUNET_OK !=
1133         GNUNET_CONFIGURATION_get_value_time (sctx->cfg,
1134                                              sctx->serviceName,
1135                                              "TIMEOUT", &idleout))
1136     {
1137       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1138                   _("Specified value for `%s' of service `%s' is invalid\n"),
1139                   "TIMEOUT", sctx->serviceName);
1140       return GNUNET_SYSERR;
1141     }
1142     sctx->timeout = idleout;
1143   }
1144   else
1145     sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1146
1147   if (GNUNET_CONFIGURATION_have_value (sctx->cfg,
1148                                        sctx->serviceName, "TOLERANT"))
1149   {
1150     if (GNUNET_SYSERR ==
1151         (tolerant = GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg,
1152                                                           sctx->serviceName,
1153                                                           "TOLERANT")))
1154     {
1155       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1156                   _("Specified value for `%s' of service `%s' is invalid\n"),
1157                   "TOLERANT", sctx->serviceName);
1158       return GNUNET_SYSERR;
1159     }
1160   }
1161   else
1162     tolerant = GNUNET_NO;
1163
1164 #ifndef MINGW
1165   errno = 0;
1166   if ((NULL != (lpid = getenv ("LISTEN_PID"))) &&
1167       (1 == sscanf (lpid, "%u", &pid)) &&
1168       (getpid () == (pid_t) pid) &&
1169       (NULL != (nfds = getenv ("LISTEN_FDS"))) &&
1170       (1 == sscanf (nfds, "%u", &cnt)) &&
1171       (cnt > 0) && (cnt < FD_SETSIZE) && (cnt + 4 < FD_SETSIZE))
1172   {
1173     sctx->lsocks =
1174         GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (cnt + 1));
1175     while (0 < cnt--)
1176     {
1177       flags = fcntl (3 + cnt, F_GETFD);
1178       if ((flags < 0) ||
1179           (0 != (flags & FD_CLOEXEC)) ||
1180           (NULL ==
1181            (sctx->lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt))))
1182       {
1183         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1184                     _
1185                     ("Could not access pre-bound socket %u, will try to bind myself\n"),
1186                     (unsigned int) 3 + cnt);
1187         cnt++;
1188         while (sctx->lsocks[cnt] != NULL)
1189           GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[cnt++]));
1190         GNUNET_free (sctx->lsocks);
1191         sctx->lsocks = NULL;
1192         break;
1193       }
1194     }
1195     unsetenv ("LISTEN_PID");
1196     unsetenv ("LISTEN_FDS");
1197   }
1198 #endif
1199
1200   if ((sctx->lsocks == NULL) &&
1201       (GNUNET_SYSERR ==
1202        GNUNET_SERVICE_get_server_addresses (sctx->serviceName,
1203                                             sctx->cfg,
1204                                             &sctx->addrs, &sctx->addrlens)))
1205     return GNUNET_SYSERR;
1206   sctx->require_found = tolerant ? GNUNET_NO : GNUNET_YES;
1207   sctx->match_uid = GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg,
1208                                                           sctx->serviceName,
1209                                                           "UNIX_MATCH_UID");
1210   sctx->match_gid = GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg,
1211                                                           sctx->serviceName,
1212                                                           "UNIX_MATCH_GID");
1213   process_acl4 (&sctx->v4_denied, sctx, "REJECT_FROM");
1214   process_acl4 (&sctx->v4_allowed, sctx, "ACCEPT_FROM");
1215   process_acl6 (&sctx->v6_denied, sctx, "REJECT_FROM6");
1216   process_acl6 (&sctx->v6_allowed, sctx, "ACCEPT_FROM6");
1217
1218   return GNUNET_OK;
1219 }
1220
1221
1222 /**
1223  * Get the name of the user that'll be used
1224  * to provide the service.
1225  */
1226 static char *
1227 get_user_name (struct GNUNET_SERVICE_Context *sctx)
1228 {
1229
1230   char *un;
1231
1232   if (GNUNET_OK !=
1233       GNUNET_CONFIGURATION_get_value_filename (sctx->cfg,
1234                                                sctx->serviceName,
1235                                                "USERNAME", &un))
1236     return NULL;
1237   return un;
1238 }
1239
1240 /**
1241  * Write PID file.
1242  */
1243 static int
1244 write_pid_file (struct GNUNET_SERVICE_Context *sctx, pid_t pid)
1245 {
1246   FILE *pidfd;
1247   char *pif;
1248   char *user;
1249   char *rdir;
1250   int len;
1251
1252   if (NULL == (pif = get_pid_file_name (sctx)))
1253     return GNUNET_OK;           /* no file desired */
1254   user = get_user_name (sctx);
1255   rdir = GNUNET_strdup (pif);
1256   len = strlen (rdir);
1257   while ((len > 0) && (rdir[len] != DIR_SEPARATOR))
1258     len--;
1259   rdir[len] = '\0';
1260   if (0 != ACCESS (rdir, F_OK))
1261   {
1262     /* we get to create a directory -- and claim it
1263      * as ours! */
1264     GNUNET_DISK_directory_create (rdir);
1265     if ((user != NULL) && (0 < strlen (user)))
1266       GNUNET_DISK_file_change_owner (rdir, user);
1267   }
1268   if (0 != ACCESS (rdir, W_OK | X_OK))
1269   {
1270     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "access", rdir);
1271     GNUNET_free (rdir);
1272     GNUNET_free_non_null (user);
1273     GNUNET_free (pif);
1274     return GNUNET_SYSERR;
1275   }
1276   GNUNET_free (rdir);
1277   pidfd = FOPEN (pif, "w");
1278   if (pidfd == NULL)
1279   {
1280     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "fopen", pif);
1281     GNUNET_free (pif);
1282     GNUNET_free_non_null (user);
1283     return GNUNET_SYSERR;
1284   }
1285   if (0 > FPRINTF (pidfd, "%u", pid))
1286     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "fprintf", pif);
1287   GNUNET_break (0 == fclose (pidfd));
1288   if ((user != NULL) && (0 < strlen (user)))
1289     GNUNET_DISK_file_change_owner (pif, user);
1290   GNUNET_free_non_null (user);
1291   GNUNET_free (pif);
1292   return GNUNET_OK;
1293 }
1294
1295
1296 /**
1297  * Task run during shutdown.
1298  *
1299  * @param cls unused
1300  * @param tc unused
1301  */
1302 static void
1303 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1304 {
1305   struct GNUNET_SERVER_Handle *server = cls;
1306
1307   GNUNET_SERVER_destroy (server);
1308 }
1309
1310
1311 /**
1312  * Initial task for the service.
1313  */
1314 static void
1315 service_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1316 {
1317   struct GNUNET_SERVICE_Context *sctx = cls;
1318   unsigned int i;
1319
1320   GNUNET_RESOLVER_connect (sctx->cfg);
1321   if (sctx->lsocks != NULL)
1322     sctx->server = GNUNET_SERVER_create_with_sockets (&check_access,
1323                                                       sctx,
1324                                                       sctx->lsocks,
1325                                                       sctx->timeout,
1326                                                       sctx->require_found);
1327   else
1328     sctx->server = GNUNET_SERVER_create (&check_access,
1329                                          sctx,
1330                                          sctx->addrs,
1331                                          sctx->addrlens,
1332                                          sctx->timeout, sctx->require_found);
1333   if (sctx->server == NULL)
1334   {
1335     if (sctx->addrs != NULL)
1336     {
1337       i = 0;
1338       while (sctx->addrs[i] != NULL)
1339       {
1340         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1341                     _("Failed to start `%s' at `%s'\n"),
1342                     sctx->serviceName,
1343                     GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
1344         i++;
1345       }
1346     }
1347     sctx->ret = GNUNET_SYSERR;
1348     return;
1349   }
1350   if (0 == (sctx->options & GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN))
1351   {
1352     /* install a task that will kill the server
1353      * process if the scheduler ever gets a shutdown signal */
1354     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1355                                   &shutdown_task, sctx->server);
1356   }
1357   sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers));
1358   memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers));
1359   i = 0;
1360   while ((sctx->my_handlers[i].callback != NULL))
1361     sctx->my_handlers[i++].callback_cls = sctx;
1362   GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers);
1363   if (sctx->ready_confirm_fd != -1)
1364   {
1365     GNUNET_break (1 == WRITE (sctx->ready_confirm_fd, ".", 1));
1366     GNUNET_break (0 == CLOSE (sctx->ready_confirm_fd));
1367     sctx->ready_confirm_fd = -1;
1368     write_pid_file (sctx, getpid ());
1369   }
1370   if (sctx->addrs != NULL)
1371   {
1372     i = 0;
1373     while (sctx->addrs[i] != NULL)
1374     {
1375       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1376                   _("Service `%s' runs at %s\n"),
1377                   sctx->serviceName,
1378                   GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
1379       i++;
1380     }
1381   }
1382   sctx->task (sctx->task_cls, sctx->server, sctx->cfg);
1383 }
1384
1385
1386 /**
1387  * Detach from terminal.
1388  */
1389 static int
1390 detach_terminal (struct GNUNET_SERVICE_Context *sctx)
1391 {
1392 #ifndef MINGW
1393   pid_t pid;
1394   int nullfd;
1395   int filedes[2];
1396
1397   if (0 != PIPE (filedes))
1398   {
1399     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "pipe");
1400     return GNUNET_SYSERR;
1401   }
1402   pid = fork ();
1403   if (pid < 0)
1404   {
1405     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fork");
1406     return GNUNET_SYSERR;
1407   }
1408   if (pid != 0)
1409   {
1410     /* Parent */
1411     char c;
1412
1413     GNUNET_break (0 == CLOSE (filedes[1]));
1414     c = 'X';
1415     if (1 != READ (filedes[0], &c, sizeof (char)))
1416       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "read");
1417     fflush (stdout);
1418     switch (c)
1419     {
1420     case '.':
1421       exit (0);
1422     case 'I':
1423       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1424                   _("Service process failed to initialize\n"));
1425       break;
1426     case 'S':
1427       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1428                   _("Service process could not initialize server function\n"));
1429       break;
1430     case 'X':
1431       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1432                   _("Service process failed to report status\n"));
1433       break;
1434     }
1435     exit (1);                   /* child reported error */
1436   }
1437   GNUNET_break (0 == CLOSE (0));
1438   GNUNET_break (0 == CLOSE (1));
1439   GNUNET_break (0 == CLOSE (filedes[0]));
1440   nullfd = OPEN ("/dev/null", O_RDWR | O_APPEND);
1441   if (nullfd < 0)
1442     return GNUNET_SYSERR;
1443   /* set stdin/stdout to /dev/null */
1444   if ((dup2 (nullfd, 0) < 0) || (dup2 (nullfd, 1) < 0))
1445   {
1446     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "dup2");
1447     (void) CLOSE (nullfd);
1448     return GNUNET_SYSERR;
1449   }
1450   (void) CLOSE (nullfd);
1451   /* Detach from controlling terminal */
1452   pid = setsid ();
1453   if (pid == -1)
1454     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "setsid");
1455   sctx->ready_confirm_fd = filedes[1];
1456 #else
1457   /* FIXME: we probably need to do something else
1458    * elsewhere in order to fork the process itself... */
1459   FreeConsole ();
1460 #endif
1461   return GNUNET_OK;
1462 }
1463
1464
1465 /**
1466  * Set user ID.
1467  */
1468 static int
1469 set_user_id (struct GNUNET_SERVICE_Context *sctx)
1470 {
1471   char *user;
1472
1473   if (NULL == (user = get_user_name (sctx)))
1474     return GNUNET_OK;           /* keep */
1475 #ifndef MINGW
1476   struct passwd *pws;
1477
1478   errno = 0;
1479   pws = getpwnam (user);
1480   if (pws == NULL)
1481   {
1482     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1483                 _("Cannot obtain information about user `%s': %s\n"),
1484                 user, errno == 0 ? _("No such user") : STRERROR (errno));
1485     GNUNET_free (user);
1486     return GNUNET_SYSERR;
1487   }
1488   if ((0 != setgid (pws->pw_gid)) || (0 != setegid (pws->pw_gid)) ||
1489 #if HAVE_INITGROUPS
1490       (0 != initgroups (user, pws->pw_gid)) ||
1491 #endif
1492       (0 != setuid (pws->pw_uid)) || (0 != seteuid (pws->pw_uid)))
1493   {
1494     if ((0 != setregid (pws->pw_gid, pws->pw_gid)) ||
1495         (0 != setreuid (pws->pw_uid, pws->pw_uid)))
1496     {
1497       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1498                   _("Cannot change user/group to `%s': %s\n"), user,
1499                   STRERROR (errno));
1500       GNUNET_free (user);
1501       return GNUNET_SYSERR;
1502     }
1503   }
1504 #endif
1505   GNUNET_free (user);
1506   return GNUNET_OK;
1507 }
1508
1509
1510 /**
1511  * Delete the PID file that was created by our parent.
1512  */
1513 static void
1514 pid_file_delete (struct GNUNET_SERVICE_Context *sctx)
1515 {
1516   char *pif = get_pid_file_name (sctx);
1517
1518   if (pif == NULL)
1519     return;                     /* no PID file */
1520   if (0 != UNLINK (pif))
1521     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", pif);
1522   GNUNET_free (pif);
1523 }
1524
1525
1526 /**
1527  * Run a standard GNUnet service startup sequence (initialize loggers
1528  * and configuration, parse options).
1529  *
1530  * @param argc number of command line arguments
1531  * @param argv command line arguments
1532  * @param serviceName our service name
1533  * @param opt service options
1534  * @param task main task of the service
1535  * @param task_cls closure for task
1536  * @return GNUNET_SYSERR on error, GNUNET_OK
1537  *         if we shutdown nicely
1538  */
1539 int
1540 GNUNET_SERVICE_run (int argc,
1541                     char *const *argv,
1542                     const char *serviceName,
1543                     enum GNUNET_SERVICE_Options opt,
1544                     GNUNET_SERVICE_Main task, void *task_cls)
1545 {
1546 #define HANDLE_ERROR do { err = 1; GNUNET_break (0); goto shutdown; } while (0)
1547
1548   int err;
1549   char *cfg_fn;
1550   char *loglev;
1551   char *logfile;
1552   int do_daemonize;
1553   unsigned int i;
1554   unsigned long long skew_offset;
1555   unsigned long long skew_variance;
1556   long long clock_offset;
1557   struct GNUNET_SERVICE_Context sctx;
1558   struct GNUNET_CONFIGURATION_Handle *cfg;
1559
1560   struct GNUNET_GETOPT_CommandLineOption service_options[] = {
1561     GNUNET_GETOPT_OPTION_CFG_FILE (&cfg_fn),
1562     {'d', "daemonize", NULL,
1563      gettext_noop ("do daemonize (detach from terminal)"), 0,
1564      GNUNET_GETOPT_set_one, &do_daemonize},
1565     GNUNET_GETOPT_OPTION_HELP (serviceName),
1566     GNUNET_GETOPT_OPTION_LOGLEVEL (&loglev),
1567     GNUNET_GETOPT_OPTION_LOGFILE (&logfile),
1568     GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION),
1569     GNUNET_GETOPT_OPTION_END
1570   };
1571   err = 0;
1572   do_daemonize = 0;
1573   logfile = NULL;
1574   loglev = GNUNET_strdup ("WARNING");
1575   cfg_fn = GNUNET_strdup (GNUNET_DEFAULT_USER_CONFIG_FILE);
1576   memset (&sctx, 0, sizeof (sctx));
1577   sctx.options = opt;
1578   sctx.ready_confirm_fd = -1;
1579   sctx.ret = GNUNET_OK;
1580   sctx.timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1581   sctx.task = task;
1582   sctx.task_cls = task_cls;
1583   sctx.serviceName = serviceName;
1584   sctx.cfg = cfg = GNUNET_CONFIGURATION_create ();
1585   /* setup subsystems */
1586   if (GNUNET_SYSERR == GNUNET_GETOPT_run (serviceName, service_options, argc,
1587                                           argv))
1588     goto shutdown;
1589   if (GNUNET_OK != GNUNET_log_setup (serviceName, loglev, logfile))
1590     HANDLE_ERROR;
1591   if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfg_fn))
1592     goto shutdown;
1593   if (GNUNET_OK != setup_service (&sctx))
1594     goto shutdown;
1595   if ((do_daemonize == 1) && (GNUNET_OK != detach_terminal (&sctx)))
1596     HANDLE_ERROR;
1597   if (GNUNET_OK != set_user_id (&sctx))
1598     goto shutdown;
1599 #if DEBUG_SERVICE
1600   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1601               "Service `%s' runs with configuration from `%s'\n",
1602               serviceName, cfg_fn);
1603 #endif
1604   if (GNUNET_OK ==
1605       GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "testing", "skew_offset",
1606                                              &skew_offset) &&
1607       (GNUNET_OK ==
1608        GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "testing",
1609                                               "skew_variance", &skew_variance)))
1610   {
1611     clock_offset = skew_offset - skew_variance;
1612     GNUNET_TIME_set_offset (clock_offset);
1613 #if DEBUG_SERVICE
1614     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Skewing clock by %dll\n",
1615                 clock_offset);
1616 #endif
1617   }
1618   /* actually run service */
1619   GNUNET_SCHEDULER_run (&service_task, &sctx);
1620
1621   /* shutdown */
1622   if ((do_daemonize == 1) && (sctx.server != NULL))
1623     pid_file_delete (&sctx);
1624   GNUNET_free_non_null (sctx.my_handlers);
1625
1626 shutdown:
1627   if (sctx.ready_confirm_fd != -1)
1628   {
1629     if (1 != WRITE (sctx.ready_confirm_fd, err ? "I" : "S", 1))
1630       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "write");
1631     GNUNET_break (0 == CLOSE (sctx.ready_confirm_fd));
1632   }
1633
1634   GNUNET_CONFIGURATION_destroy (cfg);
1635   i = 0;
1636   if (sctx.addrs != NULL)
1637     while (sctx.addrs[i] != NULL)
1638       GNUNET_free (sctx.addrs[i++]);
1639   GNUNET_free_non_null (sctx.addrs);
1640   GNUNET_free_non_null (sctx.addrlens);
1641   GNUNET_free_non_null (logfile);
1642   GNUNET_free (loglev);
1643   GNUNET_free (cfg_fn);
1644   GNUNET_free_non_null (sctx.v4_denied);
1645   GNUNET_free_non_null (sctx.v6_denied);
1646   GNUNET_free_non_null (sctx.v4_allowed);
1647   GNUNET_free_non_null (sctx.v6_allowed);
1648
1649   return err ? GNUNET_SYSERR : sctx.ret;
1650 }
1651
1652
1653 /**
1654  * Run a service startup sequence within an existing
1655  * initialized system.
1656  *
1657  * @param serviceName our service name
1658  * @param cfg configuration to use
1659  * @return NULL on error, service handle
1660  */
1661 struct GNUNET_SERVICE_Context *
1662 GNUNET_SERVICE_start (const char *serviceName,
1663                       const struct GNUNET_CONFIGURATION_Handle *cfg)
1664 {
1665   int i;
1666   struct GNUNET_SERVICE_Context *sctx;
1667
1668   sctx = GNUNET_malloc (sizeof (struct GNUNET_SERVICE_Context));
1669   sctx->ready_confirm_fd = -1;  /* no daemonizing */
1670   sctx->ret = GNUNET_OK;
1671   sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1672   sctx->serviceName = serviceName;
1673   sctx->cfg = cfg;
1674
1675   /* setup subsystems */
1676   if (GNUNET_OK != setup_service (sctx))
1677   {
1678     GNUNET_SERVICE_stop (sctx);
1679     return NULL;
1680   }
1681   if (sctx->lsocks != NULL)
1682     sctx->server = GNUNET_SERVER_create_with_sockets (&check_access,
1683                                                       sctx,
1684                                                       sctx->lsocks,
1685                                                       sctx->timeout,
1686                                                       sctx->require_found);
1687   else
1688     sctx->server = GNUNET_SERVER_create (&check_access,
1689                                          sctx,
1690                                          sctx->addrs,
1691                                          sctx->addrlens,
1692                                          sctx->timeout, sctx->require_found);
1693
1694   if (NULL == sctx->server)
1695   {
1696     GNUNET_SERVICE_stop (sctx);
1697     return NULL;
1698   }
1699   sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers));
1700   memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers));
1701   i = 0;
1702   while ((sctx->my_handlers[i].callback != NULL))
1703     sctx->my_handlers[i++].callback_cls = sctx;
1704   GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers);
1705   return sctx;
1706 }
1707
1708 /**
1709  * Obtain the server used by a service.  Note that the server must NOT
1710  * be destroyed by the caller.
1711  *
1712  * @param ctx the service context returned from the start function
1713  * @return handle to the server for this service, NULL if there is none
1714  */
1715 struct GNUNET_SERVER_Handle *
1716 GNUNET_SERVICE_get_server (struct GNUNET_SERVICE_Context *ctx)
1717 {
1718   return ctx->server;
1719 }
1720
1721
1722 /**
1723  * Stop a service that was started with "GNUNET_SERVICE_start".
1724  *
1725  * @param sctx the service context returned from the start function
1726  */
1727 void
1728 GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Context *sctx)
1729 {
1730   unsigned int i;
1731
1732   if (NULL != sctx->server)
1733     GNUNET_SERVER_destroy (sctx->server);
1734   GNUNET_free_non_null (sctx->my_handlers);
1735   if (sctx->addrs != NULL)
1736   {
1737     i = 0;
1738     while (sctx->addrs[i] != NULL)
1739       GNUNET_free (sctx->addrs[i++]);
1740     GNUNET_free (sctx->addrs);
1741   }
1742   GNUNET_free_non_null (sctx->addrlens);
1743   GNUNET_free_non_null (sctx->v4_denied);
1744   GNUNET_free_non_null (sctx->v6_denied);
1745   GNUNET_free_non_null (sctx->v4_allowed);
1746   GNUNET_free_non_null (sctx->v6_allowed);
1747   GNUNET_free (sctx);
1748 }
1749
1750
1751 /* end of service.c */