Example #1
0
/**
 * Convert an absolute domain name in the ".zkey" pTLD to the
 * respective public key.
 *
 * @param zkey string "X.zkey" where X is the coordinates of the public
 *         key in an encoding suitable for DNS labels.
 * @param pkey set to a public key on the eliptic curve
 * @return #GNUNET_SYSERR if @a zkey has the wrong syntax
 */
int
GNUNET_GNSRECORD_zkey_to_pkey (const char *zkey,
			       struct GNUNET_CRYPTO_EcdsaPublicKey *pkey)
{
  char *cpy;
  char *dot;
  const char *x;

  cpy = GNUNET_strdup (zkey);
  x = cpy;
  if (NULL == (dot = strchr (x, (int) '.')))
    goto error;
  *dot = '\0';
  if (0 != strcasecmp (dot + 1,
		       "zkey"))
    goto error;

  if (GNUNET_OK !=
      GNUNET_CRYPTO_ecdsa_public_key_from_string (x,
						strlen (x),
						pkey))
    goto error;
  GNUNET_free (cpy);
  return GNUNET_OK;
 error:
  GNUNET_free (cpy);
  return GNUNET_SYSERR;
}
/**
 * We got a block back from the namestore.  Decrypt it
 * and continue to process the result.
 *
 * @param cls the 'struct Request' we are processing
 * @param zone private key of the zone; NULL on disconnect
 * @param label label of the records; NULL on disconnect
 * @param rd_count number of entries in @a rd array, 0 if label was deleted
 * @param rd array of records with data to store
 */
static void
lookup_block_processor (void *cls,
                        const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
                        const char *label,
                        unsigned int rd_count,
                        const struct GNUNET_GNSRECORD_Data *rd)
{
  struct Request *request = cls;

  request->qe = NULL;
  if (0 == rd_count)
  {

    if (GNUNET_OK !=
        GNUNET_CRYPTO_ecdsa_public_key_from_string (request->public_key,
                                                    strlen (request->public_key),
                                                    &request->pub))
    {
      GNUNET_break (0);
      request->phase = RP_FAIL;
      run_httpd_now ();
      return;
    }
    request->qe = GNUNET_NAMESTORE_zone_to_name (ns,
                                                 &fcfs_zone_pkey,
                                                 &request->pub,
                                                 &zone_to_name_cb,
                                                 request);
    return;
  }
  GNUNET_break (0 != rd_count);
  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
              _("Found %u existing records for domain `%s'\n"),
              rd_count,
              request->domain_name);
  request->phase = RP_FAIL;
  run_httpd_now ();
  return;
}
Example #3
0
/**
 * Function called with the result from the check if the namestore
 * service is actually running.  If it is, we start the actual
 * operation.
 *
 * @param cls closure with our configuration
 * @param result #GNUNET_YES if the namestore service is running
 */
static void
testservice_task (void *cls,
                  int result)
{
  const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
  struct GNUNET_CRYPTO_EcdsaPublicKey pub;
  struct GNUNET_GNSRECORD_Data rd;

  if (GNUNET_YES != result)
  {
    FPRINTF (stderr, _("Service `%s' is not running\n"),
	     "namestore");
    return;
  }
  if (! (add|del|list|(NULL != nickstring)|(NULL != uri)|(NULL != reverse_pkey)) )
  {
    /* nothing more to be done */
    fprintf (stderr,
             _("No options given\n"));
    GNUNET_SCHEDULER_shutdown ();
    return;
  }
  GNUNET_CRYPTO_ecdsa_key_get_public (&zone_pkey,
                                    &pub);

  ns = GNUNET_NAMESTORE_connect (cfg);
  if (NULL == ns)
  {
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                _("Failed to connect to namestore\n"));
    return;
  }
  if (add)
  {
    if (NULL == name)
    {
      fprintf (stderr,
               _("Missing option `%s' for operation `%s'\n"),
               "-n", _("add"));
      GNUNET_SCHEDULER_shutdown ();
      ret = 1;
      return;
    }
    if (NULL == typestring)
    {
      fprintf (stderr,
	       _("Missing option `%s' for operation `%s'\n"),
	       "-t", _("add"));
      GNUNET_SCHEDULER_shutdown ();
      ret = 1;
      return;
    }
    type = GNUNET_GNSRECORD_typename_to_number (typestring);
    if (UINT32_MAX == type)
    {
      fprintf (stderr, _("Unsupported type `%s'\n"), typestring);
      GNUNET_SCHEDULER_shutdown ();
      ret = 1;
      return;
    }
    if (NULL == value)
    {
      fprintf (stderr,
	       _("Missing option `%s' for operation `%s'\n"),
	       "-V", _("add"));
      ret = 1;
      GNUNET_SCHEDULER_shutdown ();
      return;
    }
    if (GNUNET_OK !=
	GNUNET_GNSRECORD_string_to_value (type,
					  value,
					  &data,
					  &data_size))
    {
      fprintf (stderr, _("Value `%s' invalid for record type `%s'\n"),
	       value,
	       typestring);
      GNUNET_SCHEDULER_shutdown ();
      ret = 1;
      return;
    }
    if (NULL == expirationstring)
    {
      fprintf (stderr,
	       _("Missing option `%s' for operation `%s'\n"),
	       "-e", _("add"));
      GNUNET_SCHEDULER_shutdown ();
      ret = 1;
      return;
    }
    if (0 == strcmp (expirationstring, "never"))
    {
      etime_abs = GNUNET_TIME_UNIT_FOREVER_ABS;
      etime_is_rel = GNUNET_NO;
    }
    else if (GNUNET_OK ==
             GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
                                                    &etime_rel))
    {
      etime_is_rel = GNUNET_YES;
    }
    else if (GNUNET_OK ==
             GNUNET_STRINGS_fancy_time_to_absolute (expirationstring,
                                                    &etime_abs))
    {
      etime_is_rel = GNUNET_NO;
    }
    else
    {
      fprintf (stderr,
               _("Invalid time format `%s'\n"),
               expirationstring);
      GNUNET_SCHEDULER_shutdown ();
      ret = 1;
      return;
    }
    add_qe = GNUNET_NAMESTORE_records_lookup (ns, &zone_pkey, name,
        &get_existing_record, NULL );
  }
  if (del)
  {
    if (NULL == name)
    {
      fprintf (stderr,
               _("Missing option `%s' for operation `%s'\n"),
               "-n", _("del"));
      GNUNET_SCHEDULER_shutdown ();
      ret = 1;
      return;
    }
    del_qe = GNUNET_NAMESTORE_records_lookup (ns,
                                              &zone_pkey,
                                              name,
                                              &del_monitor,
                                              NULL);
  }
  if (list)
  {
    list_it = GNUNET_NAMESTORE_zone_iteration_start (ns,
                                                     &zone_pkey,
                                                     &display_record,
                                                     NULL);
  }
  if (NULL != reverse_pkey)
  {
    struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;

    if (GNUNET_OK !=
        GNUNET_CRYPTO_ecdsa_public_key_from_string (reverse_pkey,
                                                       strlen (reverse_pkey),
                                                       &pubkey))
    {
      fprintf (stderr,
               _("Invalid public key for reverse lookup `%s'\n"),
               reverse_pkey);
      GNUNET_SCHEDULER_shutdown ();
    }
    reverse_qe = GNUNET_NAMESTORE_zone_to_name (ns,
                                                &zone_pkey,
                                                &pubkey,
                                                &handle_reverse_lookup,
                                                NULL);
  }
  if (NULL != uri)
  {
    char sh[105];
    char sname[64];
    struct GNUNET_CRYPTO_EcdsaPublicKey pkey;

    GNUNET_STRINGS_utf8_tolower (uri, uri);
    if ( (2 != (sscanf (uri,
                        "gnunet://gns/%52s/%63s",
                        sh,
                        sname)) ) ||
         (GNUNET_OK != GNUNET_CRYPTO_ecdsa_public_key_from_string (sh, strlen (sh), &pkey)) )
    {
      fprintf (stderr,
               _("Invalid URI `%s'\n"),
               uri);
      GNUNET_SCHEDULER_shutdown ();
      ret = 1;
      return;
    }
    memset (&rd, 0, sizeof (rd));
    rd.data = &pkey;
    rd.data_size = sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
    rd.record_type = GNUNET_GNSRECORD_TYPE_PKEY;
    if (GNUNET_YES == etime_is_rel)
    {
      rd.expiration_time = etime_rel.rel_value_us;
      rd.flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
    }
    else if (GNUNET_NO == etime_is_rel)
      rd.expiration_time = etime_abs.abs_value_us;
    else
      rd.expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;

    if (1 == is_shadow)
      rd.flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
    add_qe_uri = GNUNET_NAMESTORE_records_store (ns,
						 &zone_pkey,
						 sname,
						 1,
						 &rd,
						 &add_continuation,
						 &add_qe_uri);
  }
  if (NULL != nickstring)
  {
    if (0 == strlen(nickstring))
    {
      fprintf (stderr,
               _("Invalid nick `%s'\n"),
               nickstring);
      GNUNET_SCHEDULER_shutdown ();
      ret = 1;
      return;
    }
    add_qe_uri = GNUNET_NAMESTORE_set_nick(ns, &zone_pkey, nickstring,
        &add_continuation, &add_qe_uri);
  }
  if (monitor)
  {
    zm = GNUNET_NAMESTORE_zone_monitor_start (cfg,
					      &zone_pkey,
                                              GNUNET_YES,
					      &display_record,
					      &sync_cb,
					      NULL);
  }
}
Example #4
0
/**
 * Convert human-readable version of a 'value' of a record to the binary
 * representation.
 *
 * @param cls closure, unused
 * @param type type of the record
 * @param s human-readable string
 * @param data set to value in binary encoding (will be allocated)
 * @param data_size set to number of bytes in @a data
 * @return #GNUNET_OK on success
 */
static int
gns_string_to_value (void *cls,
                     uint32_t type,
                     const char *s,
                     void **data,
                     size_t *data_size)
{
  struct GNUNET_CRYPTO_EcdsaPublicKey pkey;

  if (NULL == s)
    return GNUNET_SYSERR;
  switch (type)
  {

  case GNUNET_GNSRECORD_TYPE_PKEY:
    if (GNUNET_OK !=
	GNUNET_CRYPTO_ecdsa_public_key_from_string (s, strlen (s), &pkey))
    {
      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
           _("Unable to parse PKEY record `%s'\n"),
           s);
      return GNUNET_SYSERR;
    }
    *data = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey);
    memcpy (*data, &pkey, sizeof (pkey));
    *data_size = sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
    return GNUNET_OK;

  case GNUNET_GNSRECORD_TYPE_NICK:
    *data = GNUNET_strdup (s);
    *data_size = strlen (s);
    return GNUNET_OK;
  case GNUNET_GNSRECORD_TYPE_LEHO:
    *data = GNUNET_strdup (s);
    *data_size = strlen (s);
    return GNUNET_OK;
  case GNUNET_GNSRECORD_TYPE_GNS2DNS:
    {
      char nsbuf[514];
      char *cpy;
      char *at;
      size_t off;

      cpy = GNUNET_strdup (s);
      at = strchr (cpy, '@');
      if (NULL == at)
      {
        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                    _("Unable to parse GNS2DNS record `%s'\n"),
                    s);
        GNUNET_free (cpy);
        return GNUNET_SYSERR;
      }
      *at = '\0';
      at++;

      off = 0;
      if ( (GNUNET_OK !=
            GNUNET_DNSPARSER_builder_add_name (nsbuf,
                                               sizeof (nsbuf),
                                               &off,
                                               cpy)) ||
           (GNUNET_OK !=
            GNUNET_DNSPARSER_builder_add_name (nsbuf,
                                               sizeof (nsbuf),
                                               &off,
                                               at)) )
      {
	GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                    _("Failed to serialize GNS2DNS record with value `%s'\n"),
                    s);
        GNUNET_free (cpy);
	return GNUNET_SYSERR;
      }
      GNUNET_free (cpy);
      *data_size = off;
      *data = GNUNET_malloc (off);
      memcpy (*data, nsbuf, off);
      return GNUNET_OK;
    }
  case GNUNET_GNSRECORD_TYPE_VPN:
    {
      struct GNUNET_TUN_GnsVpnRecord *vpn;
      char s_peer[103 + 1];
      char s_serv[253 + 1];
      unsigned int proto;

      if (3 != SSCANF (s,
                       "%u %103s %253s",
                       &proto, s_peer, s_serv))
      {
        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                    _("Unable to parse VPN record string `%s'\n"),
                    s);
        return GNUNET_SYSERR;
      }
      *data_size = sizeof (struct GNUNET_TUN_GnsVpnRecord) + strlen (s_serv) + 1;
      *data = vpn = GNUNET_malloc (*data_size);
      if (GNUNET_OK != GNUNET_CRYPTO_eddsa_public_key_from_string ((char*) s_peer,
                                                                   strlen (s_peer),
                                                                   &vpn->peer.public_key))
      {
        GNUNET_free (vpn);
        *data_size = 0;
        return GNUNET_SYSERR;
      }
      vpn->proto = htons ((uint16_t) proto);
      strcpy ((char*)&vpn[1], s_serv);
      return GNUNET_OK;
    }
  case GNUNET_GNSRECORD_TYPE_BOX:
    {
      struct GNUNET_GNSRECORD_BoxRecord *box;
      size_t rest;
      unsigned int protocol;
      unsigned int service;
      unsigned int record_type;
      void *bval;
      size_t bval_size;

      if (3 != SSCANF (s,
                       "%u %u %u ",
                       &protocol,
                       &service,
                       &record_type))
      {
        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                    _("Unable to parse BOX record string `%s'\n"),
                    s);
        return GNUNET_SYSERR;
      }
      rest = snprintf (NULL, 0,
                       "%u %u %u ",
                       protocol,
                       service,
                       record_type);
      if (GNUNET_OK !=
          GNUNET_GNSRECORD_string_to_value (record_type,
                                            &s[rest],
                                            &bval,
                                            &bval_size))
        return GNUNET_SYSERR;
      *data_size = sizeof (struct GNUNET_GNSRECORD_BoxRecord) + bval_size;
      *data = box = GNUNET_malloc (*data_size);
      box->protocol = htons (protocol);
      box->service = htons (service);
      box->record_type = htonl (record_type);
      memcpy (&box[1],
              bval,
              bval_size);
      GNUNET_free (bval);
      return GNUNET_OK;
    }
  default:
    return GNUNET_SYSERR;
  }
}
Example #5
0
/**
 * Main request handler.
 */
static int
access_handler_callback (void *cls, struct MHD_Connection *connection,
                         const char *url, const char *method,
                         const char *version, const char *upload_data,
                         size_t * upload_data_size, void **con_cls)
{
  static int dummy;
  static const struct Entry map[] = {
    { "prefix", "prefix" },
    { "name", "name" },
    { "suffix", "suffix" },
    { "street", "street" },
    { "city", "city" },
    { "phone", "phone" },
    { "fax", "fax" },
    { "email", "email"},
    { "homepage", "homepage" },
    { "orga", "orga"},
    { "departmenti18n", "departmentde"},
    { "departmenten", "departmenten"},
    { "subdepartmenti18n", "subdepartmentde"},
    { "subdepartmenten", "subdepartmenten"},
    { "jobtitlei18n", "jobtitlegerman"},
    { "jobtitleen", "jobtitleenglish"},
    { "subdepartmenten", "subdepartmenten"},
    { NULL, NULL }
  };

  if (0 != strcmp (method, MHD_HTTP_METHOD_GET))
  {
    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                _("Refusing `%s' request to HTTP server\n"),
                method);
    return MHD_NO;
  }
  if (NULL == *con_cls)
  {
    (*con_cls) = &dummy;
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Sending 100 CONTINUE reply\n");
    return MHD_YES;             /* send 100 continue */
  }
  if (0 == strcasecmp (url, "/"))
    return MHD_queue_response (connection,
                               MHD_HTTP_OK,
                               main_response);
  if (0 == strcasecmp (url, "/submit.pdf"))
  {
    unsigned int i;
    char *p;
    char *tmp;
    char *deffile;
    struct GNUNET_CRYPTO_EcdsaPublicKey pub;
    size_t slen;
    FILE *f;
    struct stat st;
    struct MHD_Response *response;
    int fd;
    int ret;

    const char *gpg_fp = MHD_lookup_connection_value (connection,
                                                      MHD_GET_ARGUMENT_KIND,
                                                      "gpgfingerprint");
    const char *gns_nick = MHD_lookup_connection_value (connection,
                                                        MHD_GET_ARGUMENT_KIND,
                                                        "gnsnick");
    const char *gnskey = MHD_lookup_connection_value (connection,
                                                      MHD_GET_ARGUMENT_KIND,
                                                      "gnskey");
    if ( (NULL == gnskey) ||
         (GNUNET_OK !=
          GNUNET_CRYPTO_ecdsa_public_key_from_string (gnskey,
                                                      strlen (gnskey),
                                                      &pub)))
    {
      return MHD_queue_response (connection,
                                 MHD_HTTP_OK,
                                 invalid_gnskey_response);
    }
    tmp = GNUNET_DISK_mkdtemp (gnskey);
    if (NULL == tmp)
    {
      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "mktemp", gnskey);
      return MHD_NO;
    }
    GNUNET_asprintf (&deffile,
                     "%s%s%s",
                     tmp, DIR_SEPARATOR_STR, "def.tex");
    f = FOPEN (deffile, "w");
    if (NULL == f)
    {
      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", deffile);
      GNUNET_free (deffile);
      GNUNET_DISK_directory_remove (tmp);
      GNUNET_free (tmp);
      return MHD_NO;
    }
    for (i=0; NULL != map[i].formname; i++)
    {
      const char *val =  MHD_lookup_connection_value (connection,
                                                      MHD_GET_ARGUMENT_KIND,
                                                      map[i].formname);
      if (NULL != val)
        FPRINTF (f,
                 "\\def\\%s{%s}\n",
                 map[i].texname, val);
      else
        FPRINTF (f,
                 "\\def\\%s{}\n",
                 map[i].texname);
    }
    if (NULL != gpg_fp)
    {
      char *gpg1;
      char *gpg2;

      slen = strlen (gpg_fp);
      gpg1 = GNUNET_strndup (gpg_fp, slen / 2);
      gpg2 = GNUNET_strdup (&gpg_fp[slen / 2]);
      FPRINTF (f,
               "\\def\\gpglineone{%s}\n\\def\\gpglinetwo{%s}\n",
               gpg1, gpg2);
      GNUNET_free (gpg2);
      GNUNET_free (gpg1);
    }
    FPRINTF (f,
             "\\def\\gns{%s/%s}\n",
             gnskey,
             (NULL == gns_nick) ? "" : gns_nick);
    FCLOSE (f);
    GNUNET_asprintf (&p,
                     "cd %s; cp %s gns-bcd.tex | pdflatex --enable-write18 gns-bcd.tex > /dev/null 2> /dev/null",
                     tmp,
                     resfile);
    GNUNET_free (deffile);
    ret = system (p);
    if (WIFSIGNALED (ret) || (0 != WEXITSTATUS(ret)))
      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
                                "system",
                                p);
    GNUNET_asprintf (&deffile,
                     "%s%s%s",
                     tmp, DIR_SEPARATOR_STR, "gns-bcd.pdf");
    fd = OPEN (deffile, O_RDONLY);
    if (-1 == fd)
    {
      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
                                "open",
                                deffile);
      GNUNET_free (deffile);
      GNUNET_free (p);
      GNUNET_DISK_directory_remove (tmp);
      GNUNET_free (tmp);
      return MHD_NO;
    }
    GNUNET_break (0 == STAT (deffile, &st));
    if (NULL == (response = MHD_create_response_from_fd ((size_t) st.st_size, fd)))
    {
      GNUNET_break (0);
      GNUNET_break (0 == CLOSE (fd));
      GNUNET_free (deffile);
      GNUNET_free (p);
      GNUNET_DISK_directory_remove (tmp);
      GNUNET_free (tmp);
      return MHD_NO;
    }
    (void) MHD_add_response_header (response,
                                    MHD_HTTP_HEADER_CONTENT_TYPE,
                                    "application/pdf");
    ret = MHD_queue_response (connection,
                              MHD_HTTP_OK,
                              response);
    MHD_destroy_response (response);
    GNUNET_free (deffile);
    GNUNET_free (p);
    GNUNET_DISK_directory_remove (tmp);
    GNUNET_free (tmp);
    return ret;
  }
  return MHD_queue_response (connection,
                             MHD_HTTP_NOT_FOUND,
                             not_found_response);
}
Example #6
0
/**
 * Convert human-readable version of a 'value' of a record to the binary
 * representation.
 *
 * @param cls closure, unused
 * @param type type of the record
 * @param s human-readable string
 * @param data set to value in binary encoding (will be allocated)
 * @param data_size set to number of bytes in @a data
 * @return #GNUNET_OK on success
 */
static int
gns_string_to_value (void *cls,
                     uint32_t type,
                     const char *s,
                     void **data,
                     size_t *data_size)
{
  struct GNUNET_CRYPTO_EcdsaPublicKey pkey;

  if (NULL == s)
    return GNUNET_SYSERR;
  switch (type)
  {

    case GNUNET_GNSRECORD_TYPE_PKEY:
      if (GNUNET_OK !=
          GNUNET_CRYPTO_ecdsa_public_key_from_string (s, strlen (s), &pkey))
      {
        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                    _("Unable to parse PKEY record `%s'\n"),
                    s);
        return GNUNET_SYSERR;
      }
      *data = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey);
      GNUNET_memcpy (*data, &pkey, sizeof (pkey));
      *data_size = sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
      return GNUNET_OK;

    case GNUNET_GNSRECORD_TYPE_NICK:
      *data = GNUNET_strdup (s);
      *data_size = strlen (s);
      return GNUNET_OK;
    case GNUNET_GNSRECORD_TYPE_LEHO:
      *data = GNUNET_strdup (s);
      *data_size = strlen (s);
      return GNUNET_OK;
    case GNUNET_GNSRECORD_TYPE_GNS2DNS:
      {
        char nsbuf[514];
        char *cpy;
        char *at;
        size_t off;

        cpy = GNUNET_strdup (s);
        at = strchr (cpy, '@');
        if (NULL == at)
        {
          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                      _("Unable to parse GNS2DNS record `%s'\n"),
                      s);
          GNUNET_free (cpy);
          return GNUNET_SYSERR;
        }
        *at = '\0';
        at++;

        off = 0;
        if ( (GNUNET_OK !=
              GNUNET_DNSPARSER_builder_add_name (nsbuf,
                                                 sizeof (nsbuf),
                                                 &off,
                                                 cpy)) ||
             (GNUNET_OK !=
              GNUNET_DNSPARSER_builder_add_name (nsbuf,
                                                 sizeof (nsbuf),
                                                 &off,
                                                 at)) )
        {
          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                      _("Failed to serialize GNS2DNS record with value `%s'\n"),
                      s);
          GNUNET_free (cpy);
          return GNUNET_SYSERR;
        }
        GNUNET_free (cpy);
        *data_size = off;
        *data = GNUNET_malloc (off);
        GNUNET_memcpy (*data, nsbuf, off);
        return GNUNET_OK;
      }
    case GNUNET_GNSRECORD_TYPE_VPN:
      {
        struct GNUNET_TUN_GnsVpnRecord *vpn;
        char s_peer[103 + 1];
        char s_serv[253 + 1];
        unsigned int proto;

        if (3 != SSCANF (s,
                         "%u %103s %253s",
                         &proto, s_peer, s_serv))
        {
          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                      _("Unable to parse VPN record string `%s'\n"),
                      s);
          return GNUNET_SYSERR;
        }
        *data_size = sizeof (struct GNUNET_TUN_GnsVpnRecord) + strlen (s_serv) + 1;
        *data = vpn = GNUNET_malloc (*data_size);
        if (GNUNET_OK != GNUNET_CRYPTO_eddsa_public_key_from_string ((char*) s_peer,
                                                                     strlen (s_peer),
                                                                     &vpn->peer.public_key))
        {
          GNUNET_free (vpn);
          *data_size = 0;
          return GNUNET_SYSERR;
        }
        vpn->proto = htons ((uint16_t) proto);
        strcpy ((char*)&vpn[1], s_serv);
        return GNUNET_OK;
      }
    case GNUNET_GNSRECORD_TYPE_BOX:
      {
        struct GNUNET_GNSRECORD_BoxRecord *box;
        size_t rest;
        unsigned int protocol;
        unsigned int service;
        unsigned int record_type;
        void *bval;
        size_t bval_size;

        if (3 != SSCANF (s,
                         "%u %u %u ",
                         &protocol,
                         &service,
                         &record_type))
        {
          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                      _("Unable to parse BOX record string `%s'\n"),
                      s);
          return GNUNET_SYSERR;
        }
        rest = snprintf (NULL, 0,
                         "%u %u %u ",
                         protocol,
                         service,
                         record_type);
        if (GNUNET_OK !=
            GNUNET_GNSRECORD_string_to_value (record_type,
                                              &s[rest],
                                              &bval,
                                              &bval_size))
          return GNUNET_SYSERR;
        *data_size = sizeof (struct GNUNET_GNSRECORD_BoxRecord) + bval_size;
        *data = box = GNUNET_malloc (*data_size);
        box->protocol = htons (protocol);
        box->service = htons (service);
        box->record_type = htonl (record_type);
        GNUNET_memcpy (&box[1],
                       bval,
                       bval_size);
        GNUNET_free (bval);
        return GNUNET_OK;
      }
    case GNUNET_GNSRECORD_TYPE_REVERSE:
      {
        struct GNUNET_GNSRECORD_ReverseRecord *rev;
        char known_by[253 + 1];
        struct GNUNET_TIME_Absolute expiration;

        /* TODO: From crypto_ecc.c
         * Why is this not a constant???
         */
        size_t enclen = (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)) * 8;
        if (enclen % 5 > 0)
          enclen += 5 - enclen % 5;
        enclen /= 5; /* 260/5 = 52 */
        char pkey_str[enclen + 1];

        if (3 != SSCANF (s,
                         "%253s %52s %"SCNu64,
                         known_by,
                         pkey_str,
                         &expiration.abs_value_us))
        {
          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                      _("Unable to parse REVERSE record string `%s'\n"),
                      s);
          return GNUNET_SYSERR;
        }
        *data_size = sizeof (struct GNUNET_GNSRECORD_ReverseRecord) + strlen (known_by) + 1;
        *data = rev = GNUNET_malloc (*data_size);
        GNUNET_CRYPTO_ecdsa_public_key_from_string (pkey_str,
                                                    strlen (pkey_str),
                                                    &rev->pkey);
        rev->expiration = expiration;
        GNUNET_memcpy (&rev[1],
                       known_by,
                       strlen (known_by));
        return GNUNET_OK;
      }
    default:
      return GNUNET_SYSERR;
  }
}