123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- #include "platform.h"
- #include <errno.h>
- #include <stdint.h>
- #include <stdlib.h>
- #include <string.h>
- #include "crypto.h"
- #include "crypto_entropy.h"
- #include "netpacket.h"
- #include "netproto.h"
- #include "storage_internal.h"
- #include "sysendian.h"
- #include "tsnetwork.h"
- #include "warnp.h"
- #include "storage.h"
- struct directory_read_internal {
- /* General state information. */
- uint64_t machinenum;
- int done;
- NETPACKET_CONNECTION * NPC;
- /* Parameters used in directory read. */
- uint8_t class;
- int key;
- uint8_t start[32];
- uint8_t nonce[32];
- uint8_t * flist;
- size_t nfiles;
- size_t nfiles_alloc;
- };
- static sendpacket_callback callback_getnonce_send;
- static handlepacket_callback callback_getnonce_response;
- static handlepacket_callback callback_directory_response;
- /**
- * storage_directory_read(machinenum, class, key, flist, nfiles):
- * Fetch a sorted list of files in the specified class. If ${key} is 0, use
- * NETPACKET_DIRECTORY requests (using the read key); otherwise, use
- * NETPACKET_DIRECTORY_D requests (using the delete key). Return the list
- * and the number of files via ${flist} and ${nfiles} respectively.
- */
- int
- storage_directory_read(uint64_t machinenum, char class, int key,
- uint8_t ** flist, size_t * nfiles)
- {
- struct directory_read_internal C;
- /* Open netpacket connection. */
- if ((C.NPC = netpacket_open(USERAGENT)) == NULL)
- goto err0;
- /* Initialize structure. */
- C.machinenum = machinenum;
- C.done = 0;
- C.class = (uint8_t)class;
- C.key = key;
- memset(C.start, 0, 32);
- C.flist = NULL;
- C.nfiles = C.nfiles_alloc = 0;
- /* Ask the netpacket layer to send a request and get a response. */
- if (netpacket_op(C.NPC, callback_getnonce_send, &C))
- goto err2;
- /* Wait until we're done or we have failed. */
- if (network_spin(&C.done))
- goto err2;
- /* Return results. */
- *flist = C.flist;
- *nfiles = C.nfiles;
- /* Close netpacket connection. */
- if (netpacket_close(C.NPC))
- goto err1;
- /* Success! */
- return (0);
- err2:
- netpacket_close(C.NPC);
- err1:
- free(C.flist);
- err0:
- /* Failure! */
- return (-1);
- }
- static int
- callback_getnonce_send(void * cookie, NETPACKET_CONNECTION * NPC)
- {
- struct directory_read_internal * C = cookie;
- /* Ask the server to provide a transaction server nonce. */
- return (netpacket_transaction_getnonce(NPC, C->machinenum,
- callback_getnonce_response));
- }
- static int
- callback_getnonce_response(void * cookie, NETPACKET_CONNECTION * NPC,
- int status, uint8_t packettype, const uint8_t * packetbuf,
- size_t packetlen)
- {
- struct directory_read_internal * C = cookie;
- uint8_t cnonce[32];
- (void)packetlen; /* UNUSED */
- /* Handle read errors. */
- if (status != NETWORK_STATUS_OK) {
- netproto_printerr(status);
- goto err0;
- }
- /* Make sure we received the right type of packet. */
- if (packettype != NETPACKET_TRANSACTION_GETNONCE_RESPONSE)
- goto err1;
- /* Generate a random client nonce. */
- if (crypto_entropy_read(cnonce, 32))
- goto err0;
- /* Compute operation nonce. */
- if (crypto_hash_data_2(CRYPTO_KEY_HMAC_SHA256, packetbuf, 32,
- cnonce, 32, C->nonce)) {
- warn0("Programmer error: "
- "SHA256 should never fail");
- goto err0;
- }
- /* Send a directory read request. */
- if (netpacket_directory(NPC, C->machinenum, C->class, C->start,
- packetbuf, cnonce, C->key, callback_directory_response))
- goto err0;
- /* Success! */
- return (0);
- err1:
- netproto_printerr(NETPROTO_STATUS_PROTERR);
- err0:
- /* Failure! */
- return (-1);
- }
- static int
- callback_directory_response(void * cookie, NETPACKET_CONNECTION * NPC,
- int status, uint8_t packettype, const uint8_t * packetbuf,
- size_t packetlen)
- {
- struct directory_read_internal * C = cookie;
- uint8_t * flist_new;
- size_t nfiles;
- size_t file;
- int i;
- /* Handle read errors. */
- if (status != NETWORK_STATUS_OK) {
- netproto_printerr(status);
- goto err0;
- }
- /* Make sure we received the right type of packet. */
- if (packettype != NETPACKET_DIRECTORY_RESPONSE)
- goto err1;
- /* Verify packet hmac. */
- switch (netpacket_hmac_verify(packettype, C->nonce,
- packetbuf, packetlen - 32,
- (C->key == 0) ? CRYPTO_KEY_AUTH_GET : CRYPTO_KEY_AUTH_DELETE)) {
- case 1:
- goto err1;
- case -1:
- goto err0;
- }
- /* Parse nfiles field. */
- nfiles = be32dec(&packetbuf[34]);
- /* Sanity-check parameters. */
- if ((packetbuf[0] > 3) ||
- (packetbuf[1] != C->class) ||
- (memcmp(&packetbuf[2], C->start, 32) != 0) ||
- (nfiles > NETPACKET_DIRECTORY_RESPONSE_MAXFILES))
- goto err1;
- /* Sanity-check length. */
- if (packetlen != 70 + nfiles * 32)
- goto err1;
- /* Do we need to reallocate? */
- if (C->nfiles + nfiles > C->nfiles_alloc) {
- C->nfiles_alloc = 2 * C->nfiles + nfiles;
- if (C->nfiles_alloc > SIZE_MAX / 32) {
- errno = ENOMEM;
- goto err0;
- }
- if ((flist_new = malloc(C->nfiles_alloc * 32)) == NULL)
- goto err0;
- if (C->nfiles > 0)
- memcpy(flist_new, C->flist, C->nfiles * 32);
- free(C->flist);
- C->flist = flist_new;
- }
- /* Add files to list, while making sure that the files are ordered. */
- for (file = 0; file < nfiles; file++) {
- if (memcmp(C->start, &packetbuf[38 + file * 32], 32) > 0)
- goto err1;
- memcpy(C->start, &packetbuf[38 + file * 32], 32);
- memcpy(C->flist + (C->nfiles + file) * 32, C->start, 32);
- for (i = 31; i >= 0; i--)
- if (++(C->start[i]) != 0)
- break;
- }
- C->nfiles += nfiles;
- /* Are there more packets to come? */
- switch (packetbuf[0]) {
- case 0:
- /* No more files. */
- C->done = 1;
- break;
- case 1:
- /* More files to come. */
- if (netpacket_directory_readmore(NPC,
- callback_directory_response))
- goto err0;
- break;
- case 2:
- /* We need to send another request. */
- if (netpacket_op(NPC, callback_getnonce_send, C))
- goto err0;
- break;
- case 3:
- /* Insufficient funds. */
- warn0("Cannot read list of archive fragments: "
- "Account balance is not positive.");
- warn0("Please add more money to your tarsnap account");
- goto err0;
- }
- /* Success! */
- return (0);
- err1:
- netproto_printerr(NETPROTO_STATUS_PROTERR);
- err0:
- /* Failure! */
- return (-1);
- }
|