/** * Listen to the pipe, decode messages and send to core. */ static void * listenAndDistribute (void *unused) { char *line; unsigned int linesize; SMTPMessage *mp; FILE *fdes; char *retl; char *out; unsigned int size; GNUNET_TransportPacket *coreMP; int fd; unsigned int pos; linesize = ((GNUNET_MAX_BUFFER_SIZE * 4 / 3) + 8) * (MAX_CHAR_PER_LINE + 2) / MAX_CHAR_PER_LINE; /* maximum size of a line supported */ line = GNUNET_malloc (linesize + 2); /* 2 bytes for off-by-one errors, just to be safe... */ #define READLINE(l,limit) \ do { retl = fgets(l, (limit), fdes); \ if ( (retl == NULL) || (smtp_shutdown == GNUNET_YES)) {\ goto END; \ }\ if (core_api->load_monitor != NULL) \ GNUNET_network_monitor_notify_transmission(core_api->load_monitor, GNUNET_ND_DOWNLOAD, strlen(retl)); \ } while (0) while (smtp_shutdown == GNUNET_NO) { fd = OPEN (pipename, O_RDONLY | O_ASYNC); if (fd == -1) { if (smtp_shutdown == GNUNET_NO) GNUNET_thread_sleep (5 * GNUNET_CRON_SECONDS); continue; } fdes = fdopen (fd, "r"); while (smtp_shutdown == GNUNET_NO) { /* skip until end of header */ do { READLINE (line, linesize); } while ((line[0] != '\r') && (line[0] != '\n')); /* expect newline */ READLINE (line, linesize); /* read base64 encoded message; decode, process */ pos = 0; while (1) { pos = strlen (line) - 1; /* ignore new line */ READLINE (&line[pos], linesize - pos); /* read base64 encoded message; decode, process */ if ((line[pos] == '\r') || (line[pos] == '\n')) break; /* empty line => end of message! */ } size = GNUNET_STRINGS_base64_decode (line, pos, &out); if (size < sizeof (SMTPMessage)) { GNUNET_GE_BREAK (ectx, 0); GNUNET_free (out); goto END; } mp = (SMTPMessage *) &out[size - sizeof (SMTPMessage)]; if (ntohs (mp->header.size) != size) { GNUNET_GE_LOG (ectx, GNUNET_GE_WARNING | GNUNET_GE_BULK | GNUNET_GE_USER, _("Received malformed message via %s. Ignored.\n"), "SMTP"); #if DEBUG_SMTP GNUNET_GE_LOG (ectx, GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER, "Size returned by base64=%d, in the msg=%d.\n", size, ntohl (mp->size)); #endif GNUNET_free (out); goto END; } if (stats != NULL) stats->change (stat_bytesReceived, size); coreMP = GNUNET_new (GNUNET_TransportPacket); coreMP->msg = out; coreMP->size = size - sizeof (SMTPMessage); coreMP->tsession = NULL; coreMP->sender = mp->sender; #if DEBUG_SMTP GNUNET_GE_LOG (ectx, GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER, "SMTP message passed to the core.\n"); #endif core_api->receive (coreMP); } END: #if DEBUG_SMTP GNUNET_GE_LOG (ectx, GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER, "SMTP message processed.\n"); #endif if (fdes != NULL) fclose (fdes); } GNUNET_free (line); return NULL; }
/** * Initialize the database connections and associated * data structures (create tables and indices * as needed as well). * * @param plugin the plugin context (state for this module) * @return GNUNET_OK on success */ static int database_setup (struct Plugin *plugin) { char *afsdir; char *key; char *sub_system; const char *peer_id; char *peer; char *value; char *expiry; struct GNUNET_DISK_FileHandle *fh; struct GNUNET_PEERSTORE_Record *entry; struct GNUNET_HashCode hkey; size_t size; char *buffer; char *line; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (plugin->cfg, "peerstore-flat", "FILENAME", &afsdir)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "peerstore-flat", "FILENAME"); return GNUNET_SYSERR; } if (GNUNET_OK != GNUNET_DISK_file_test (afsdir)) { if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (afsdir)) { GNUNET_break (0); GNUNET_free (afsdir); return GNUNET_SYSERR; } } /* afsdir should be UTF-8-encoded. If it isn't, it's a bug */ plugin->fn = afsdir; fh = GNUNET_DISK_file_open (afsdir, GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_READWRITE, GNUNET_DISK_PERM_USER_WRITE | GNUNET_DISK_PERM_USER_READ); if (NULL == fh) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unable to initialize file: %s.\n"), afsdir); return GNUNET_SYSERR; } /* Load data from file into hashmap */ plugin->hm = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO); if (GNUNET_SYSERR == GNUNET_DISK_file_size (afsdir, &size, GNUNET_YES, GNUNET_YES)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unable to get filesize: %s.\n"), afsdir); return GNUNET_SYSERR; } buffer = GNUNET_malloc (size + 1); if (GNUNET_SYSERR == GNUNET_DISK_file_read (fh, buffer, size)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unable to read file: %s.\n"), afsdir); GNUNET_DISK_file_close (fh); GNUNET_free (buffer); return GNUNET_SYSERR; } buffer[size] = '\0'; GNUNET_DISK_file_close (fh); if (0 < size) { line = strtok (buffer, "\n"); while (line != NULL) { sub_system = strtok (line, ","); if (NULL == sub_system) break; peer = strtok (NULL, ","); if (NULL == peer) break; key = strtok (NULL, ","); if (NULL == key) break; value = strtok (NULL, ","); if (NULL == value) break; expiry = strtok (NULL, ","); if (NULL == expiry) break; entry = GNUNET_new (struct GNUNET_PEERSTORE_Record); entry->sub_system = GNUNET_strdup (sub_system); entry->key = GNUNET_strdup (key); GNUNET_STRINGS_base64_decode (peer, strlen (peer), (char**)&entry->peer); entry->value_size = GNUNET_STRINGS_base64_decode (value, strlen (value), (char**)&entry->value); if (GNUNET_SYSERR == GNUNET_STRINGS_fancy_time_to_absolute (expiry, entry->expiry)) { GNUNET_free (entry->sub_system); GNUNET_free (entry->key); GNUNET_free (entry->peer); GNUNET_free (entry); break; } peer_id = GNUNET_i2s (entry->peer); GNUNET_CRYPTO_hash (peer_id, strlen (peer_id), &hkey); GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (plugin->hm, &hkey, entry, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); } }
/** * This function updates the old token with new attributes, * removes deleted attributes and expiration times. * * @param cls the ego entry * @param tc task context */ static void handle_token_update (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { char *token_header; char *token_payload; char *token_payload_json; char *new_token; char *new_payload_str; char *new_payload_base64; char *sig_str; char *key; char *padding; const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key; struct EgoEntry *ego_entry = cls; struct GNUNET_GNSRECORD_Data token_record; struct GNUNET_CRYPTO_EccSignaturePurpose *purpose; struct GNUNET_CRYPTO_EcdsaSignature sig; struct GNUNET_HashCode key_hash; struct GNUNET_TIME_Relative token_rel_exp; struct GNUNET_TIME_Relative token_ttl; struct GNUNET_TIME_Absolute token_exp; struct GNUNET_TIME_Absolute token_nbf; struct GNUNET_TIME_Absolute new_exp; struct GNUNET_TIME_Absolute new_iat; struct GNUNET_TIME_Absolute new_nbf; json_t *payload_json; json_t *value; json_t *cur_value; json_t *new_payload_json; json_t *token_nbf_json; json_t *token_exp_json; json_error_t json_err; priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); //Note: We need the token expiration time here. Not the record expiration //time. //There are two types of tokens: Token that expire on GNS level with //an absolute expiration time. Those are basically tokens that will //be automatically revoked on (record)expiration. //Tokens stored with relative expiration times will expire on the token level (token expiration) //but this service will reissue new tokens that can be retrieved from GNS //automatically. token_header = strtok (token, "."); token_payload = strtok (NULL, "."); GNUNET_STRINGS_base64_decode (token_payload, strlen (token_payload), &token_payload_json); payload_json = json_loads (token_payload_json, JSON_DECODE_ANY, &json_err); GNUNET_free (token_payload_json); token_exp_json = json_object_get (payload_json, "exp"); token_nbf_json = json_object_get (payload_json, "nbf"); token_exp.abs_value_us = json_integer_value(token_exp_json); token_nbf.abs_value_us = json_integer_value(token_nbf_json); token_rel_exp = GNUNET_TIME_absolute_get_difference (token_nbf, token_exp); token_ttl = GNUNET_TIME_absolute_get_remaining (token_exp); if (0 != GNUNET_TIME_absolute_get_remaining (token_exp).rel_value_us) { //This token is not yet expired! Save and skip if (min_rel_exp.rel_value_us > token_ttl.rel_value_us) { min_rel_exp = token_ttl; } json_decref (payload_json); GNUNET_free (token); token = NULL; GNUNET_free (label); label = NULL; GNUNET_NAMESTORE_zone_iterator_next (ns_it); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Token is expired. Create a new one\n"); new_exp = GNUNET_TIME_relative_to_absolute (token_rel_exp); new_nbf = GNUNET_TIME_absolute_get (); new_iat = new_nbf; new_payload_json = json_object(); json_object_foreach(payload_json, key, value) { if (0 == strcmp (key, "exp")) { json_object_set_new (new_payload_json, key, json_integer (new_exp.abs_value_us)); } else if (0 == strcmp (key, "nbf")) { json_object_set_new (new_payload_json, key, json_integer (new_nbf.abs_value_us)); } else if (0 == strcmp (key, "iat")) { json_object_set_new (new_payload_json, key, json_integer (new_iat.abs_value_us)); } else if ((0 == strcmp (key, "iss")) || (0 == strcmp (key, "aud")) || (0 == strcmp (key, "sub")) || (0 == strcmp (key, "rnl"))) { json_object_set (new_payload_json, key, value); } else { GNUNET_CRYPTO_hash (key, strlen (key), &key_hash); //Check if attr still exists. omit of not if (GNUNET_NO != GNUNET_CONTAINER_multihashmap_contains (ego_entry->attr_map, &key_hash)) { cur_value = GNUNET_CONTAINER_multihashmap_get (ego_entry->attr_map, &key_hash); json_object_set (new_payload_json, key, cur_value); } } } // reassemble and set new_payload_str = json_dumps (new_payload_json, JSON_COMPACT); json_decref (payload_json); json_decref (new_payload_json); GNUNET_STRINGS_base64_encode (new_payload_str, strlen (new_payload_str), &new_payload_base64); //Remove padding padding = strtok(new_payload_base64, "="); while (NULL != padding) padding = strtok(NULL, "="); GNUNET_asprintf (&new_token, "%s,%s", token_header, new_payload_base64); purpose = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + strlen (new_token)); purpose->size = htonl (strlen (new_token) + sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose)); purpose->purpose = htonl(GNUNET_SIGNATURE_PURPOSE_GNUID_TOKEN); memcpy (&purpose[1], new_token, strlen (new_token)); if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign (priv_key, purpose, &sig)) GNUNET_break(0); GNUNET_free (new_token); sig_str = GNUNET_STRINGS_data_to_string_alloc (&sig, sizeof (struct GNUNET_CRYPTO_EcdsaSignature)); GNUNET_asprintf (&new_token, "%s.%s.%s", token_header, new_payload_base64, sig_str); GNUNET_free (sig_str); GNUNET_free (new_payload_str); GNUNET_free (new_payload_base64); GNUNET_free (purpose); token_record.data = new_token; token_record.data_size = strlen (new_token); token_record.expiration_time = new_exp.abs_value_us; token_record.record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN; token_record.flags = GNUNET_GNSRECORD_RF_NONE | GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; ns_qe = GNUNET_NAMESTORE_records_store (ns_handle, priv_key, label, 1, &token_record, &store_token_cont, ego_entry); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, ">>> Updating Token w/ %s\n", new_token); GNUNET_free (new_token); GNUNET_free (token); token = NULL; GNUNET_free (label); label = NULL; }
/** * Initialize the database connections and associated * data structures (create tables and indices * as needed as well). * * @param plugin the plugin context (state for this module) * @return #GNUNET_OK on success */ static int database_setup (struct Plugin *plugin) { char *afsdir; char* block_buffer; char* buffer; char* line; char* query; char* block; size_t size; struct FlatFileEntry *entry; struct GNUNET_DISK_FileHandle *fh; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (plugin->cfg, "namecache-flat", "FILENAME", &afsdir)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "namecache-flat", "FILENAME"); return GNUNET_SYSERR; } if (GNUNET_OK != GNUNET_DISK_file_test (afsdir)) { if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (afsdir)) { GNUNET_break (0); GNUNET_free (afsdir); return GNUNET_SYSERR; } } /* afsdir should be UTF-8-encoded. If it isn't, it's a bug */ plugin->fn = afsdir; /* Load data from file into hashmap */ plugin->hm = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO); fh = GNUNET_DISK_file_open (afsdir, GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_READWRITE, GNUNET_DISK_PERM_USER_WRITE | GNUNET_DISK_PERM_USER_READ); if (NULL == fh) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unable to initialize file: %s.\n"), afsdir); return GNUNET_SYSERR; } if (GNUNET_SYSERR == GNUNET_DISK_file_size (afsdir, &size, GNUNET_YES, GNUNET_YES)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unable to get filesize: %s.\n"), afsdir); return GNUNET_SYSERR; } if (0 == size) return GNUNET_OK; buffer = GNUNET_malloc (size); if (GNUNET_SYSERR == GNUNET_DISK_file_read (fh, buffer, size)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unable to read file: %s.\n"), afsdir); return GNUNET_SYSERR; } GNUNET_DISK_file_close (fh); if (0 < size) { line = strtok (buffer, "\n"); while (line != NULL) { query = strtok (line, ","); if (NULL == query) break; block = strtok (NULL, ","); if (NULL == block) break; line = strtok (NULL, "\n"); entry = GNUNET_malloc (sizeof (struct FlatFileEntry)); GNUNET_CRYPTO_hash_from_string (query, &entry->query); GNUNET_STRINGS_base64_decode (block, strlen (block), &block_buffer); entry->block = (struct GNUNET_GNSRECORD_Block *) block_buffer; if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (plugin->hm, &entry->query, entry, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) { GNUNET_free (entry); GNUNET_break (0); } } } GNUNET_free (buffer); return GNUNET_OK; }