/*
This file is part of GNUnet.
Copyright (C) 2013 GNUnet e.V.
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 3, 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
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNUnet; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
/**
* @file identity/gnunet-service-identity.c
* @brief identity management service
* @author Christian Grothoff
*
* The purpose of this service is to manage private keys that
* represent the various egos/pseudonyms/identities of a GNUnet user.
*
* Todo:
* - auto-initialze default egos; maybe trigger default
* initializations (such as gnunet-gns-import.sh?)
*/
#include "platform.h"
#include "gnunet_util_lib.h"
#include "gnunet_constants.h"
#include "gnunet_protocols.h"
#include "gnunet_statistics_service.h"
#include "gnunet_identity_service.h"
#include "identity.h"
/**
* Information we keep about each ego.
*/
struct Ego
{
/**
* We keep egos in a DLL.
*/
struct Ego *next;
/**
* We keep egos in a DLL.
*/
struct Ego *prev;
/**
* Private key of the ego.
*/
struct GNUNET_CRYPTO_EcdsaPrivateKey *pk;
/**
* String identifier for the ego.
*/
char *identifier;
};
/**
* Handle to our current configuration.
*/
static const struct GNUNET_CONFIGURATION_Handle *cfg;
/**
* Handle to subsystem configuration which for each subsystem contains
* the name of the default ego.
*/
static struct GNUNET_CONFIGURATION_Handle *subsystem_cfg;
/**
* Handle to the statistics service.
*/
static struct GNUNET_STATISTICS_Handle *stats;
/**
* Notification context, simplifies client broadcasts.
*/
static struct GNUNET_NotificationContext *nc;
/**
* Directory where we store the identities.
*/
static char *ego_directory;
/**
* Configuration file name where subsystem information is kept.
*/
static char *subsystem_cfg_file;
/**
* Head of DLL of all egos.
*/
static struct Ego *ego_head;
/**
* Tail of DLL of all egos.
*/
static struct Ego *ego_tail;
/**
* Get the name of the file we use to store a given ego.
*
* @param ego ego for which we need the filename
* @return full filename for the given ego
*/
static char *
get_ego_filename (struct Ego *ego)
{
char *filename;
GNUNET_asprintf (&filename,
"%s%s%s",
ego_directory,
DIR_SEPARATOR_STR,
ego->identifier);
return filename;
}
/**
* Called whenever a client is disconnected.
*
* @param cls closure
* @param client identification of the client
* @param app_ctx @a client
*/
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);
}
/**
* Add a client to our list of active clients.
*
* @param cls NULL
* @param client client to add
* @param mq message queue for @a client
* @return internal namestore client structure for this client
*/
static void *
client_connect_cb (void *cls,
struct GNUNET_SERVICE_Client *client,
struct GNUNET_MQ_Handle *mq)
{
return client;
}
/**
* Task run during shutdown.
*
* @param cls unused
*/
static void
shutdown_task (void *cls)
{
struct Ego *e;
if (NULL != nc)
{
GNUNET_notification_context_destroy (nc);
nc = NULL;
}
if (NULL != stats)
{
GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
stats = NULL;
}
GNUNET_CONFIGURATION_destroy (subsystem_cfg);
subsystem_cfg = NULL;
GNUNET_free (subsystem_cfg_file);
subsystem_cfg_file = NULL;
GNUNET_free (ego_directory);
ego_directory = NULL;
while (NULL != (e = ego_head))
{
GNUNET_CONTAINER_DLL_remove (ego_head, ego_tail, e);
GNUNET_free (e->pk);
GNUNET_free (e->identifier);
GNUNET_free (e);
}
}
/**
* Send a result code back to the client.
*
* @param client client that should receive the result code
* @param result_code code to transmit
* @param emsg error message to include (or NULL for none)
*/
static void
send_result_code (struct GNUNET_SERVICE_Client *client,
uint32_t result_code,
const char *emsg)
{
struct ResultCodeMessage *rcm;
struct GNUNET_MQ_Envelope *env;
size_t elen;
if (NULL == emsg)
elen = 0;
else
elen = strlen (emsg) + 1;
env = GNUNET_MQ_msg_extra (rcm,
elen,
GNUNET_MESSAGE_TYPE_IDENTITY_RESULT_CODE);
rcm->result_code = htonl (result_code);
if (0 < elen)
GNUNET_memcpy (&rcm[1], emsg, elen);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,