struct blob *blob_parse(const char *blob, size_t len, const unsigned char key[KDF_HASH_LEN], const struct private_key *private_key) { struct blob_pos blob_pos = { .data = blob, .len = len }; struct chunk chunk; struct account *account, **next_account; struct field *field, **next_field = NULL; struct share *last_share = NULL; struct blob *parsed; _cleanup_free_ char *versionstr = NULL; parsed = new0(struct blob, 1); parsed->local_version = false; next_account = &parsed->account_head; while (read_chunk(&blob_pos, &chunk)) { if (!strcmp(chunk.name, "LPAV")) { versionstr = xstrndup(chunk.data, chunk.len); parsed->version = strtoull(versionstr, NULL, 10); } else if (!strcmp(chunk.name, "ACCT")) { account = account_parse(&chunk, last_share ? last_share->key : key); if (!account) goto error; share_assign(last_share, &account->share); *next_account = account; next_account = &account->next; next_field = &account->field_head; } else if (!strcmp(chunk.name, "ACFL") || !strcmp(chunk.name, "ACOF")) { if (!next_field) goto error; field = field_parse(&chunk, last_share ? last_share->key : key); if (!field) goto error; *next_field = field; next_field = &field->next; } else if (!strcmp(chunk.name, "LOCL")) parsed->local_version = true; else if (!strcmp(chunk.name, "SHAR")) { share_free(last_share); share_assign(share_parse(&chunk, private_key), &last_share); } } if (!versionstr) goto error; if (!parsed->account_head) goto error; share_free(last_share); return parsed; error: share_free(last_share); blob_free(parsed); return NULL; }
void account_free(struct account *account) { if (!account) return; free(account->id); free(account->name); free(account->group); free(account->fullname); free(account->url); free(account->username); free(account->password); free(account->note); free(account->name_encrypted); free(account->group_encrypted); free(account->username_encrypted); free(account->password_encrypted); free(account->note_encrypted); for (struct field *field = account->field_head, *next_field = NULL; field; field = next_field) { next_field = field->next; field_free(field); } share_free(account->share); free(account); }
static struct share *share_parse(struct chunk *chunk, const struct private_key *private_key) { struct share *parsed = new0(struct share, 1); struct item item; _cleanup_free_ char *ciphertext = NULL; _cleanup_free_ char *hex_key = NULL; _cleanup_free_ unsigned char *key = NULL; _cleanup_free_ char *base64_name = NULL; size_t len; if (!private_key) goto error; if (chunk->len) { parsed->chunk_len = chunk->len; parsed->chunk = xmalloc(chunk->len); memcpy(parsed->chunk, chunk->data, chunk->len); } entry_plain(id); if (!read_item(chunk, &item) || item.len == 0 || item.len % 2 != 0) goto error; hex_to_bytes(item.data, &ciphertext); hex_key = cipher_rsa_decrypt(ciphertext, item.len / 2, private_key); if (!hex_key) goto error; len = strlen(hex_key); if (len % 2 != 0) goto error; len /= 2; if (len != KDF_HASH_LEN) goto error; hex_to_bytes(hex_key, (char **)&key); mlock(parsed->key, KDF_HASH_LEN); memcpy(parsed->key, key, KDF_HASH_LEN); base64_name = read_plain_string(chunk); parsed->name = cipher_aes_decrypt_base64(base64_name, parsed->key); if (!parsed->name) goto error; entry_boolean(readonly); return parsed; error: share_free(parsed); return NULL; }
/* Called by ares library for each result. */ static void result_callback (ASSearch *search, ASResult *r, as_bool duplicate) { Share *share; char *url, *filename, *user; if (!r) { AS_DBG_1 ("Search complete. Id: %d.", search->id); /* Tell giFT we're finished. */ PROTO->search_complete (PROTO, search->udata); /* The above does _not_ make giFT call asp_cb_search_cancel() so * remove the search now. */ if (!as_searchman_remove (AS->searchman, search)) { AS_ERR ("Failed to remove complete search"); assert (0); } return; } /* Create a share object for giFT. */ if (!(share = share_new (NULL))) return; share->p = PROTO; share->size = r->filesize; filename = r->filename; /* Try to find file name and size in hash table if none was returned. */ if (search->type == SEARCH_LOCATE && (!filename || share->size == 0)) { size_t size; char *name; /* Lookup this hash in the evil hash map to find the * size and filename for giFT. */ if (asp_hashmap_lookup (r->hash, &name, &size)) { if (share->size == 0) share->size = size; if (!filename && name && *name) filename = name; } } /* If we still don't have a file name fake one to prevent things from * blowing up elsewhere. */ if (!filename) filename = "<Unknown>"; share_set_path (share, filename); share_set_mime (share, mime_type (filename)); share_set_hash (share, "SHA1", r->hash->data, AS_HASH_SIZE, FALSE); /* Add meta data. */ if (r->meta) as_meta_foreach_tag (r->meta, (ASMetaForeachFunc)meta_to_gift, share); /* Create the url giFT will pass back to us on download. */ if (!(url = as_source_serialize (r->source))) { AS_ERR_1 ("Couldn't serialize source '%s'", as_source_str (r->source)); share_free (share); return; } /* Assemble username@ip string. */ if (STRING_NULL (r->source->username)) user = stringf_dup ("%s@%s", r->source->username, net_ip_str (r->source->host)); else user = gift_strdup (net_ip_str (r->source->host)); /* Send the result to giFT. */ PROTO->search_result (PROTO, search->udata, user, NULL, url, 1, share); free (user); free (url); share_free (share); }