/*
This file is part of GNUnet.
Copyright (C) 2011-2013 GNUnet e.V.
GNUnet is free software: you can redistribute it and/or modify it
under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License,
or (at your option) any later version.
GNUnet is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
SPDX-License-Identifier: AGPL3.0-or-later
*/
/**
* @file abd/gnunet-service-abd.c
* @brief GNUnet Credential Service (main service)
* @author Martin Schanzenbach
*/
#include "platform.h"
#include "gnunet_util_lib.h"
#include "abd.h"
#include "abd_serialization.h"
#include "gnunet_abd_service.h"
#include "gnunet_protocols.h"
#include "gnunet_signatures.h"
#include "gnunet_statistics_service.h"
#include
#include
#include
#include
#include
#define GNUNET_ABD_MAX_LENGTH 255
struct VerifyRequestHandle;
struct DelegationSetQueueEntry;
struct DelegationChainEntry
{
/**
* DLL
*/
struct DelegationChainEntry *next;
/**
* DLL
*/
struct DelegationChainEntry *prev;
/**
* The issuer
*/
struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key;
/**
* The subject
*/
struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
/**
* The issued attribute
*/
char *issuer_attribute;
/**
* The delegated attribute
*/
char *subject_attribute;
};
/**
* DLL for record
*/
struct DelegateRecordEntry
{
/**
* DLL
*/
struct DelegateRecordEntry *next;
/**
* DLL
*/
struct DelegateRecordEntry *prev;
/**
* Number of references in delegation chains
*/
uint32_t refcount;
/**
* Payload
*/
struct GNUNET_ABD_Delegate *delegate;
};
/**
* DLL used for delegations
* Used for OR delegations
*/
struct DelegationQueueEntry
{
/**
* DLL
*/
struct DelegationQueueEntry *next;
/**
* DLL
*/
struct DelegationQueueEntry *prev;
/**
* Parent set
*/
struct DelegationSetQueueEntry *parent_set;
/**
* Required solutions
*/
uint32_t required_solutions;
};
/**
* DLL for delegation sets
* Used for AND delegation set
*/
struct DelegationSetQueueEntry
{
/**
* DLL
*/
struct DelegationSetQueueEntry *next;
/**
* DLL
*/
struct DelegationSetQueueEntry *prev;
/**
* GNS handle
*/
struct GNUNET_GNS_LookupRequest *lookup_request;
/**
* Verify handle
*/
struct VerifyRequestHandle *handle;
/**
* Parent attribute delegation
*/
struct DelegationQueueEntry *parent;
/**
* Issuer key
*/
struct GNUNET_CRYPTO_EcdsaPublicKey *issuer_key;
/**
* Queue entries of this set
*/
struct DelegationQueueEntry *queue_entries_head;
/**
* Queue entries of this set
*/
struct DelegationQueueEntry *queue_entries_tail;
/**
* Parent QueueEntry
*/
struct DelegationQueueEntry *parent_queue_entry;
/**
* Issuer attribute delegated to
*/
char *issuer_attribute;
/**
* The current attribute to look up
*/
char *lookup_attribute;
/**
* Trailing attribute context
*/
char *attr_trailer;
/**
* Still to resolve delegation as string
*/
char *unresolved_attribute_delegation;
/**
* The delegation chain entry
*/
struct DelegationChainEntry *delegation_chain_entry;
/**
* True if added by backward resolution
*/
bool from_bw;
};
/**
* Handle to a lookup operation from api
*/
struct VerifyRequestHandle
{
/**
* True if created by a collect request.
*/
bool is_collect;
/**
* We keep these in a DLL.
*/
struct VerifyRequestHandle *next;
/**
* We keep these in a DLL.
*/
struct VerifyRequestHandle *prev;
/**
* Handle to the requesting client
*/
struct GNUNET_SERVICE_Client *client;
/**
* Size of delegation tree
*/
uint32_t delegation_chain_size;
/**
* Children of this attribute
*/
struct DelegationChainEntry *delegation_chain_head;
/**
* Children of this attribute
*/
struct DelegationChainEntry *delegation_chain_tail;
/**
* List for bidirectional matching
*/
struct DelegationSetQueueEntry *dsq_head;
/**
* List for bidirectional matching
*/
struct DelegationSetQueueEntry *dsq_tail;
/**
* Issuer public key
*/
struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key;
/**
* Issuer attribute
*/
char *issuer_attribute;
/**
* Subject public key
*/
struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
/**
* Delegate DLL
*/
struct DelegateRecordEntry *del_chain_head;
/**
* Delegate DLL
*/
struct DelegateRecordEntry *del_chain_tail;
/**
* Delegate DLL size
*/
uint32_t del_chain_size;
/**
* Current Delegation Pointer
*/
struct DelegationQueueEntry *current_delegation;
/**
* request id
*/
uint32_t request_id;
/**
* Pending lookups
*/
uint64_t pending_lookups;
/**
* Direction of the resolution algo
*/
enum GNUNET_ABD_AlgoDirectionFlags resolution_algo;
/**
* Delegate iterator for lookup
*/
struct GNUNET_NAMESTORE_QueueEntry *dele_qe;
};
/**
* Head of the DLL.
*/
static struct VerifyRequestHandle *vrh_head = NULL;
/**
* Tail of the DLL.
*/
static struct VerifyRequestHandle *vrh_tail = NULL;
/**
* Handle to the statistics service
*/
static struct GNUNET_STATISTICS_Handle *statistics;
/**
* Handle to GNS service.
*/
static struct GNUNET_GNS_Handle *gns;
/**
* Handle to namestore service
*/
static struct GNUNET_NAMESTORE_Handle *namestore;
static void
print_deleset (struct DelegationSetQueueEntry *dsentry, char *text)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"%s %s.%s <- %s.%s\n",
text,
GNUNET_CRYPTO_ecdsa_public_key_to_string (
&dsentry->delegation_chain_entry->issuer_key),
dsentry->delegation_chain_entry->issuer_attribute,
GNUNET_CRYPTO_ecdsa_public_key_to_string (
&dsentry->delegation_chain_entry->subject_key),
dsentry->delegation_chain_entry->subject_attribute);
}
static void
cleanup_dsq_entry (struct DelegationSetQueueEntry *ds_entry)
{
GNUNET_free (ds_entry->issuer_key);
GNUNET_free (ds_entry->issuer_attribute);
GNUNET_free (ds_entry->attr_trailer);
// those fields are only set/used in bw search
if (ds_entry->from_bw)
{
GNUNET_free (ds_entry->lookup_attribute);
GNUNET_free (ds_entry->unresolved_attribute_delegation);
}
if (NULL != ds_entry->lookup_request)
{
GNUNET_GNS_lookup_cancel (ds_entry->lookup_request);
ds_entry->lookup_request = NULL;
}
if (NULL != ds_entry->delegation_chain_entry)
{
GNUNET_free (
ds_entry->delegation_chain_entry->subject_attribute);
GNUNET_free (ds_entry->delegation_chain_entry->issuer_attribute);
GNUNET_free (ds_entry->delegation_chain_entry);
}
// Free DQ entries
for (struct DelegationQueueEntry *dq_entry = ds_entry->queue_entries_head;
NULL != ds_entry->queue_entries_head;
dq_entry = ds_entry->queue_entries_head)
{
GNUNET_CONTAINER_DLL_remove (ds_entry->queue_entries_head,
ds_entry->queue_entries_tail,
dq_entry);
GNUNET_free (dq_entry);
}
GNUNET_free (ds_entry);
}
static void
cleanup_handle (struct VerifyRequestHandle *vrh)
{
struct DelegateRecordEntry *del_entry;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up...\n");
if (NULL != vrh->dsq_head)
{
for (struct DelegationSetQueueEntry *ds_entry = vrh->dsq_head; NULL !=
vrh->dsq_head;
ds_entry = vrh->dsq_head)
{
GNUNET_CONTAINER_DLL_remove (vrh->dsq_head, vrh->dsq_tail, ds_entry);
cleanup_dsq_entry (ds_entry);
}
}
if (NULL != vrh->del_chain_head)
{
for (del_entry = vrh->del_chain_head; NULL != vrh->del_chain_head;
del_entry = vrh->del_chain_head)
{
GNUNET_CONTAINER_DLL_remove (vrh->del_chain_head,
vrh->del_chain_tail,
del_entry);
GNUNET_free (del_entry->delegate);
GNUNET_free (del_entry);
}
}
GNUNET_free (vrh->issuer_attribute);
GNUNET_free (vrh);
}
static void
shutdown_task (void *cls)
{
struct VerifyRequestHandle *vrh;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutting down!\n");
while (NULL != (vrh = vrh_head))
{
// ABD_resolver_lookup_cancel (clh->lookup);
GNUNET_CONTAINER_DLL_remove (vrh_head, vrh_tail, vrh);
cleanup_handle (vrh);
}
if (NULL != gns)
{
GNUNET_GNS_disconnect (gns);
gns = NULL;
}
if (NULL != namestore)
{
GNUNET_NAMESTORE_disconnect (namestore);
namestore = NULL;
}
if (NULL != statistics)
{
GNUNET_STATISTICS_destroy (statistics, GNUNET_NO);
statistics = NULL;
}
}
static void
send_intermediate_response (struct VerifyRequestHandle *vrh, struct
DelegationChainEntry *ch_entry, bool is_bw)
{
struct DelegationChainIntermediateMessage *rmsg;
struct GNUNET_MQ_Envelope *env;
struct GNUNET_ABD_Delegation *dd;
size_t size;
// Don't report immediate results during collect
if (vrh->is_collect)
return;
dd = GNUNET_new (struct GNUNET_ABD_Delegation);
dd->issuer_key = ch_entry->issuer_key;
dd->subject_key = ch_entry->subject_key;
dd->issuer_attribute = ch_entry->issuer_attribute;
dd->issuer_attribute_len = strlen (ch_entry->issuer_attribute) + 1;
dd->subject_attribute_len = 0;
dd->subject_attribute = NULL;
if (NULL != ch_entry->subject_attribute)
{
dd->subject_attribute = ch_entry->subject_attribute;
dd->subject_attribute_len = strlen (ch_entry->subject_attribute) + 1;
}
size = GNUNET_ABD_delegation_chain_get_size (1,
dd,
0,
NULL);
env = GNUNET_MQ_msg_extra (rmsg,
size,
GNUNET_MESSAGE_TYPE_ABD_INTERMEDIATE_RESULT);
// Assign id so that client can find associated request
rmsg->id = vrh->request_id;
rmsg->is_bw = htons (is_bw);
rmsg->size = htonl (size);
GNUNET_assert (
-1 != GNUNET_ABD_delegation_chain_serialize (1,
dd,
0,
NULL,
size,
(char *) &rmsg[1]));
GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (vrh->client), env);
}
static void
send_lookup_response (struct VerifyRequestHandle *vrh)
{
struct GNUNET_MQ_Envelope *env;
struct DelegationChainResultMessage *rmsg;
struct DelegationChainEntry *dce;
struct GNUNET_ABD_Delegation dd[vrh->delegation_chain_size];
struct GNUNET_ABD_Delegate dele[vrh->del_chain_size];
struct DelegateRecordEntry *del;
struct DelegateRecordEntry *tmp;
size_t size;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending response\n");
dce = vrh->delegation_chain_head;
for (uint32_t i = 0; i < vrh->delegation_chain_size; i++)
{
dd[i].issuer_key = dce->issuer_key;
dd[i].subject_key = dce->subject_key;
dd[i].issuer_attribute = dce->issuer_attribute;
dd[i].issuer_attribute_len = strlen (dce->issuer_attribute) + 1;
dd[i].subject_attribute_len = 0;
dd[i].subject_attribute = NULL;
if (NULL != dce->subject_attribute)
{
dd[i].subject_attribute = dce->subject_attribute;
dd[i].subject_attribute_len = strlen (dce->subject_attribute) + 1;
}
dce = dce->next;
}
// Remove all not needed credentials
for (del = vrh->del_chain_head; NULL != del;)
{
if (del->refcount > 0)
{
del = del->next;
continue;
}
tmp = del;
del = del->next;
GNUNET_CONTAINER_DLL_remove (vrh->del_chain_head, vrh->del_chain_tail, tmp);
GNUNET_free (tmp->delegate);
GNUNET_free (tmp);
vrh->del_chain_size--;
}
// Get serialized record data
// Append at the end of rmsg
del = vrh->del_chain_head;
for (uint32_t i = 0; i < vrh->del_chain_size; i++)
{
dele[i].issuer_key = del->delegate->issuer_key;
dele[i].subject_key = del->delegate->subject_key;
dele[i].issuer_attribute_len = strlen (del->delegate->issuer_attribute) + 1;
dele[i].issuer_attribute = del->delegate->issuer_attribute;
dele[i].subject_attribute_len = del->delegate->subject_attribute_len;
dele[i].subject_attribute = del->delegate->subject_attribute;
dele[i].expiration = del->delegate->expiration;
dele[i].signature = del->delegate->signature;
del = del->next;
}
size =
GNUNET_ABD_delegation_chain_get_size (vrh->delegation_chain_size,
dd,
vrh->del_chain_size,
dele);
env = GNUNET_MQ_msg_extra (rmsg,
size,
GNUNET_MESSAGE_TYPE_ABD_VERIFY_RESULT);
// Assign id so that client can find associated request
rmsg->id = vrh->request_id;
rmsg->d_count = htonl (vrh->delegation_chain_size);
rmsg->c_count = htonl (vrh->del_chain_size);
if (0 < vrh->del_chain_size)
rmsg->del_found = htonl (GNUNET_YES);
else
rmsg->del_found = htonl (GNUNET_NO);
GNUNET_assert (
-1 !=
GNUNET_ABD_delegation_chain_serialize (vrh->delegation_chain_size,
dd,
vrh->del_chain_size,
dele,
size,
(char *) &rmsg[1]));
GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (vrh->client), env);
GNUNET_CONTAINER_DLL_remove (vrh_head, vrh_tail, vrh);
cleanup_handle (vrh);
GNUNET_STATISTICS_update (statistics,
"Completed verifications",
1,
GNUNET_NO);
}
static char *
partial_match (char *tmp_trail,
char *tmp_subattr,
char *parent_trail,
char *issuer_attribute)
{
char *saveptr1, *saveptr2;
char *trail_token;
char *sub_token;
char *attr_trailer;
// tok both, parent->attr_trailer and del->sub_attr to see how far they match,
// take rest of parent trailer (only when del->sub_attr token is null), and
// create new/actual trailer with del->iss_attr
trail_token = strtok_r (tmp_trail, ".", &saveptr1);
sub_token = strtok_r (tmp_subattr, ".", &saveptr2);
while (NULL != trail_token && NULL != sub_token)
{
if (0 == strcmp (trail_token, sub_token))
{
// good, matches, remove
}
else
{
// not relevant for solving the chain, end for iteration here
return NULL;
}
trail_token = strtok_r (NULL, ".", &saveptr1);
sub_token = strtok_r (NULL, ".", &saveptr2);
}
// skip this entry and go to next for if:
// 1. at some point the attr of the trailer and the subject dont match
// 2. the trailer is NULL, but the subject has more attributes
// Reason: This will lead to "startzone.attribute" but we're looking for a solution
// for "<- startzone"
if (NULL == trail_token)
{
return NULL;
}
// do not have to check sub_token == NULL, if both would be NULL
// at the same time, the complete match part above should have triggered already
// otherwise, above while only ends when sub_token == NULL
GNUNET_asprintf (&attr_trailer, "%s", trail_token);
trail_token = strtok_r (NULL, ".", &saveptr1);
while (NULL != trail_token)
{
GNUNET_asprintf (&attr_trailer, "%s.%s", parent_trail, trail_token);
trail_token = strtok_r (NULL, ".", &saveptr1);
}
GNUNET_asprintf (&attr_trailer, "%s.%s", issuer_attribute, attr_trailer);
return attr_trailer;
}
static int
handle_bidirectional_match (struct DelegationSetQueueEntry *actual_entry,
struct DelegationSetQueueEntry *match_entry,
struct VerifyRequestHandle *vrh)
{
struct DelegationSetQueueEntry *old_fw_parent;
struct DelegationSetQueueEntry *fw_entry = actual_entry;
struct DelegationSetQueueEntry *last_entry = match_entry;
// parent fixing, combine backward and forward chain parts
while (NULL != fw_entry->parent_queue_entry)
{
old_fw_parent = fw_entry->parent_queue_entry->parent_set;
// set parent
fw_entry->parent_queue_entry->parent_set = last_entry;
last_entry = fw_entry;
fw_entry = old_fw_parent;
}
// set last entry of chain as actual_entry
// actual_entry = last_entry;
// set refcount, loop all delegations
for (struct DelegateRecordEntry *del_entry = vrh->del_chain_head;
del_entry != NULL;
del_entry = del_entry->next)
{
if (0 != memcmp (&last_entry->delegation_chain_entry->subject_key,
&del_entry->delegate->issuer_key,
sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
continue;
if (0 != strcmp (last_entry->delegation_chain_entry->subject_attribute,
del_entry->delegate->issuer_attribute))
continue;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found delegate.\n");
// increase refcount of the start delegation
del_entry->refcount++;
}
// backtrack
for (struct DelegationSetQueueEntry *tmp_set = last_entry;
NULL != tmp_set->parent_queue_entry;
tmp_set = tmp_set->parent_queue_entry->parent_set)
{
tmp_set->parent_queue_entry->required_solutions--;
// add new found entry to vrh
vrh->delegation_chain_size++;
GNUNET_CONTAINER_DLL_insert (vrh->delegation_chain_head,
vrh->delegation_chain_tail,
tmp_set->delegation_chain_entry);
// if one node on the path still needs solutions, this current
// patch cannot fullfil the conditions and therefore stops here
// however, it is in the vrh and can be used by the other paths
// related to this path/collection/verification
if (0 < tmp_set->parent_queue_entry->required_solutions)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Chain requires more solutions, waiting...\n");
return GNUNET_NO;
}
}
return GNUNET_YES;
}
static void
forward_resolution (void *cls,
uint32_t rd_count,
const struct GNUNET_GNSRECORD_Data *rd)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received %d entries.\n", rd_count);
struct VerifyRequestHandle *vrh;
struct DelegationSetQueueEntry *current_set;
struct DelegationSetQueueEntry *ds_entry;
struct DelegationQueueEntry *dq_entry;
current_set = cls;
// set handle to NULL (as el = NULL)
current_set->lookup_request = NULL;
vrh = current_set->handle;
vrh->pending_lookups--;
// Loop record entries
for (uint32_t i = 0; i < rd_count; i++)
{
if (GNUNET_GNSRECORD_TYPE_DELEGATE != rd[i].record_type)
continue;
// Start deserialize into Delegate
struct GNUNET_ABD_Delegate *del;
del = GNUNET_ABD_delegate_deserialize (rd[i].data, rd[i].data_size);
// Start: Create DQ Entry
dq_entry = GNUNET_new (struct DelegationQueueEntry);
// AND delegations are not possible, only 1 solution
dq_entry->required_solutions = 1;
dq_entry->parent_set = current_set;
// Insert it into the current set
GNUNET_CONTAINER_DLL_insert (current_set->queue_entries_head,
current_set->queue_entries_tail,
dq_entry);
// Start: Create DS Entry
ds_entry = GNUNET_new (struct DelegationSetQueueEntry);
GNUNET_CONTAINER_DLL_insert (vrh->dsq_head, vrh->dsq_tail, ds_entry);
ds_entry->from_bw = false;
// (1) A.a <- A.b.c
// (2) A.b <- D.d
// (3) D.d <- E
// (4) E.c <- F.c
// (5) F.c <- G
// Possibilities:
// 1. complete match: trailer = 0, validate
// 2. partial match: replace
// 3. new solution: replace, add trailer
// At resolution chain start trailer of parent is NULL
if (NULL == current_set->attr_trailer)
{
// for (5) F.c <- G, remember .c when going upwards
ds_entry->attr_trailer = GNUNET_strdup (del->issuer_attribute);
}
else
{
if (0 == del->subject_attribute_len)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found: New solution\n");
// new solution
// create new trailer del->issuer_attribute, ds_entry->attr_trailer
GNUNET_asprintf (&ds_entry->attr_trailer,
"%s.%s",
del->issuer_attribute,
current_set->attr_trailer);
}
else if (0 == strcmp (del->subject_attribute, current_set->attr_trailer))
{
// complete match
// new trailer == issuer attribute (e.g. (5) to (4))
ds_entry->attr_trailer = GNUNET_strdup (del->issuer_attribute);
}
else
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found: Partial match\n");
// partial match
char *trail = partial_match (GNUNET_strdup (current_set->attr_trailer),
GNUNET_strdup (del->subject_attribute),
current_set->attr_trailer,
GNUNET_strdup (del->issuer_attribute));
// if null: skip this record entry (reasons: mismatch or overmatch, both not relevant)
if (NULL == trail)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Entry not relevant, discarding: %s.%s <- %s.%s\n",
GNUNET_CRYPTO_ecdsa_public_key_to_string (
&del->issuer_key),
del->issuer_attribute,
GNUNET_CRYPTO_ecdsa_public_key_to_string (
&del->subject_key),
del->subject_attribute);
continue;
}
else
ds_entry->attr_trailer = trail;
}
}
// Start: Credential Chain Entry
// issuer key is subject key, who needs to be contacted to resolve this (forward, therefore subject)
ds_entry->issuer_key = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey);
GNUNET_memcpy (ds_entry->issuer_key,
&del->subject_key,
sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
ds_entry->delegation_chain_entry = GNUNET_new (struct DelegationChainEntry);
ds_entry->delegation_chain_entry->subject_key = del->subject_key;
if (0 < del->subject_attribute_len)
ds_entry->delegation_chain_entry->subject_attribute =
GNUNET_strdup (del->subject_attribute);
ds_entry->delegation_chain_entry->issuer_key = del->issuer_key;
ds_entry->delegation_chain_entry->issuer_attribute =
GNUNET_strdup (del->issuer_attribute);
// Found new entry, repoting intermediate result
send_intermediate_response (vrh, ds_entry->delegation_chain_entry, false);
// current delegation as parent
ds_entry->parent_queue_entry = dq_entry;
// Check for solution
// if: issuer key we looking for
if (0 == memcmp (&del->issuer_key,
&vrh->issuer_key,
sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
{
// if: issuer attr we looking for
if (0 == strcmp (del->issuer_attribute, vrh->issuer_attribute))
{
// if: complete match, meaning new trailer == issuer attr
if (0 == strcmp (vrh->issuer_attribute, ds_entry->attr_trailer))
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found: Solution\n");
// Add found solution into delegation_chain
struct DelegationSetQueueEntry *tmp_set;
for (tmp_set = ds_entry; NULL != tmp_set->parent_queue_entry;
tmp_set = tmp_set->parent_queue_entry->parent_set)
{
if (NULL != tmp_set->delegation_chain_entry)
{
vrh->delegation_chain_size++;
GNUNET_CONTAINER_DLL_insert (vrh->delegation_chain_head,
vrh->delegation_chain_tail,
tmp_set->delegation_chain_entry);
}
}
// Increase refcount for this delegate
for (struct DelegateRecordEntry *del_entry = vrh->del_chain_head;
del_entry != NULL;
del_entry = del_entry->next)
{
if (0 == memcmp (&del_entry->delegate->issuer_key,
&vrh->delegation_chain_head->subject_key,
sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
{
if (0 == strcmp (del_entry->delegate->issuer_attribute,
vrh->delegation_chain_head->subject_attribute))
{
del_entry->refcount++;
}
}
}
send_lookup_response (vrh);
return;
}
}
}
// Check for bidirectional crossmatch
for (struct DelegationSetQueueEntry *del_entry = vrh->dsq_head;
del_entry != NULL;
del_entry = del_entry->next)
{
// only check entries not by backward algorithm
if (del_entry->from_bw)
{
// key of list entry matches actual key
if (0 == memcmp (&del_entry->delegation_chain_entry->subject_key,
&ds_entry->delegation_chain_entry->issuer_key,
sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
{
// compare entry subject attributes to this trailer (iss attr + old trailer)
if (0 == strcmp (del_entry->unresolved_attribute_delegation,
ds_entry->attr_trailer))
{
print_deleset (del_entry, "Forward:");
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Forward: Found match with above!\n");
// one node on the path still needs solutions: return
if (GNUNET_NO ==
handle_bidirectional_match (ds_entry, del_entry, vrh))
return;
send_lookup_response (vrh);
return;
}
}
}
}
// Starting a new GNS lookup
vrh->pending_lookups++;
ds_entry->handle = vrh;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Starting to look up trailer %s in zone %s\n",
ds_entry->attr_trailer,
GNUNET_CRYPTO_ecdsa_public_key_to_string (&del->issuer_key));
ds_entry->lookup_request =
GNUNET_GNS_lookup (gns,
GNUNET_GNS_EMPTY_LABEL_AT,
&del->issuer_key,
GNUNET_GNSRECORD_TYPE_DELEGATE,
GNUNET_GNS_LO_DEFAULT,
&forward_resolution,
ds_entry);
}
if (0 == vrh->pending_lookups)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "We are all out of attributes...\n");
send_lookup_response (vrh);
return;
}
}
static void
backward_resolution (void *cls,
uint32_t rd_count,
const struct GNUNET_GNSRECORD_Data *rd)
{
struct VerifyRequestHandle *vrh;
const struct GNUNET_ABD_DelegationRecord *sets;
struct DelegateRecordEntry *del_pointer;
struct DelegationSetQueueEntry *current_set;
struct DelegationSetQueueEntry *ds_entry;
struct DelegationSetQueueEntry *tmp_set;
struct DelegationQueueEntry *dq_entry;
char *expanded_attr;
char *lookup_attribute;
current_set = cls;
current_set->lookup_request = NULL;
vrh = current_set->handle;
vrh->pending_lookups--;
// Each OR
for (uint32_t i = 0; i < rd_count; i++)
{
if (GNUNET_GNSRECORD_TYPE_ATTRIBUTE != rd[i].record_type)
continue;
sets = rd[i].data;
struct GNUNET_ABD_DelegationSet set[ntohl (sets->set_count)];
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Found new attribute delegation with %d sets. Creating new Job...\n",
ntohl (sets->set_count));
if (GNUNET_OK !=
GNUNET_ABD_delegation_set_deserialize (GNUNET_ntohll (
sets->data_size),
(const char *) &sets[1],
ntohl (sets->set_count),
set))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to deserialize!\n");
continue;
}
dq_entry = GNUNET_new (struct DelegationQueueEntry);
dq_entry->required_solutions = ntohl (sets->set_count);
dq_entry->parent_set = current_set;
GNUNET_CONTAINER_DLL_insert (current_set->queue_entries_head,
current_set->queue_entries_tail,
dq_entry);
// Each AND
for (uint32_t j = 0; j < ntohl (sets->set_count); j++)
{
ds_entry = GNUNET_new (struct DelegationSetQueueEntry);
GNUNET_CONTAINER_DLL_insert (vrh->dsq_head, vrh->dsq_tail, ds_entry);
ds_entry->from_bw = true;
if (NULL != current_set->attr_trailer)
{
if (0 == set[j].subject_attribute_len)
{
GNUNET_asprintf (&expanded_attr, "%s", current_set->attr_trailer);
}
else
{
GNUNET_asprintf (&expanded_attr,
"%s.%s",
set[j].subject_attribute,
current_set->attr_trailer);
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Expanded to %s\n", expanded_attr);
ds_entry->unresolved_attribute_delegation = expanded_attr;
}
else
{
if (0 != set[j].subject_attribute_len)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Not Expanding %s\n",
set[j].subject_attribute);
ds_entry->unresolved_attribute_delegation =
GNUNET_strdup (set[j].subject_attribute);
}
}
// Add a credential chain entry
ds_entry->delegation_chain_entry =
GNUNET_new (struct DelegationChainEntry);
ds_entry->delegation_chain_entry->subject_key = set[j].subject_key;
ds_entry->issuer_key = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey);
GNUNET_memcpy (ds_entry->issuer_key,
&set[j].subject_key,
sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
if (0 < set[j].subject_attribute_len)
ds_entry->delegation_chain_entry->subject_attribute =
GNUNET_strdup (set[j].subject_attribute);
ds_entry->delegation_chain_entry->issuer_key = *current_set->issuer_key;
ds_entry->delegation_chain_entry->issuer_attribute =
GNUNET_strdup (current_set->lookup_attribute);
// Found new entry, repoting intermediate result
send_intermediate_response (vrh, ds_entry->delegation_chain_entry, true);
ds_entry->parent_queue_entry = dq_entry; // current_delegation;
/**
* Check if this delegation already matches one of our credentials
*/
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Checking for cred match\n");
for (del_pointer = vrh->del_chain_head; del_pointer != NULL;
del_pointer = del_pointer->next)
{
// If key and attribute match credential: continue and backtrack
if (0 != memcmp (&set[j].subject_key,
&del_pointer->delegate->issuer_key,
sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
continue;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Checking if %s matches %s\n",
ds_entry->unresolved_attribute_delegation,
del_pointer->delegate->issuer_attribute);
if (0 != strcmp (ds_entry->unresolved_attribute_delegation,
del_pointer->delegate->issuer_attribute))
continue;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found issuer\n");
// increase refcount of the start delegation
del_pointer->refcount++;
// Backtrack
for (tmp_set = ds_entry; NULL != tmp_set->parent_queue_entry;
tmp_set = tmp_set->parent_queue_entry->parent_set)
{
tmp_set->parent_queue_entry->required_solutions--;
if (NULL != tmp_set->delegation_chain_entry)
{
vrh->delegation_chain_size++;
GNUNET_CONTAINER_DLL_insert (vrh->delegation_chain_head,
vrh->delegation_chain_tail,
tmp_set->delegation_chain_entry);
}
if (0 < tmp_set->parent_queue_entry->required_solutions)
break;
}
// if the break above is not called the condition of the for is met
if (NULL == tmp_set->parent_queue_entry)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All solutions found\n");
// Found match
send_lookup_response (vrh);
return;
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Not all solutions found yet.\n");
continue;
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Building new lookup request from %s\n",
ds_entry->unresolved_attribute_delegation);
// Continue with next/new backward resolution
char issuer_attribute_name[strlen (
ds_entry->unresolved_attribute_delegation)
+ 1];
strcpy (issuer_attribute_name, ds_entry->unresolved_attribute_delegation);
char *next_attr = strtok (issuer_attribute_name, ".");
if (NULL == next_attr)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to parse next attribute\n");
continue;
}
GNUNET_asprintf (&lookup_attribute, "%s", next_attr);
GNUNET_asprintf (&ds_entry->lookup_attribute, "%s", next_attr);
if (strlen (next_attr) ==
strlen (ds_entry->unresolved_attribute_delegation))
{
ds_entry->attr_trailer = NULL;
}
else
{
next_attr += strlen (next_attr) + 1;
ds_entry->attr_trailer = GNUNET_strdup (next_attr);
}
// Check for bidirectional crossmatch
for (struct DelegationSetQueueEntry *del_entry = vrh->dsq_head;
del_entry != NULL;
del_entry = del_entry->next)
{
// only check entries added by forward algorithm
if (! del_entry->from_bw)
{
// key of list entry matches actual key
if (0 == memcmp (&del_entry->delegation_chain_entry->issuer_key,
&ds_entry->delegation_chain_entry->subject_key,
sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
{
// compare entry subject attributes to this trailer (iss attr + old trailer)
if (0 == strcmp (del_entry->attr_trailer,
ds_entry->unresolved_attribute_delegation))
{
print_deleset (del_entry, "Backward:");
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Backward: Found match with above!\n");
// if one node on the path still needs solutions: return
if (GNUNET_NO ==
handle_bidirectional_match (del_entry, ds_entry, vrh))
break;
// Send lookup response
send_lookup_response (vrh);
return;
}
}
}
}
// Starting a new GNS lookup
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Looking up %s\n",
ds_entry->lookup_attribute);
if (NULL != ds_entry->attr_trailer)
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"%s still to go...\n",
ds_entry->attr_trailer);
vrh->pending_lookups++;
ds_entry->handle = vrh;
ds_entry->lookup_request =
GNUNET_GNS_lookup (gns,
lookup_attribute,
ds_entry->issuer_key, // issuer_key,
GNUNET_GNSRECORD_TYPE_ATTRIBUTE,
GNUNET_GNS_LO_DEFAULT,
&backward_resolution,
ds_entry);
GNUNET_free (lookup_attribute);
}
}
if (0 == vrh->pending_lookups)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "We are all out of attributes...\n");
send_lookup_response (vrh);
return;
}
}
/**
* Result from GNS lookup.
*
* @param cls the closure (our client lookup handle)
*/
static int
delegation_chain_bw_resolution_start (void *cls)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Start Backward Resolution...\n");
struct VerifyRequestHandle *vrh = cls;
struct DelegationSetQueueEntry *ds_entry;
struct DelegateRecordEntry *del_entry;
if (0 == vrh->del_chain_size)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No delegates found\n");
send_lookup_response (vrh);
return 1;
}
// Pre-check with vrh->dele_chain_.. if match issuer_key
// Backward: check every cred entry if match issuer key
// otherwise: start at issuer and go down till match
// A.a <- ...
// X.x <- C
// Y.y <- C
// if not X.x or Y.y == A.a start at A
for (del_entry = vrh->del_chain_head; del_entry != NULL;
del_entry = del_entry->next)
{
if (0 != memcmp (&del_entry->delegate->issuer_key,
&vrh->issuer_key,
sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
continue;
if (0 !=
strcmp (del_entry->delegate->issuer_attribute, vrh->issuer_attribute))
continue;
del_entry->refcount++;
// Found match prematurely
send_lookup_response (vrh);
return 1;
}
// Check for attributes from the issuer and follow the chain
// till you get the required subject's attributes
char issuer_attribute_name[strlen (vrh->issuer_attribute) + 1];
strcpy (issuer_attribute_name, vrh->issuer_attribute);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Looking up %s\n",
issuer_attribute_name);
ds_entry = GNUNET_new (struct DelegationSetQueueEntry);
GNUNET_CONTAINER_DLL_insert (vrh->dsq_head, vrh->dsq_tail, ds_entry);
ds_entry->from_bw = true;
ds_entry->issuer_key = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey);
GNUNET_memcpy (ds_entry->issuer_key,
&vrh->issuer_key,
sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
ds_entry->issuer_attribute = GNUNET_strdup (vrh->issuer_attribute);
ds_entry->delegation_chain_entry = GNUNET_new (struct DelegationChainEntry);
ds_entry->delegation_chain_entry->issuer_key = vrh->issuer_key;
ds_entry->delegation_chain_entry->issuer_attribute =
GNUNET_strdup (vrh->issuer_attribute);
ds_entry->handle = vrh;
ds_entry->lookup_attribute = GNUNET_strdup (vrh->issuer_attribute);
ds_entry->unresolved_attribute_delegation = NULL;
vrh->pending_lookups = 1;
// Start with backward resolution
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Start Backward Resolution\n");
ds_entry->lookup_request = GNUNET_GNS_lookup (gns,
issuer_attribute_name,
&vrh->issuer_key, // issuer_key,
GNUNET_GNSRECORD_TYPE_ATTRIBUTE,
GNUNET_GNS_LO_DEFAULT,
&backward_resolution,
ds_entry);
return 0;
}
static int
delegation_chain_fw_resolution_start (void *cls)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Start Forward Resolution...\n");
struct VerifyRequestHandle *vrh = cls;
struct DelegationSetQueueEntry *ds_entry;
struct DelegateRecordEntry *del_entry;
// set to 0 and increase on each lookup: for fw multiple lookups (may be) started
vrh->pending_lookups = 0;
if (0 == vrh->del_chain_size)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No delegations found\n");
send_lookup_response (vrh);
return 1;
}
// Pre-check with vrh->dele_chain_.. if match issuer_key
// otherwise FW: start mutliple lookups for each vrh->dele_chain
// A.a <- ...
// X.x <- C
// Y.y <- C
// if not X.x or Y.y == A.a start at X and at Y
for (del_entry = vrh->del_chain_head; del_entry != NULL;
del_entry = del_entry->next)
{
if (0 != memcmp (&del_entry->delegate->issuer_key,
&vrh->issuer_key,
sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
continue;
if (0 !=
strcmp (del_entry->delegate->issuer_attribute, vrh->issuer_attribute))
continue;
del_entry->refcount++;
// Found match prematurely
send_lookup_response (vrh);
return 1;
}
// None match, therefore start for every delegation found a lookup chain
// Return and end collect process on first chain iss <-> sub found
// ds_entry created belongs to the first lookup, vrh still has the
// issuer+attr we look for
for (del_entry = vrh->del_chain_head; del_entry != NULL;
del_entry = del_entry->next)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Looking for %s.%s\n",
GNUNET_CRYPTO_ecdsa_public_key_to_string (
&del_entry->delegate->issuer_key),
del_entry->delegate->issuer_attribute);
ds_entry = GNUNET_new (struct DelegationSetQueueEntry);
GNUNET_CONTAINER_DLL_insert (vrh->dsq_head, vrh->dsq_tail, ds_entry);
ds_entry->from_bw = false;
ds_entry->issuer_key = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey);
GNUNET_memcpy (ds_entry->issuer_key,
&del_entry->delegate->subject_key,
sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
ds_entry->delegation_chain_entry = GNUNET_new (struct DelegationChainEntry);
ds_entry->delegation_chain_entry->subject_key =
del_entry->delegate->subject_key;
ds_entry->delegation_chain_entry->subject_attribute = NULL;
ds_entry->delegation_chain_entry->issuer_key =
del_entry->delegate->issuer_key;
ds_entry->delegation_chain_entry->issuer_attribute =
GNUNET_strdup (del_entry->delegate->issuer_attribute);
ds_entry->attr_trailer =
GNUNET_strdup (del_entry->delegate->issuer_attribute);
ds_entry->handle = vrh;
vrh->pending_lookups++;
// Start with forward resolution
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Start Forward Resolution\n");
ds_entry->lookup_request =
GNUNET_GNS_lookup (gns,
GNUNET_GNS_EMPTY_LABEL_AT,
&del_entry->delegate->issuer_key, // issuer_key,
GNUNET_GNSRECORD_TYPE_DELEGATE,
GNUNET_GNS_LO_DEFAULT,
&forward_resolution,
ds_entry);
}
return 0;
}
static int
check_verify (void *cls, const struct VerifyMessage *v_msg)
{
size_t msg_size;
const char *attr;
msg_size = ntohs (v_msg->header.size);
if (msg_size < sizeof (struct VerifyMessage))
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
if (ntohs (v_msg->issuer_attribute_len) > GNUNET_ABD_MAX_LENGTH)
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
attr = (const char *) &v_msg[1];
if (strlen (attr) > GNUNET_ABD_MAX_LENGTH)
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
return GNUNET_OK;
}
static void
handle_verify (void *cls, const struct VerifyMessage *v_msg)
{
struct VerifyRequestHandle *vrh;
struct GNUNET_SERVICE_Client *client = cls;
struct DelegateRecordEntry *del_entry;
uint32_t delegate_count;
uint32_t delegate_data_size;
char attr[GNUNET_ABD_MAX_LENGTH + 1];
char issuer_attribute[GNUNET_ABD_MAX_LENGTH + 1];
char *attrptr = attr;
char *delegate_data;
const char *utf_in;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received VERIFY message\n");
utf_in = (const char *) &v_msg[1];
GNUNET_STRINGS_utf8_tolower (utf_in, attrptr);
GNUNET_memcpy (issuer_attribute, attr, ntohs (v_msg->issuer_attribute_len));
issuer_attribute[ntohs (v_msg->issuer_attribute_len)] = '\0';
vrh = GNUNET_new (struct VerifyRequestHandle);
vrh->is_collect = false;
GNUNET_CONTAINER_DLL_insert (vrh_head, vrh_tail, vrh);
vrh->client = client;
vrh->request_id = v_msg->id;
vrh->issuer_key = v_msg->issuer_key;
vrh->subject_key = v_msg->subject_key;
vrh->issuer_attribute = GNUNET_strdup (issuer_attribute);
vrh->resolution_algo = ntohs (v_msg->resolution_algo);
vrh->del_chain_head = NULL;
vrh->del_chain_tail = NULL;
vrh->dsq_head = NULL;
vrh->dsq_tail = NULL;
vrh->del_chain_head = NULL;
vrh->del_chain_tail = NULL;
GNUNET_SERVICE_client_continue (vrh->client);
if (0 == strlen (issuer_attribute))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No issuer attribute provided!\n");
send_lookup_response (vrh);
return;
}
// Parse delegates from verifaction message
delegate_count = ntohl (v_msg->d_count);
delegate_data_size = ntohs (v_msg->header.size)
- sizeof (struct VerifyMessage)
- ntohs (v_msg->issuer_attribute_len) - 1;
struct GNUNET_ABD_Delegate delegates[delegate_count];
memset (delegates,
0,
sizeof (struct GNUNET_ABD_Delegate) * delegate_count);
delegate_data = (char *) &v_msg[1] + ntohs (v_msg->issuer_attribute_len) + 1;
if (GNUNET_OK != GNUNET_ABD_delegates_deserialize (delegate_data_size,
delegate_data,
delegate_count,
delegates))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cannot deserialize delegates!\n");
send_lookup_response (vrh);
return;
}
// Prepare vrh delegation chain for later validation
for (uint32_t i = 0; i < delegate_count; i++)
{
del_entry = GNUNET_new (struct DelegateRecordEntry);
del_entry->delegate =
GNUNET_malloc (sizeof (struct GNUNET_ABD_Delegate)
+ delegates[i].issuer_attribute_len + 1);
GNUNET_memcpy (del_entry->delegate,
&delegates[i],
sizeof (struct GNUNET_ABD_Delegate));
GNUNET_memcpy (&del_entry->delegate[1],
delegates[i].issuer_attribute,
delegates[i].issuer_attribute_len);
del_entry->delegate->issuer_attribute_len =
delegates[i].issuer_attribute_len;
del_entry->delegate->issuer_attribute = (char *) &del_entry->delegate[1];
GNUNET_CONTAINER_DLL_insert_tail (vrh->del_chain_head,
vrh->del_chain_tail,
del_entry);
vrh->del_chain_size++;
}
// Switch resolution algo
if (GNUNET_ABD_FLAG_BACKWARD & vrh->resolution_algo &&
GNUNET_ABD_FLAG_FORWARD & vrh->resolution_algo)
{
if (1 == delegation_chain_fw_resolution_start (vrh))
return;
delegation_chain_bw_resolution_start (vrh);
}
else if (GNUNET_ABD_FLAG_BACKWARD & vrh->resolution_algo)
{
delegation_chain_bw_resolution_start (vrh);
}
else if (GNUNET_ABD_FLAG_FORWARD & vrh->resolution_algo)
{
delegation_chain_fw_resolution_start (vrh);
}
}
static void
handle_delegate_collection_error_cb (void *cls)
{
struct VerifyRequestHandle *vrh = cls;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Got disconnected from namestore database.\n");
vrh->dele_qe = NULL;
send_lookup_response (vrh);
}
static void
delegate_collection_finished (void *cls)
{
struct VerifyRequestHandle *vrh = cls;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Done collecting delegates.\n");
// if both are set: bidirectional search, meaning start both chain resolutions
if (GNUNET_ABD_FLAG_BACKWARD & vrh->resolution_algo &&
GNUNET_ABD_FLAG_FORWARD & vrh->resolution_algo)
{
// if premature match found don't start bw resultion
if (1 == delegation_chain_fw_resolution_start (vrh))
return;
delegation_chain_bw_resolution_start (vrh);
}
else if (GNUNET_ABD_FLAG_BACKWARD & vrh->resolution_algo)
{
delegation_chain_bw_resolution_start (vrh);
}
else if (GNUNET_ABD_FLAG_FORWARD & vrh->resolution_algo)
{
delegation_chain_fw_resolution_start (vrh);
}
}
static void
handle_delegate_collection_cb (void *cls,
const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
const char *label,
unsigned int rd_count,
const struct GNUNET_GNSRECORD_Data *rd)
{
struct VerifyRequestHandle *vrh = cls;
struct GNUNET_ABD_Delegate *del;
struct DelegateRecordEntry *del_entry;
int cred_record_count;
cred_record_count = 0;
vrh->dele_qe = NULL;
for (uint32_t i = 0; i < rd_count; i++)
{
if (GNUNET_GNSRECORD_TYPE_DELEGATE != rd[i].record_type)
continue;
cred_record_count++;
del = GNUNET_ABD_delegate_deserialize (rd[i].data, rd[i].data_size);
if (NULL == del)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid delegate found\n");
continue;
}
// only add the entries that are explicity marked as private
// and therefor symbolize the end of a chain
if (rd[i].flags & GNUNET_GNSRECORD_RF_PRIVATE)
{
del_entry = GNUNET_new (struct DelegateRecordEntry);
del_entry->delegate = del;
GNUNET_CONTAINER_DLL_insert_tail (vrh->del_chain_head,
vrh->del_chain_tail,
del_entry);
vrh->del_chain_size++;
}
}
delegate_collection_finished (vrh);
}
static void
handle_collect (void *cls, const struct CollectMessage *c_msg)
{
char attr[GNUNET_ABD_MAX_LENGTH + 1];
char issuer_attribute[GNUNET_ABD_MAX_LENGTH + 1];
struct VerifyRequestHandle *vrh;
struct GNUNET_SERVICE_Client *client = cls;
char *attrptr = attr;
const char *utf_in;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received COLLECT message\n");
utf_in = (const char *) &c_msg[1];
GNUNET_STRINGS_utf8_tolower (utf_in, attrptr);
GNUNET_memcpy (issuer_attribute, attr, ntohs (c_msg->issuer_attribute_len));
issuer_attribute[ntohs (c_msg->issuer_attribute_len)] = '\0';
vrh = GNUNET_new (struct VerifyRequestHandle);
vrh->is_collect = true;
GNUNET_CONTAINER_DLL_insert (vrh_head, vrh_tail, vrh);
vrh->client = client;
vrh->request_id = c_msg->id;
vrh->issuer_key = c_msg->issuer_key;
GNUNET_CRYPTO_ecdsa_key_get_public (&c_msg->subject_key, &vrh->subject_key);
vrh->issuer_attribute = GNUNET_strdup (issuer_attribute);
vrh->resolution_algo = ntohs (c_msg->resolution_algo);
vrh->del_chain_head = NULL;
vrh->del_chain_tail = NULL;
vrh->dsq_head = NULL;
vrh->dsq_tail = NULL;
vrh->del_chain_head = NULL;
vrh->del_chain_tail = NULL;
if (0 == strlen (issuer_attribute))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No issuer attribute provided!\n");
send_lookup_response (vrh);
return;
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting delegates for subject\n");
// Get all delegates from subject
vrh->dele_qe =
GNUNET_NAMESTORE_records_lookup (namestore,
&c_msg->subject_key,
GNUNET_GNS_EMPTY_LABEL_AT,
&handle_delegate_collection_error_cb,
vrh,
&handle_delegate_collection_cb,
vrh);
GNUNET_SERVICE_client_continue (vrh->client);
}
static int
check_collect (void *cls, const struct CollectMessage *c_msg)
{
size_t msg_size;
const char *attr;
msg_size = ntohs (c_msg->header.size);
if (msg_size < sizeof (struct CollectMessage))
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
if (ntohs (c_msg->issuer_attribute_len) > GNUNET_ABD_MAX_LENGTH)
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
attr = (const char *) &c_msg[1];
if (('\0' != attr[msg_size - sizeof (struct CollectMessage) - 1]) ||
(strlen (attr) > GNUNET_ABD_MAX_LENGTH))
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
return GNUNET_OK;
}
static void
client_disconnect_cb (void *cls,
struct GNUNET_SERVICE_Client *client,
void *app_ctx)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p disconnected\n", client);
}
static void *
client_connect_cb (void *cls,
struct GNUNET_SERVICE_Client *client,
struct GNUNET_MQ_Handle *mq)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", client);
return client;
}
/**
* Process Credential requests.
*
* @param cls closure
* @param c configuration to use
* @param handle service handle
*/
static void
run (void *cls,
const struct GNUNET_CONFIGURATION_Handle *c,
struct GNUNET_SERVICE_Handle *handle)
{
gns = GNUNET_GNS_connect (c);
if (NULL == gns)
{
fprintf (stderr, _ ("Failed to connect to GNS\n"));
}
namestore = GNUNET_NAMESTORE_connect (c);
if (NULL == namestore)
{
fprintf (stderr, _ ("Failed to connect to namestore\n"));
}
statistics = GNUNET_STATISTICS_create ("abd", c);
GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
}
/**
* Define "main" method using service macro
*/
GNUNET_SERVICE_MAIN (
"abd",
GNUNET_SERVICE_OPTION_NONE,
&run,
&client_connect_cb,
&client_disconnect_cb,
NULL,
GNUNET_MQ_hd_var_size (verify,
GNUNET_MESSAGE_TYPE_ABD_VERIFY,
struct VerifyMessage,
NULL),
GNUNET_MQ_hd_var_size (collect,
GNUNET_MESSAGE_TYPE_ABD_COLLECT,
struct CollectMessage,
NULL),
GNUNET_MQ_handler_end ());
/* end of gnunet-service-abd.c */