/** * network_desleep(handle): * Deregister the callback associated with the provided handle. The * callback will be called with a status of NETWORK_STATUS_CANCEL. */ int network_desleep(int handle) { struct sleeper * sp; /* Sanity-check the handle. */ if ((handle >= (int)sleepers_getsize(sleepers)) || (handle < 0)) { warn0("Invalid sleeper handle: %d", handle); goto err0; } /* Grab the relevant sleeper record. */ sp = *sleepers_get(sleepers, (size_t)handle); /* If there is no timer, return silently. */ if (sp->event_cookie == NULL) return (0); /* Cancel the timer. */ events_timer_cancel(sp->event_cookie); sp->event_cookie = NULL; /* Invoke the callback. */ return ((sp->callback)(sp->cookie, NETWORK_STATUS_CANCEL)); err0: /* Failure! */ return (-1); }
/** * crypto_keys_subr_export_RSA_priv(key, buf, buflen): * If buf != NULL, export the specified RSA private key. Return the key * length in bytes. */ uint32_t crypto_keys_subr_export_RSA_priv(RSA * key, uint8_t * buf, size_t buflen) { uint32_t len = 0; if (key == NULL) { warn0("Cannot export a key which we don't have!"); goto err0; } /* Each large integer gets exported. */ if (export_BN(key->n, &buf, &buflen, &len)) goto err0; if (export_BN(key->e, &buf, &buflen, &len)) goto err0; if (export_BN(key->d, &buf, &buflen, &len)) goto err0; if (export_BN(key->p, &buf, &buflen, &len)) goto err0; if (export_BN(key->q, &buf, &buflen, &len)) goto err0; if (export_BN(key->dmp1, &buf, &buflen, &len)) goto err0; if (export_BN(key->dmq1, &buf, &buflen, &len)) goto err0; if (export_BN(key->iqmp, &buf, &buflen, &len)) goto err0; /* Success! */ return (len); err0: /* Failure! */ return ((uint32_t)(-1)); }
/* Should we use AESNI? */ static int useaesni(void) { static int aesnigood = -1; uint8_t key[32]; uint8_t ptext[16]; size_t i; /* If we haven't decided which code to use yet, decide now. */ while (aesnigood == -1) { /* Default to OpenSSL. */ aesnigood = 0; /* If the CPU doesn't claim to support AESNI, stop here. */ if (!cpusupport_x86_aesni()) break; /* Test cases: key is 0x00010203..., ptext is 0x00112233... */ for (i = 0; i < 16; i++) ptext[i] = 0x11 * i; for (i = 0; i < 32; i++) key[i] = i; /* Test that AESNI and OpenSSL produce the same results. */ if (aesnitest(ptext, key, 16) || aesnitest(ptext, key, 32)) { warn0("Disabling AESNI due to failed self-test"); break; } /* AESNI works; use it. */ aesnigood = 1; } return (aesnigood); }
/** * multitape_metadata_recrypt(obuf, obuflen, nbuf, nbuflen): * Decrypt and re-encrypt the provided metadata file. */ int multitape_metadata_recrypt(uint8_t * obuf, size_t obuflen, uint8_t ** nbuf, size_t * nbuflen) { struct tapemetadata mdat; /* Parse the metadata file. */ switch (multitape_metadata_dec(&mdat, obuf, obuflen)) { case 1: warn0("Metadata file is corrupt"); goto err0; case -1: warnp("Error parsing metadata file"); goto err0; } /* Construct a new metadata file. */ if (multitape_metadata_enc(&mdat, nbuf, nbuflen)) { warnp("Error constructing metadata file"); goto err1; } /* Free the metadata we parsed. */ multitape_metadata_free(&mdat); /* Success! */ return (0); err1: multitape_metadata_free(&mdat); err0: /* Failure! */ return (-1); }
/** * crypto_keys_subr_import_RSA_pub(key, buf, buflen): * Import the specified RSA public key from the provided buffer. */ int crypto_keys_subr_import_RSA_pub(RSA ** key, const uint8_t * buf, size_t buflen) { /* Free any existing key. */ if (*key != NULL) RSA_free(*key); /* Create a new key. */ if ((*key = RSA_new()) == NULL) { warn0("%s", ERR_error_string(ERR_get_error(), NULL)); goto err0; } /* Load values. */ if (import_BN(&(*key)->n, &buf, &buflen)) goto err1; if (import_BN(&(*key)->e, &buf, &buflen)) goto err1; /* We should have no unprocessed data left. */ if (buflen) goto err1; /* Success! */ return (0); err1: RSA_free(*key); *key = NULL; err0: /* Failure! */ return (-1); }
/** * netpacket_register_request(NPC, user, callback): * Construct and send a NETPACKET_REGISTER_REQUEST packet asking to register * a new machine belonging to the specified user. */ int netpacket_register_request(NETPACKET_CONNECTION * NPC, const char * user, handlepacket_callback * callback) { /* Make sure user name is a sane length. */ if (strlen(user) > 255) { warn0("User name too long: %s", user); goto err0; } /* Send the packet. */ if (netproto_writepacket(NPC->NC, NETPACKET_REGISTER_REQUEST, (const uint8_t *)user, strlen(user), netpacket_op_packetsent, NPC)) goto err0; /* Set callback for handling a response. */ NPC->pending_current->handlepacket = callback; /* Success! */ return (0); err0: /* Failure! */ return (-1); }
/** * netproto_sleep(C, secs, callback, cookie): * Call the provided callback after ${secs} seconds. */ int netproto_sleep(NETPROTO_CONNECTION * C, int secs, network_callback * callback, void * cookie) { struct timeval timeo; /* Set timeout. */ timeo.tv_sec = secs; timeo.tv_usec = 0; /* Make sure this connection isn't already sleeping. */ if (C->sleepcookie.handle != -1) { warn0("Connection is already sleeping!"); goto err0; } /* Record callback parameters. */ C->sleepcookie.callback = callback; C->sleepcookie.cookie = cookie; /* Ask for a wake-up call. */ if ((C->sleepcookie.handle = network_sleep(&timeo, callback_sleep, C)) == -1) goto err0; /* Success! */ return (0); err0: /* Failure! */ return (-1); }
/** * crypto_MGF1(seed, seedlen, buf, buflen): * The MGF1 mask generation function, as specified in RFC 3447. */ void crypto_MGF1(uint8_t * seed, size_t seedlen, uint8_t * buf, size_t buflen) { uint8_t hbuf[32]; size_t pos; uint32_t i; uint8_t C[4]; /* Sanity check for I2OSP function. */ assert(((buflen - 1) / 32) <= UINT32_MAX); /* Iterate through the buffer. */ for (pos = 0; pos < buflen; pos += 32) { /* The ith block starts at position i * 32. */ i = (uint32_t)(pos / 32); /* Convert counter to big-endian format. */ be32enc(C, i); /* Compute the hash of (seed || C). */ if (crypto_hash_data_2(CRYPTO_KEY_HMAC_SHA256, seed, seedlen, C, 4, hbuf)) { warn0("Programmer error: " "SHA256 should never fail"); abort(); } /* Copy as much data as needed. */ if (buflen - pos > 32) memcpy(buf + pos, hbuf, 32); else memcpy(buf + pos, hbuf, buflen - pos); } }
/** * crypto_dh_compute(pub, priv, key): * In the Diffie-Hellman group #14, compute ${pub}^(2^258 + ${priv}) and * write the result into ${key}. All values are big-endian. Note that the * value ${pub} is the public key produced by the call to crypto_dh_generate * made by the *other* participant in the key exchange. */ int crypto_dh_compute(const uint8_t pub[CRYPTO_DH_PUBLEN], const uint8_t priv[CRYPTO_DH_PRIVLEN], uint8_t key[CRYPTO_DH_KEYLEN]) { BIGNUM * a; /* Convert ${pub} into BN representation. */ if ((a = BN_bin2bn(pub, CRYPTO_DH_PUBLEN, NULL)) == NULL) { warn0("%s", ERR_error_string(ERR_get_error(), NULL)); goto err0; } /* Compute key = pub^(2^258 + priv). */ if (blinded_modexp(key, a, priv)) goto err1; /* Free storage allocated by BN_bin2bn. */ BN_free(a); /* Success! */ return (0); err1: BN_free(a); err0: /* Failure! */ return (-1); }
int main(int argc, char * argv[]) { struct sock_addr ** sas; uintmax_t N; int s; struct wire_requestqueue * Q; WARNP_INIT; /* Check number of arguments. */ if (argc != 3) { fprintf(stderr, "usage: hotspot_read %s N\n", "<socketname>"); exit(1); } /* Parse N. */ if ((N = strtoumax(argv[2], NULL, 0)) == 0) { warnp("Invalid value for N: %s", argv[2]); exit(1); } /* Resolve the socket address and connect. */ if ((sas = sock_resolve(argv[1])) == NULL) { warnp("Error resolving socket address: %s", argv[1]); exit(1); } if (sas[0] == NULL) { warn0("No addresses found for %s", argv[1]); exit(1); } if ((s = sock_connect(sas)) == -1) exit(1); /* Create a request queue. */ if ((Q = wire_requestqueue_init(s)) == NULL) { warnp("Cannot create packet write queue"); exit(1); } /* Start issuing hotspot read requests. */ if (hotspotread(Q, N)) exit(1); /* Free the request queue. */ wire_requestqueue_destroy(Q); wire_requestqueue_free(Q); /* Free socket addresses. */ sock_addr_freelist(sas); /* Shut down the event subsystem. */ events_shutdown(); /* Success! */ exit(0); }
/** * callback_file(cookie, buf, buflen): * Handle a chunk ${buf} of length ${buflen} from a file which is being * written to the tape associated with the multitape write cookie ${cookie}. */ static int callback_file(void * cookie, uint8_t * buf, size_t buflen) { struct multitape_write_internal * d = cookie; struct chunkheader ch; /* Data is being passed out by c_file. */ d->c_file_out += buflen; /* Anything under MINCHUNK bytes belongs in the trailer stream. */ if (buflen < MINCHUNK) { /* There shouldn't be any trailer yet. */ if (d->tlen != 0) { warn0("Archive entry has two trailers?"); goto err0; } /* Write to the trailer stream. */ if (chunkify_write(d->t.c, buf, buflen)) goto err0; /* Record the trailer length. */ d->tlen = buflen; /* Call the trailer callback, if one exists. */ if ((d->callback_trailer != NULL) && (d->callback_trailer)(d->callback_cookie, buf, buflen)) goto err0; } else { /* Store the chunk. */ if (store_chunk(buf, buflen, &ch, d->C)) goto err0; /* Write chunk header to chunk index stream. */ if (chunkify_write(d->c.c, (uint8_t *)(&ch), sizeof(struct chunkheader))) goto err0; /* Record the chunkified data length. */ d->clen += buflen; /* Call the chunk callback, if one exists. */ if ((d->callback_chunk != NULL) && (d->callback_chunk)(d->callback_cookie, &ch)) goto err0; } /* Success! */ return (0); err0: /* Failure! */ return (-1); }
int main(int argc, char * argv[]) { struct sock_addr ** sas; int s; struct wire_requestqueue * Q; WARNP_INIT; /* Check number of arguments. */ if (argc != 2) { fprintf(stderr, "usage: bulk_insert %s\n", "<socketname>"); exit(1); } /* Resolve the socket address and connect. */ if ((sas = sock_resolve(argv[1])) == NULL) { warnp("Error resolving socket address: %s", argv[1]); exit(1); } if (sas[0] == NULL) { warn0("No addresses found for %s", argv[1]); exit(1); } if ((s = sock_connect(sas)) == -1) exit(1); /* Create a request queue. */ if ((Q = wire_requestqueue_init(s)) == NULL) { warnp("Cannot create packet write queue"); exit(1); } /* Start bulk inserting. */ if (bulkinsert(Q, stdin)) exit(1); /* Free the request queue. */ wire_requestqueue_destroy(Q); wire_requestqueue_free(Q); /* Free socket addresses. */ sock_addr_freelist(sas); /* Shut down the event subsystem. */ events_shutdown(); /* Success! */ exit(0); }
/** * tsnetwork_read(fd, buf, buflen, to0, to1, callback, cookie): * Asynchronously fill the provided buffer with data from ${fd}, and call * callback(cookie, status) where status is a NETWORK_STATUS_* value. Time * out if no data can be read for a period of time to0, or if the complete * buffer has not been read after time to1. Note that ${buflen} must be * non-zero, since otherwise deadlock would result. */ int tsnetwork_read(int fd, uint8_t * buf, size_t buflen, struct timeval * to0, struct timeval * to1, network_callback * callback, void * cookie) { /* Make sure buflen is non-zero. */ if (buflen == 0) { warn0("Cannot read zero-byte buffer"); return (-1); } return (network_buf(fd, buf, buflen, to0, to1, callback, cookie, recv, NETWORK_OP_READ, 0)); }
/** * callback_print(cookie, ch): * Call chunks_stats_addchunk on the chunk stats cookie ${cookie} and the * chunk header ${ch}. */ static int callback_print(void * cookie, struct chunkheader * ch) { CHUNKS_S * C = cookie; size_t len, zlen; int rc; /* Decode chunk header. */ len = le32dec(ch->len); zlen = le32dec(ch->zlen); if ((rc = chunks_stats_addchunk(C, ch->hash, len, zlen)) == 1) { warn0("Directory is not consistent with archive: Run --fsck"); rc = -1; } /* Return status. */ return (rc); }
bool random_get(uint8_t *buffer, size_t buffer_len) { FILE *frand = fopen(CANDADO_RANDOM_DEV, "r"); if (!frand) { warn0("%s", CANDADO_RANDOM_DEV); goto err0; } if (fread(buffer, 1, buffer_len, frand) < buffer_len) goto err1; fclose(frand); return true; err1: fclose(frand); err0: return false; }
/** * storage_util_unlock(S): * Release the lock on the storage state ${S}. */ int storage_util_unlock(struct storage_state * S) { int rc; /* Try to release the lock. */ if ((rc = pthread_rwlock_unlock(&S->lck)) != 0) { warn0("pthread_rwlock_unlock: %s", strerror(rc)); goto err0; } /* Success! */ return (0); err0: /* Failure! */ return (-1); }
static int found(void * cookie, struct sock_addr ** sas) { char * addr; int i; (void)cookie; /* UNUSED */ /* Sanity check. */ if (sas == NULL) goto err0; /* Print each address. */ for (i = 0; i < MAX_ADDRS; i++) { if (sas[i] == NULL) break; /* Extract address and print it. */ if ((addr = sock_addr_prettyprint(sas[i])) == NULL) { warn0("sock_addr_prettyprint()"); goto err1; } printf("%s\n", addr); /* Clean up. */ free(addr); } /* Clean up. */ sock_addr_freelist(sas); /* Quit event loop. */ doneloop = 1; /* Success! */ return (0); err1: sock_addr_freelist(sas); err0: /* Failure! */ return (-1); }
static int callback_reconnect(void * cookie, int status) { struct netpacket_internal * NPC = cookie; uint64_t in, out, queued; /* If we're being cancelled, return. */ if (status == NETWORK_STATUS_CANCEL) goto done; /* The status should be NETWORK_STATUS_TIMEOUT. */ if (status != NETWORK_STATUS_TIMEOUT) { warn0("Bad status in callback_reconnect: %d", status); goto err0; } /* Add the bandwidth used by the connection to our running totals. */ netproto_getstats(NPC->NC, &in, &out, &queued); NPC->bytesin += in; NPC->bytesout += out; /* Close the (dead) connection. */ if (netproto_close(NPC->NC)) goto err1; NPC->NC = NULL; /* Open a new connection. */ if ((NPC->NC = netproto_connect(NPC->useragent, callback_connect, NPC)) == NULL) goto err0; done: /* Success! */ return (0); err1: NPC->NC = NULL; err0: /* Failure! */ return (-1); }
/** * sock_connect(sas): * Iterate through the addresses in ${sas}, attempting to create a socket and * connect (blockingly). Once connected, stop iterating, mark the socket as * non-blocking, and return it. */ int sock_connect(struct sock_addr * const * sas) { int s = -1; /* Iterate through the addresses provided. */ for (; sas[0] != NULL; sas++) { /* Create a socket. */ if ((s = socket(sas[0]->ai_family, sas[0]->ai_socktype, 0)) == -1) continue; /* Attempt to connect. */ if (connect(s, sas[0]->name, sas[0]->namelen) == 0) break; /* Close the socket; this address didn't work. */ close(s); } /* Did we manage to connect? */ if (sas[0] == NULL) { warn0("Could not connect"); goto err0; } /* Mark the socket as non-blocking. */ if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) { warnp("Cannot make connection non-blocking"); goto err1; } /* Success! */ return (s); err1: close(s); err0: /* Failure! */ return (-1); }
/** * crypto_keys_subr_import_HMAC(key, buf, buflen): * Import the specified HMAC key from the provided buffer. */ int crypto_keys_subr_import_HMAC(struct crypto_hmac_key ** key, const uint8_t * buf, size_t buflen) { /* Free any existing key. */ if (*key != NULL) { free((*key)->key); free(*key); } /* Make sure the buffer is the right length. */ if (buflen != 32) { warn0("Incorrect HMAC key size: %zu", buflen); goto err0; } /* Allocate key structure. */ if ((*key = malloc(sizeof(struct crypto_hmac_key))) == NULL) goto err0; /* Allocate key buffer. */ if (((*key)->key = malloc(buflen)) == NULL) goto err1; /* Copy key data and length. */ (*key)->len = buflen; memcpy((*key)->key, buf, buflen); /* Success! */ return (0); err1: free(*key); *key = NULL; err0: /* Failure! */ return (-1); }
/** * tapepresent(S, fmt, s): * Return 1 if an archive exists with the name sprintf(fmt, s), or 0 * otherwise. */ static int tapepresent(STORAGE_W * S, const char * fmt, const char * s) { char * tapename; /* Generate name. */ if (asprintf(&tapename, fmt, s) == -1) goto err0; /* Make sure that there isn't already a tape with this name. */ switch (multitape_metadata_ispresent(S, tapename)) { case 1: /* File exists. */ warn0("An archive already exists with the name \"%s\"", tapename); goto eexist; case -1: /* Something went wrong. */ goto err1; } /* Free string allocated by asprintf. */ free(tapename); /* Nothing is in the way. */ return (0); eexist: free(tapename); /* Something is in the way. */ return (1); err1: free(tapename); err0: /* Failure! */ return (-1); }
/** * writetape_setmode(d, mode): * Set the tape mode to 0 (HEADER) or 1 (DATA). */ int writetape_setmode(TAPE_W * d, int mode) { if (mode == d->mode) goto done; /* If we were in DATA mode, end the current file chunk. */ if (d->mode == 1) { if (chunkify_end(d->c_file)) goto err0; } /* If we have written an archive trailer, we can't change the mode. */ if (d->mode == 3) { warn0("Programmer error: " "Archive entry occurs after archive trailer."); goto err0; } /* If the entry is ending, write to the header stream. */ if (mode == 2) { if (endentry(d)) goto err0; } /* Record the new mode. */ d->mode = mode; done: /* Success! */ return (0); err0: /* Failure! */ return (-1); }
/* Callback for btree_sync when write is complete. */ static int callback_append(void * cookie, int failed, int status, uint64_t blkno) { struct write_cookie * WC = cookie; struct btree * T = WC->T; /* Throw a fit if we didn't manage to write the pages. */ if (failed) goto err1; if (status) { warn0("Failed to write dirty nodes to backing store"); goto err1; } /* Record the next available block number. */ T->nextblk = blkno; /* Mark the nodes in the dirty tree as clean. */ makeclean(T, T->root_dirty); /* * Make sure no callbacks are pending on the shadow tree before we * garbage collect it. */ if (!events_immediate_register(callback_unshadow, WC, 1)) goto err1; /* Success! */ return (0); err1: free(WC); /* Failure! */ return (-1); }
/** * crypto_aes_key_expand_aesni(key, len): * Expand the ${len}-byte AES key ${key} into a structure which can be passed * to crypto_aes_encrypt_block_aesni. The length must be 16 or 32. This * implementation uses x86 AESNI instructions, and should only be used if * CPUSUPPORT_X86_AESNI is defined and cpusupport_x86_aesni() returns nonzero. */ void * crypto_aes_key_expand_aesni(const uint8_t * key, size_t len) { struct crypto_aes_key_aesni * kexp; size_t rkey_offset; /* Allocate structure. */ if ((kexp = malloc(sizeof(struct crypto_aes_key_aesni))) == NULL) goto err0; /* Figure out where to put the round keys. */ rkey_offset = (uintptr_t)(&kexp->rkeys_buf[0]) % sizeof(__m128i); rkey_offset = (sizeof(__m128i) - rkey_offset) % sizeof(__m128i); kexp->rkeys = (void *)&kexp->rkeys_buf[rkey_offset]; /* Compute round keys. */ if (len == 16) { kexp->nr = 10; crypto_aes_key_expand_128_aesni(key, kexp->rkeys); } else if (len == 32) { kexp->nr = 14; crypto_aes_key_expand_256_aesni(key, kexp->rkeys); } else { warn0("Unsupported AES key length: %zu bytes", len); goto err1; } /* Success! */ return (kexp); err1: free(kexp); err0: /* Failure! */ return (NULL); }
/** * storage_done(S): * Free the storage state data ${S}. */ int storage_done(struct storage_state * S) { int rc; /* Destroy the lock on the storage state. */ if ((rc = pthread_rwlock_destroy(&S->lck)) != 0) { warn0("pthread_rwlock_destroy: %s", strerror(rc)); goto err0; } /* Free the queue of file state structures. */ elasticqueue_free(S->files); /* Free the storage state. */ free(S); /* Success! */ return (0); err0: /* Failure! */ return (-1); }
/** * events_network_cancel(s, op): * Cancel the event registered for the socket/operation pair ${s}/${op}. If * there is no such registration, errno will be set to ENOENT and the * function will fail. */ int events_network_cancel(int s, int op) { struct eventrec ** r; /* Initialize if necessary. */ if (initsocketlist()) goto err0; /* Sanity-check socket number. */ if ((s < 0) || (s >= (int)FD_SETSIZE)) { warn0("Invalid file descriptor for network event: %d", s); goto err0; } /* Sanity-check operation. */ if ((op != EVENTS_NETWORK_OP_READ) && (op != EVENTS_NETWORK_OP_WRITE)) { warn0("Invalid operation for network event: %d", op); goto err0; } /* We have no events registered beyond the end of the array. */ if ((size_t)(s) >= socketlist_getsize(S)) { errno = ENOENT; goto err0; } /* Look up the relevant event pointer. */ if (op == EVENTS_NETWORK_OP_READ) r = &socketlist_get(S, s)->reader; else r = &socketlist_get(S, s)->writer; /* Check if we have an event. */ if (*r == NULL) { errno = ENOENT; goto err0; } /* Free the event. */ events_freerec(*r); *r = NULL; /* * Since there is no longer an event registered for this socket / * operation pair, it doesn't make any sense for it to be ready. */ if (op == EVENTS_NETWORK_OP_READ) FD_CLR(s, &readfds); else FD_CLR(s, &writefds); /* * Decrement events-registered counter; and if it is becoming zero, * stop the inter-select duration clock. */ if (--nev == 0) events_network_selectstats_stopclock(); /* Success! */ return (0); err0: /* Failure! */ return (-1); }
/** * chunks_directory_read(cachepath, dir, stats_unique, stats_all, stats_extra, * mustexist, statstape): * Read stats_extra statistics (statistics on non-chunks which are stored) * and the chunk directory (if present) from "${cachepath}/directory" into * memory allocated and assigned to ${*dir}; and return a hash table * populated with struct chunkdata records. Populate stats_all with * statistics for all the chunks listed in the directory (counting * multiplicity) and populate stats_unique with statistics reflecting the * unique chunks. If ${mustexist}, error out if the directory does not exist. * If ${statstape}, allocate struct chunkdata_statstape records instead. */ RWHASHTAB * chunks_directory_read(const char * cachepath, void ** dir, struct chunkstats * stats_unique, struct chunkstats * stats_all, struct chunkstats * stats_extra, int mustexist, int statstape) { struct chunkdata_external che; struct chunkstats_external cse; struct stat sb; RWHASHTAB * HT; char * s; struct chunkdata * p = NULL; struct chunkdata_statstape * ps = NULL; FILE * f; size_t numchunks; /* Zero statistics. */ chunks_stats_zero(stats_unique); chunks_stats_zero(stats_all); chunks_stats_zero(stats_extra); /* Create a hash table to hold the chunkdata structures. */ HT = rwhashtab_init(offsetof(struct chunkdata, hash), 32); if (HT == NULL) goto err0; /* Construct the string "${cachepath}/directory". */ if (asprintf(&s, "%s/directory", cachepath) == -1) { warnp("asprintf"); goto err1; } if (stat(s, &sb)) { /* Could not stat ${cachepath}/directory. Error? */ if (errno != ENOENT) { warnp("stat(%s)", s); goto err2; } /* The directory doesn't exist; complain if mustexist != 0. */ if (mustexist) { warn0("Error reading cache directory from %s", cachepath); goto err2; } /* * ${cachepath}/directory does not exist; set ${*dir} to NULL * and return the empty hash table. */ free(s); *dir = NULL; return (HT); } /* * Make sure the directory file isn't too large or too small, in * order to avoid any possibility of integer overflows. */ if ((sb.st_size < 0) || ((sizeof(off_t) > sizeof(size_t)) && (sb.st_size > SIZE_MAX))) { warn0("on-disk directory has insane size (%jd bytes): %s", (intmax_t)(sb.st_size), s); goto err2; } /* Make sure the number of chunks is an integer. */ if ((size_t)(sb.st_size - sizeof(struct chunkstats_external)) % (sizeof(struct chunkdata_external))) { warn0("on-disk directory is corrupt: %s", s); goto err2; } /* Compute the number of on-disk chunks. */ numchunks = (size_t)(sb.st_size - sizeof(struct chunkstats_external)) / sizeof(struct chunkdata_external); /* Make sure we don't get an integer overflow. */ if (numchunks >= SIZE_MAX / sizeof(struct chunkdata_statstape)) { warn0("on-disk directory is too large: %s", s); goto err2; } /* * Allocate memory to ${*dir} large enough to store a struct * chunkdata or struct chunkdata_statstape for each struct * chunkdata_external in ${cachepath}/directory. */ if (statstape) { ps = malloc(numchunks * sizeof(struct chunkdata_statstape)); *dir = ps; } else { p = malloc(numchunks * sizeof(struct chunkdata)); *dir = p; } if (*dir == NULL) goto err2; /* Open the directory file. */ if ((f = fopen(s, "r")) == NULL) { warnp("fopen(%s)", s); goto err3; } /* Read the extra files statistics. */ if (fread(&cse, sizeof(cse), 1, f) != 1) { warnp("fread(%s)", s); goto err4; } stats_extra->nchunks = le64dec(cse.nchunks); stats_extra->s_len = le64dec(cse.s_len); stats_extra->s_zlen = le64dec(cse.s_zlen); /* Read the chunk structures. */ for (; numchunks != 0; numchunks--) { /* Set p to point at the struct chunkdata. */ if (statstape) p = &ps->d; /* Read the file one record at a time... */ if (fread(&che, sizeof(che), 1, f) != 1) { warnp("fread(%s)", s); goto err4; } /* ... creating struct chunkdata records... */ memcpy(p->hash, che.hash, 32); p->len = le32dec(che.len); p->zlen_flags = le32dec(che.zlen); p->nrefs = le32dec(che.nrefs); p->ncopies = le32dec(che.ncopies); /* ... inserting them into the hash table... */ if (rwhashtab_insert(HT, p)) goto err4; /* ... and updating the statistics. */ chunks_stats_add(stats_unique, p->len, p->zlen_flags, 1); chunks_stats_add(stats_all, p->len, p->zlen_flags, p->ncopies); /* Sanity check. */ if ((p->len == 0) || (p->zlen_flags == 0) || (p->nrefs == 0)) { warn0("on-disk directory is corrupt: %s", s); goto err4; } /* Move to next record. */ if (statstape) ps++; else p++; } if (fclose(f)) { warnp("fclose(%s)", s); goto err3; } /* Free string allocated by asprintf. */ free(s); /* Success! */ return (HT); err4: fclose(f); err3: free(*dir); err2: free(s); err1: rwhashtab_free(HT); err0: /* Failure! */ return (NULL); }
/** * archive_multitape_copy(ina, read_cookie, a, write_cookie) * Copy the data for an entry from one archive to another. */ int archive_multitape_copy(struct archive * ina, void * read_cookie, struct archive * a, void * write_cookie) { char buff[64*1024]; struct chunkheader * ch; ssize_t lenread; ssize_t writelen; off_t entrylen; ssize_t backloglen; /* Compute the entry size. */ if ((entrylen = archive_read_get_entryleft(ina)) < 0) { archive_set_error(ina, ENOSYS, "read_get_entryleft not supported"); return (-2); } /* Copy data. */ while (entrylen > 0) { /* Is there data buffered by libarchive? */ if ((backloglen = archive_read_get_backlog(ina)) < 0) { warn0("Error reading libarchive data backlog"); return (-2); } if (backloglen > 0) { /* Drain some data from libarchive. */ if ((size_t)backloglen > sizeof(buff)) lenread = sizeof(buff); else lenread = backloglen; lenread = archive_read_data(ina, buff, lenread); if (lenread == 0) { warn0("libarchive claims data backlog," " but no data can be read?"); return (-2); } if (lenread < 0) return (-2); /* Write it out to the new archive. */ writelen = archive_write_data(a, buff, lenread); if (writelen < lenread) return (-1); /* Adjust the remaining entry length and continue. */ entrylen -= lenread; continue; } /* Attempt to read a chunk for fast-pathing. */ lenread = readtape_readchunk(read_cookie, &ch); if (lenread < 0) return (-2); if (lenread > entrylen) { warn0("readchunk returned chunk beyond end" " of archive entry?"); return (-2); } if (lenread == 0) goto nochunk; /* Attempt to write the chunk via the fast path. */ writelen = writetape_writechunk(write_cookie, ch); if (writelen < 0) return (-1); if (writelen == 0) goto nochunk; if (writelen != lenread) { warn0("chunk write size != chunk read size?"); return (-1); } /* * Advance libarchive pointers. Do the write pointer * first since a failure there is fatal. */ if (archive_write_skip(a, writelen)) return (-1); if (archive_read_advance(ina, lenread)) return (-2); /* We don't need to see this chunk again. */ if (readtape_skip(read_cookie, lenread) != lenread) { warn0("could not skip read data?"); return (-2); } /* We've done part of the entry. */ entrylen -= lenread; continue; nochunk: /* * We have no data buffered in libarchive, and we can't copy * an intact chunk. We need to read some data, but we have * no idea how much the multitape layer wants to provide to * libarchive next; and we don't want to read too much data * since we might waste time reading and writing chunked data * which could be fast-pathed. Simple solution: Read and * write one byte. Libarchive will almost certainly get more * than one byte from the multitape layer, but when we return * to the start of this loop and handle backlogged data we * will pick up the rest of the data. (Also, this is always * where we end up when we hit the end of an archive entry, * in which case archive_read_data returns 0 and we exit the * loop.) */ lenread = archive_read_data(ina, buff, 1); if (lenread == 0) break; if (lenread < 0) return (-2); writelen = archive_write_data(a, buff, 1); if (writelen < 1) return (-1); }; return (0); }
int main(int argc, char *argv[]) { FILE * infile; FILE * outfile; int dec = 0; size_t maxmem = 0; double maxmemfrac = 0.5; double maxtime = 300.0; const char * ch; char * passwd; int rc; int verbose = 0; WARNP_INIT; /* We should have "enc" or "dec" first. */ if (argc < 2) usage(); if (strcmp(argv[1], "enc") == 0) { maxmem = 0; maxmemfrac = 0.125; maxtime = 5.0; } else if (strcmp(argv[1], "dec") == 0) { dec = 1; } else usage(); argc--; argv++; /* Parse arguments. */ while ((ch = GETOPT(argc, argv)) != NULL) { GETOPT_SWITCH(ch) { GETOPT_OPTARG("-M"): maxmem = strtoumax(optarg, NULL, 0); break; GETOPT_OPTARG("-m"): maxmemfrac = strtod(optarg, NULL); break; GETOPT_OPTARG("-t"): maxtime = strtod(optarg, NULL); break; GETOPT_OPT("-v"): verbose = 1; break; GETOPT_MISSING_ARG: warn0("Missing argument to %s\n", ch); /* FALLTHROUGH */ GETOPT_DEFAULT: usage(); } } argc -= optind; argv += optind; /* We must have one or two parameters left. */ if ((argc < 1) || (argc > 2)) usage(); /* If the input isn't stdin, open the file. */ if (strcmp(argv[0], "-")) { if ((infile = fopen(argv[0], "rb")) == NULL) { warnp("Cannot open input file: %s", argv[0]); exit(1); } } else { infile = stdin; } /* If we have an output file, open it. */ if (argc > 1) { if ((outfile = fopen(argv[1], "wb")) == NULL) { warnp("Cannot open output file: %s", argv[1]); exit(1); } } else { outfile = stdout; } /* Prompt for a password. */ if (readpass(&passwd, "Please enter passphrase", dec ? NULL : "Please confirm passphrase", 1)) exit(1); /* Encrypt or decrypt. */ if (dec) rc = scryptdec_file(infile, outfile, (uint8_t *)passwd, strlen(passwd), maxmem, maxmemfrac, maxtime, verbose); else rc = scryptenc_file(infile, outfile, (uint8_t *)passwd, strlen(passwd), maxmem, maxmemfrac, maxtime, verbose); /* Zero and free the password. */ insecure_memzero(passwd, strlen(passwd)); free(passwd); /* Close any files we opened. */ if (infile != stdin) fclose(infile); if (outfile != stdout) fclose(outfile); /* If we failed, print the right error message and exit. */ if (rc != 0) { switch (rc) { case 1: warnp("Error determining amount of available memory"); break; case 2: warnp("Error reading clocks"); break; case 3: warnp("Error computing derived key"); break; case 4: warnp("Error reading salt"); break; case 5: warnp("OpenSSL error"); break; case 6: warnp("Error allocating memory"); break; case 7: warn0("Input is not valid scrypt-encrypted block"); break; case 8: warn0("Unrecognized scrypt format version"); break; case 9: warn0("Decrypting file would require too much memory"); break; case 10: warn0("Decrypting file would take too much CPU time"); break; case 11: warn0("Passphrase is incorrect"); break; case 12: warnp("Error writing file: %s", (argc > 1) ? argv[1] : "standard output"); break; case 13: warnp("Error reading file: %s", argv[0]); break; } exit(1); } return (0); }
static int multitape_metadata_get(STORAGE_R * S, CHUNKS_S * C, struct tapemetadata * mdat, const uint8_t tapehash[32], const char * tapename, int quiet) { uint8_t hbuf[32]; uint8_t * mbuf; size_t mdlen; /* Read the tape metadata. */ switch (storage_read_file_alloc(S, &mbuf, &mdlen, 'm', tapehash)) { case -1: /* Internal error. */ goto err1; case 1: /* ENOENT. */ goto notpresent; case 2: /* Corrupt metadata file. */ goto corrupt; } /* Adjust chunk statistics. */ if (C != NULL) chunks_stats_extrastats(C, mdlen); /* Parse the tape metadata. */ switch (multitape_metadata_dec(mdat, mbuf, mdlen)) { case 1: /* Metadata is corrupt. */ goto corrupt1; case -1: /* Error. */ goto err2; } /* Store metadata length. */ mdat->metadatalen = mdlen; /* Free tape metadata. */ free(mbuf); /* * Make sure the name stored in the archive metadata matches the * name of the metadata file. */ if (crypto_hash_data(CRYPTO_KEY_HMAC_NAME, (uint8_t *)mdat->name, strlen(mdat->name), hbuf)) goto err0; if (crypto_verify_bytes(tapehash, hbuf, 32)) goto corrupt; /* Success! */ return (0); corrupt1: free(mbuf); corrupt: if (quiet == 0) { if (tapename) warn0("Archive metadata is corrupt: %s", tapename); else warn0("Archive metadata file is corrupt"); } /* File is corrupt. */ return (2); notpresent: if (quiet == 0) { if (tapename) warn0("Archive does not exist: %s", tapename); else warn0("Cannot read archive metadata file"); } /* ENOENT. */ return (1); err2: free(mbuf); err1: warnp("Error reading archive metadata"); err0: /* Failure! */ return (-1); }