diff --git a/main.cpp b/main.cpp index dc4d972..b81a0e6 100644 --- a/main.cpp +++ b/main.cpp @@ -117,7 +117,7 @@ int main(int argc, char **argv) { cc::clibrary::pclsync_lib::get_lib().set_username(username); if (passwordsw) { - cc::clibrary::pclsync_lib::get_lib().get_pass_from_console(); + cc::clibrary::pclsync_lib::get_lib().read_password(); } cc::clibrary::pclsync_lib::get_lib().set_tfa_code(tfa_code); cc::clibrary::pclsync_lib::get_lib().set_trusted_device(trusted_device); @@ -127,7 +127,7 @@ int main(int argc, char **argv) { cc::clibrary::pclsync_lib::get_lib().set_crypto_pass(password); } else { std::cout << "Enter crypto password." << std::endl; - cc::clibrary::pclsync_lib::get_lib().get_cryptopass_from_console(); + cc::clibrary::pclsync_lib::get_lib().read_cryptopass(); } } else cc::clibrary::pclsync_lib::get_lib().setup_crypto_ = false; diff --git a/pclsync/pcrypto.c b/pclsync/pcrypto.c index d407299..a779863 100644 --- a/pclsync/pcrypto.c +++ b/pclsync/pcrypto.c @@ -36,7 +36,6 @@ #include #include -#include "pfile.h" #include "pcompiler.h" #include "pssl.h" @@ -68,7 +67,7 @@ static void psync_hmac_sha512_init(psync_hmac_sha512_ctx *ctx, } psync_sha512_init(&ctx->sha1ctx); psync_sha512_update(&ctx->sha1ctx, keyxor, PSYNC_SHA512_BLOCK_LEN); - pssl_memclean(keyxor, PSYNC_SHA512_BLOCK_LEN); + putil_wipe(keyxor, PSYNC_SHA512_BLOCK_LEN); } static void psync_hmac_sha512_update(psync_hmac_sha512_ctx *ctx, @@ -81,7 +80,7 @@ static void psync_hmac_sha512_final(unsigned char *result, psync_sha512_final(ctx->final + PSYNC_SHA512_BLOCK_LEN, &ctx->sha1ctx); psync_sha512(ctx->final, PSYNC_SHA512_BLOCK_LEN + PSYNC_SHA512_DIGEST_LEN, result); - pssl_memclean(ctx->final, + putil_wipe(ctx->final, PSYNC_SHA512_BLOCK_LEN + PSYNC_SHA512_DIGEST_LEN); } @@ -107,8 +106,8 @@ static void psync_hmac_sha512(const unsigned char *msg, size_t msglen, psync_sha512_update(&sha1ctx, msg, msglen); psync_sha512_final(final + PSYNC_SHA512_BLOCK_LEN, &sha1ctx); psync_sha512(final, PSYNC_SHA512_BLOCK_LEN + PSYNC_SHA512_DIGEST_LEN, result); - pssl_memclean(keyxor, PSYNC_SHA512_BLOCK_LEN); - pssl_memclean(final, PSYNC_SHA512_BLOCK_LEN + PSYNC_SHA512_DIGEST_LEN); + putil_wipe(keyxor, PSYNC_SHA512_BLOCK_LEN); + putil_wipe(final, PSYNC_SHA512_BLOCK_LEN + PSYNC_SHA512_DIGEST_LEN); } #define ALIGN_A256_BS(n) \ @@ -193,7 +192,7 @@ pcrypto_ctr_encdec_t pcrypto_ctr_encdec_create(psync_symmetric_key_t key) { void pcrypto_ctr_encdec_free( pcrypto_ctr_encdec_t enc) { paes_free_encoder(enc->encoder); - pssl_memclean(enc->iv, PSYNC_AES256_BLOCK_SIZE); + putil_wipe(enc->iv, PSYNC_AES256_BLOCK_SIZE); psync_free(enc); } @@ -419,7 +418,7 @@ pcrypto_textenc_create(psync_symmetric_key_t key) { void pcrypto_textenc_free( pcrypto_textenc_t enc) { paes_free_encoder(enc->encoder); - pssl_memclean(enc->iv, enc->ivlen); + putil_wipe(enc->iv, enc->ivlen); pmemlock_free(enc); } @@ -445,7 +444,7 @@ pcrypto_textdec_create(psync_symmetric_key_t key) { void pcrypto_textdec_free( pcrypto_textdec_t enc) { paes_free_encoder(enc->encoder); - pssl_memclean(enc->iv, enc->ivlen); + putil_wipe(enc->iv, enc->ivlen); pmemlock_free(enc); } @@ -478,7 +477,7 @@ void pcrypto_sec_encdec_free( pcrypto_sector_encdec_t enc) { paes_free_encoder(enc->encoder); paes_free_decoder(enc->decoder); - pssl_memclean(enc->iv, enc->ivlen); + putil_wipe(enc->iv, enc->ivlen); pmemlock_free(enc); } diff --git a/pclsync/pcryptofolder.c b/pclsync/pcryptofolder.c index d51a142..72d6796 100644 --- a/pclsync/pcryptofolder.c +++ b/pclsync/pcryptofolder.c @@ -271,6 +271,7 @@ static int download_keys(unsigned char **rsapriv, size_t *rsaprivlen, unsigned c break; default: def1: + putil_wipe(rsaprivstruct, rsaprivstructlen); psync_free(rsaprivstruct); psync_free(rsapubstruct); return PRINT_RETURN_CONST(PSYNC_CRYPTO_START_UNKNOWN_KEY_FORMAT); @@ -292,10 +293,12 @@ static int download_keys(unsigned char **rsapriv, size_t *rsaprivlen, unsigned c default: def2: psync_free(*rsapub); + putil_wipe(rsaprivstruct, rsaprivstructlen); psync_free(rsaprivstruct); psync_free(rsapubstruct); return PRINT_RETURN_CONST(PSYNC_CRYPTO_START_UNKNOWN_KEY_FORMAT); } + putil_wipe(rsaprivstruct, rsaprivstructlen); psync_free(rsaprivstruct); psync_free(rsapubstruct); return PSYNC_CRYPTO_START_SUCCESS; @@ -591,6 +594,7 @@ int pcryptofolder_unlock(const char *password) { if (unlikely(rowcnt != 0)) { debug(D_BUG, "only some of records found in the database, should not happen"); + putil_wipe(rsapriv, rsaprivlen); psync_free(rsapriv); psync_free(rsapub); psync_free(salt); @@ -614,8 +618,10 @@ int pcryptofolder_unlock(const char *password) { if (crypto_pubkey == PSYNC_INVALID_RSA) { pthread_rwlock_unlock(&crypto_lock); debug(D_WARNING, "could not load public key"); + putil_wipe(rsapriv, rsaprivlen); psync_free(rsapriv); psync_free(rsapub); + putil_wipe(salt, saltlen); psync_free(salt); return PRINT_RETURN_CONST(PSYNC_CRYPTO_START_UNKNOWN_KEY_FORMAT); } @@ -634,15 +640,17 @@ int pcryptofolder_unlock(const char *password) { debug(D_NOTICE, "trying to load private key"); crypto_privkey = prsa_load_private(rsaprivdec, rsaprivlen); - pssl_memclean(rsaprivdec, rsaprivlen); + putil_wipe(rsaprivdec, rsaprivlen); pmemlock_free(rsaprivdec); if (crypto_privkey == PSYNC_INVALID_RSA) { debug(D_NOTICE, "failed to load private key"); prsa_free_public(crypto_pubkey); crypto_pubkey = PSYNC_INVALID_RSA; pthread_rwlock_unlock(&crypto_lock); + putil_wipe(rsapriv, rsaprivlen); psync_free(rsapriv); psync_free(rsapub); + putil_wipe(salt, saltlen); psync_free(salt); return PRINT_RETURN_CONST(PSYNC_CRYPTO_START_BAD_PASSWORD); } @@ -656,8 +664,10 @@ int pcryptofolder_unlock(const char *password) { crypto_privkey = PSYNC_INVALID_RSA; pthread_rwlock_unlock(&crypto_lock); debug(D_ERROR, "keys don't match"); + putil_wipe(rsapriv, rsaprivlen); psync_free(rsapriv); psync_free(rsapub); + putil_wipe(salt, saltlen); psync_free(salt); return PRINT_RETURN_CONST(PSYNC_CRYPTO_START_KEYS_DONT_MATCH); } @@ -672,8 +682,10 @@ int pcryptofolder_unlock(const char *password) { salt, saltlen, iterations, 0, publicsha1, privatesha1, flags); } + putil_wipe(rsapriv, rsaprivlen); psync_free(rsapriv); psync_free(rsapub); + putil_wipe(salt, saltlen); psync_free(salt); debug(D_NOTICE, "crypto successfully started"); return PSYNC_CRYPTO_START_SUCCESS; @@ -1704,7 +1716,7 @@ char *pcryptofolder_filencoder_key_new(uint32_t flags, size_t *keylen) { debug(D_ERROR, "RSA encryption failed"); return (char *)errptr(PRINT_RETURN_CONST(PSYNC_CRYPTO_RSA_ERROR)); } - pssl_memclean(&sym, sizeof(sym)); + putil_wipe(&sym, sizeof(sym)); ret = (char *)psync_base64_encode(encsym->data, encsym->datalen, keylen); psync_free(encsym); return ret; @@ -1734,7 +1746,7 @@ char *pcryptofolder_filencoder_key_newplain( return (char *)errptr(PRINT_RETURN_CONST(PSYNC_CRYPTO_RSA_ERROR)); } *deckey = symkeyv1_to_symkey(&sym); - pssl_memclean(&sym, sizeof(sym)); + putil_wipe(&sym, sizeof(sym)); ret = (char *)psync_base64_encode(encsym->data, encsym->datalen, keylen); psync_free(encsym); return ret; @@ -1762,7 +1774,7 @@ int pcryptofolder_mkdir(psync_folderid_t folderid, const char *name, } encsym = prsa_encrypt_data(crypto_pubkey, (unsigned char *)&sym, sizeof(sym)); - pssl_memclean(&sym, sizeof(sym)); + putil_wipe(&sym, sizeof(sym)); ret = get_fldr_name(folderid, name, &ename, err); pthread_rwlock_unlock(&crypto_lock); if (ret) { @@ -1864,7 +1876,7 @@ int psync_pcloud_crypto_reencode_key( pcrypto_ctr_encdec_free(enc); newprivlen = offsetof(priv_key_ver1, key) + rsaprivlen; priv = prsa_load_private(rsaprivdec, rsaprivlen); - pssl_memclean(rsaprivdec, rsaprivlen); + putil_wipe(rsaprivdec, rsaprivlen); psync_free(rsaprivdec); if (unlikely(priv == PSYNC_INVALID_RSA)) goto err_ph_1; @@ -1954,6 +1966,7 @@ int psync_pcloud_crypto_encode_key(const char *newpassphrase, uint32_t flags, psync_sha256(newpriv, rsaprivlen, newprivsha); rsasign = prsa_sign_sha256_hash(crypto_privkey, newprivsha); if (is_err(rsasign)) { + putil_wipe(newpriv, rsaprivlen); psync_free(newpriv); prsa_free_binary(rsapriv); return to_err(rsasign); @@ -1961,6 +1974,7 @@ int psync_pcloud_crypto_encode_key(const char *newpassphrase, uint32_t flags, *privenc = (char *)psync_base64_encode(newpriv, rsaprivlen, &dummy); *sign = (char *)psync_base64_encode(rsasign->data, rsasign->datalen, &dummy); psync_free(rsasign); + putil_wipe(newpriv, rsaprivlen); psync_free(newpriv); prsa_free_binary(rsapriv); @@ -2017,6 +2031,7 @@ int pcryptofolder_change_pass(const char *oldpassphrase, memset(privatekey_struct, 0, offsetof(priv_key_ver1, key) + privkeylen); memcpy(privatekey_struct->key, privkey, privkeylen); privatekey_struct->type = PSYNC_CRYPTO_TYPE_RSA4096_64BYTESALT_20000IT; + putil_wipe(privkey, privkeylen); psync_free(privkey); } else if (!strcmp(id, "crypto_public_key")) { load_str_to(&row[1], &pubkey, &pubkeylen); @@ -2034,6 +2049,7 @@ int pcryptofolder_change_pass(const char *oldpassphrase, continue; } memcpy(privatekey_struct->salt, salt, saltlen); + putil_wipe(salt, saltlen); psync_free(salt); } } @@ -2081,7 +2097,9 @@ int pcryptofolder_change_pass(const char *oldpassphrase, pubkey, pubkeylen, privkey, privkeylen, oldpassphrase, newpassphrase, flags, privenc, sign); psync_free(pubkey); + putil_wipe(privkey, privkeylen); psync_free(privkey); + putil_wipe(salt, saltlen); psync_free(salt); if (cres) goto ex; @@ -2092,6 +2110,7 @@ int pcryptofolder_change_pass(const char *oldpassphrase, (unsigned char *)privatekey_struct, privkeylen + offsetof(priv_key_ver1, key), oldpassphrase, newpassphrase, flags, privenc, sign); + putil_wipe(privatekey_struct, privkeylen + offsetof(priv_key_ver1, key)); psync_free(privatekey_struct); psync_free(pubkey_struct); if (cres) diff --git a/pclsync/pnetlibs.c b/pclsync/pnetlibs.c index 1c6e273..a93f63d 100644 --- a/pclsync/pnetlibs.c +++ b/pclsync/pnetlibs.c @@ -2583,14 +2583,14 @@ int psync_get_upload_checksum(psync_uploadid_t uploadid, unsigned char *uhash, return PSYNC_NET_OK; } -void psync_logout2(uint32_t auth_status, int doinvauth); - -static void logout2_thread() { psync_logout2(PSTATUS_AUTH_BADTOKEN, 0); } +static void proc_logout() { + psync_logout(PSTATUS_AUTH_BADTOKEN, 0); +} // this is called when ANY api call returns non zero result void psync_process_api_error(uint64_t result) { if (result == 2000) - prun_thread("logout from process_api_error", logout2_thread); + prun_thread("logout from process_api_error", proc_logout); } static void psync_netlibs_timer(psync_timer_t timer, void *ptr) { diff --git a/pclsync/ppassword.c b/pclsync/ppassword.c index 704617c..8a471b2 100644 --- a/pclsync/ppassword.c +++ b/pclsync/ppassword.c @@ -39,6 +39,7 @@ #include "ppassword.h" #include "ppassworddict.h" #include "pssl.h" +#include "putil.h" #include #include @@ -351,8 +352,8 @@ uint64_t ppassword_score(const char *cpassword) { ldpwd[nlen] = lpwd[nlen]; } num = score_variants(password, lpwd, ldpwd, plen); - pssl_memclean(lpwd, plen); - pssl_memclean(ldpwd, plen); + putil_wipe(lpwd, plen); + putil_wipe(ldpwd, plen); psync_free(lpwd); psync_free(ldpwd); mul_score(num); diff --git a/pclsync/pssl.c b/pclsync/pssl.c index c9fa996..1b6bd88 100644 --- a/pclsync/pssl.c +++ b/pclsync/pssl.c @@ -58,6 +58,7 @@ #include "pssl.h" #include "psslcerts.h" #include "psynclib.h" +#include "putil.h" static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; @@ -69,7 +70,7 @@ static void ssl_debug(int loglevel, int errnum, const char *msg) { } static void free_encrypted(psync_encrypted_data_t e) { - pssl_memclean(e->data, e->datalen); + putil_wipe(e->data, e->datalen); pmemlock_free(e); } @@ -78,7 +79,7 @@ void prsa_free_binary(psync_binary_rsa_key_t bin) { } void psymkey_free(psync_symmetric_key_t key) { - pssl_memclean(key->key, key->keylen); + putil_wipe(key->key, key->keylen); pmemlock_free(key); } @@ -207,12 +208,6 @@ int pssl_init() { return 0; } -void pssl_memclean(void *ptr, size_t len) { - volatile unsigned char *p = ptr; - while (len--) - *p++ = 0; -} - static ssl_connection_t *conn_alloc(const char *hostname) { ssl_connection_t *conn; size_t len; @@ -574,7 +569,7 @@ prsa_private_to_binary(psync_rsa_privatekey_t rsa) { pmemlock_malloc(offsetof(psync_encrypted_data_struct_t, data) + len); ret->datalen = len; memcpy(ret->data, buff + sizeof(buff) - len, len); - pssl_memclean(buff + sizeof(buff) - len, len); + putil_wipe(buff + sizeof(buff) - len, len); return ret; } @@ -754,7 +749,7 @@ psync_symmetric_key_t prsa_decrypt_data(psync_rsa_privatekey_t rsa, offsetof(psync_symmetric_key_struct_t, key) + len); ret->keylen = len; memcpy(ret->key, buff, len); - pssl_memclean(buff, len); + putil_wipe(buff, len); return ret; } @@ -779,7 +774,7 @@ paes_create_encoder(psync_symmetric_key_t key) { } void paes_free_encoder(psync_aes256_encoder aes) { - pssl_memclean(aes, sizeof(mbedtls_aes_context)); + putil_wipe(aes, sizeof(mbedtls_aes_context)); psync_free(aes); } @@ -793,7 +788,7 @@ paes_create_decoder(psync_symmetric_key_t key) { } void paes_free_decoder(psync_aes256_encoder aes) { - pssl_memclean(aes, sizeof(mbedtls_aes_context)); + putil_wipe(aes, sizeof(mbedtls_aes_context)); psync_free(aes); } diff --git a/pclsync/pssl.h b/pclsync/pssl.h index 0e7921d..6d8a2fb 100644 --- a/pclsync/pssl.h +++ b/pclsync/pssl.h @@ -149,7 +149,6 @@ typedef psync_encrypted_data_t psync_rsa_signature_t; // Lock used to serialize access to RSA decrypt key function int pssl_init(); -void pssl_memclean(void *ptr, size_t len); int pssl_connect(int sock, void **sslconn, const char *hostname); int pssl_connect_finish(void *sslconn, const char *hostname); void pssl_free(void *sslconn); diff --git a/pclsync/psynclib.c b/pclsync/psynclib.c index 62ecb0e..c4d6073 100644 --- a/pclsync/psynclib.c +++ b/pclsync/psynclib.c @@ -428,21 +428,25 @@ static void psync_invalidate_auth(const char *auth) { psync_run_command("logout", params, NULL); } -void psync_logout2(uint32_t auth_status, int doinvauth) { +void psync_logout(uint32_t auth_status, int doinvauth) { tfa = 0; debug(D_NOTICE, "logout"); - psync_sql_statement( - "DELETE FROM setting WHERE id IN ('pass', 'auth', 'saveauth')"); - if (doinvauth) + + psync_sql_statement("DELETE FROM setting WHERE id IN ('pass', 'auth', 'saveauth')"); + if (doinvauth) { psync_invalidate_auth(psync_my_auth); - memset(psync_my_auth, 0, sizeof(psync_my_auth)); + } + putil_wipe(psync_my_auth, sizeof(psync_my_auth)); pcryptofolder_lock(); + pthread_mutex_lock(&psync_my_auth_mutex); + putil_wipe(psync_my_pass, sizeof(psync_my_pass)); psync_free(psync_my_pass); - psync_my_pass = NULL; pthread_mutex_unlock(&psync_my_auth_mutex); + pstatus_set(PSTATUS_TYPE_ONLINE, PSTATUS_ONLINE_CONNECTING); pstatus_set(PSTATUS_TYPE_AUTH, auth_status); + psync_fs_pause_until_login(); pdownload_stop_all(); pupload_stop_all(); @@ -451,12 +455,11 @@ void psync_logout2(uint32_t auth_status, int doinvauth) { psync_set_apiserver(PSYNC_API_HOST, PSYNC_LOCATIONID_DEFAULT); psync_restart_localscan(); ptimer_notify_exception(); - if (psync_fs_need_per_folder_refresh()) + if (psync_fs_need_per_folder_refresh()) { psync_fs_refresh_folder(0); + } } -void psync_logout() { psync_logout2(PSTATUS_AUTH_REQUIRED, 1); } - apiservers_list_t *psync_get_apiservers(char **err) { psock_t *api; binresult *bres; @@ -573,19 +576,19 @@ void psync_unlink() { ppagecache_clean(); psync_sql_connect(psync_database); if (deviceid) { - res = psync_sql_prep_statement( - "REPLACE INTO setting (id, value) VALUES ('deviceid', ?)"); + res = psync_sql_prep_statement("REPLACE INTO setting (id, value) VALUES ('deviceid', ?)"); psync_sql_bind_string(res, 1, deviceid); psync_sql_run_free(res); psync_free(deviceid); } pthread_mutex_lock(&psync_my_auth_mutex); - memset(psync_my_auth, 0, sizeof(psync_my_auth)); + putil_wipe(psync_my_auth, sizeof(psync_my_auth)); psync_my_user = NULL; - psync_my_pass = NULL; + putil_wipe(psync_my_pass, sizeof(psync_my_pass)); psync_my_userid = 0; pthread_mutex_unlock(&psync_my_auth_mutex); debug(D_NOTICE, "clearing database, finished"); + psync_fs_pause_until_login(); psync_fs_clean_tasks(); ppathstatus_init(); @@ -602,8 +605,9 @@ void psync_unlink() { pstatus_set(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_REQUIRED); pstatus_set(PSTATUS_TYPE_RUN, PSTATUS_RUN_RUN); psync_resume_localscan(); - if (psync_fs_need_per_folder_refresh()) + if (psync_fs_need_per_folder_refresh()) { psync_fs_refresh_folder(0); + } } int psync_tfa_has_devices() { return psync_my_2fa_has_devices; } diff --git a/pclsync/psynclib.h b/pclsync/psynclib.h index 4f7cb55..095899d 100644 --- a/pclsync/psynclib.h +++ b/pclsync/psynclib.h @@ -638,7 +638,7 @@ char *psync_get_username(); void psync_set_user_pass(const char *username, const char *password, int save); void psync_set_pass(const char *password, int save); void psync_set_auth(const char *auth, int save); -void psync_logout(); +void psync_logout(uint32_t auth_status, int doinvauth); void psync_unlink(); /* Upon seein a status of PSTATUS_TFA_REQUIRED the application is supposed to diff --git a/pclsync/putil.c b/pclsync/putil.c new file mode 100644 index 0000000..04c4ff4 --- /dev/null +++ b/pclsync/putil.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include + +#include "plibs.h" + +// wipe a segment of memory mem of size sz using a DoD 5220.22-M compliant +// 3-pass wipe. the first pass overwrites the memory with zeroes, the second +// with ones, and the third with random data using the urandom entropy +// source. if the urandom source fails, it falls back to a simple +// (non-cryptographically-secure) RNG. +void putil_wipe(void *mem, size_t sz) { + if (!mem || sz == 0) { return; } + + volatile unsigned char *p = (volatile unsigned char *)mem; + + memset((void*)p, 0x00, sz); + memset((void*)p, 0xFF, sz); + + ssize_t result = getrandom((void*)p, sz, 0); + if (result != (ssize_t)sz) { + if (result == -1) { + debug(D_WARNING, "getrandom() failed: %s.", strerror(errno)); + } else { + debug(D_WARNING, "getrandom() returned partial data."); + } + + debug(D_WARNING, "falling back to less secure third pass. This may occur due to insufficient entropy, early boot state, or kernel incompatibility."); + srand((unsigned int)(time(NULL) ^ (uintptr_t)&srand)); + for (size_t i = 0; i < sz; i++) { + p[i] = (unsigned char)rand(); + } + } +} diff --git a/pclsync/putil.h b/pclsync/putil.h index 157d6fc..8d391e9 100644 --- a/pclsync/putil.h +++ b/pclsync/putil.h @@ -1,3 +1,20 @@ +#ifndef __PUTIL_H +#define __PUTIL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + #define NTO_STR(s) TO_STR(s) #define TO_STR(s) #s #define VAR_ARRAY(name, type, size) type name[size] + +void putil_wipe(void *mem, size_t sz); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/pclsync_lib.cpp b/pclsync_lib.cpp index 609f2ee..72152d5 100644 --- a/pclsync_lib.cpp +++ b/pclsync_lib.cpp @@ -43,6 +43,7 @@ #include "pshm.h" #include "pdevice.h" #include "pcommands.h" +#include "putil.h" #include "pclsync_lib.h" @@ -70,6 +71,18 @@ const std::string &clib::pclsync_lib::get_crypto_pass() { return crypto_pass_; }; +void clib::pclsync_lib::wipe_crypto_pass() { + this->wipe(crypto_pass_); +} + +void clib::pclsync_lib::wipe_password() { + this->wipe(password_); +} + +void clib::pclsync_lib::wipe_tfa_code() { + this->wipe(tfa_code_); +} + const std::string &clib::pclsync_lib::get_mount() { return mount_; } void clib::pclsync_lib::set_trusted_device(bool arg) { @@ -81,9 +94,6 @@ void clib::pclsync_lib::set_tfa_code(const std::string &arg) { void clib::pclsync_lib::set_username(const std::string &arg) { username_ = arg; } -void clib::pclsync_lib::set_password(const std::string &arg) { - password_ = arg; -} void clib::pclsync_lib::set_crypto_pass(const std::string &arg) { crypto_pass_ = arg; }; @@ -103,30 +113,27 @@ clib::pclsync_lib &clib::pclsync_lib::get_lib() { char *clib::pclsync_lib::get_token() { return psync_get_token(); } -void clib::pclsync_lib::get_pass_from_console() { - do_get_pass_from_console(password_); +void clib::pclsync_lib::read_password() { + read_from_stdin(password_); } -void clib::pclsync_lib::get_tfa_code_from_console() +void clib::pclsync_lib::read_tfa_code() { if (daemon_) { - std::cout << "Not able to read 2fa code when started as daemon." - << std::endl; + std::cout << "Not able to read 2fa code when started as daemon." << std::endl; exit(1); } - std::cout << "Please enter 2fa code" - << std::endl; + std::cout << "Please enter 2fa code" << std::endl; getline(std::cin, tfa_code_); } -void clib::pclsync_lib::get_cryptopass_from_console() { - do_get_pass_from_console(crypto_pass_); +void clib::pclsync_lib::read_cryptopass() { + read_from_stdin(crypto_pass_); } -void clib::pclsync_lib::do_get_pass_from_console(std::string &password) { +void clib::pclsync_lib::read_from_stdin(std::string &s) { if (daemon_) { - std::cout << "Not able to read password when started as daemon." - << std::endl; + std::cout << "Not able to read password when started as daemon." << std::endl; exit(1); } termios oldt; @@ -135,7 +142,7 @@ void clib::pclsync_lib::do_get_pass_from_console(std::string &password) { newt.c_lflag &= ~ECHO; tcsetattr(STDIN_FILENO, TCSANOW, &newt); std::cout << "Please, enter password" << std::endl; - getline(std::cin, password); + getline(std::cin, s); tcsetattr(STDIN_FILENO, TCSANOW, &oldt); } @@ -201,21 +208,22 @@ void event_handler(psync_eventtype_t event, psync_eventdata_t eventdata) { } static int lib_setup_cripto() { - const char *pwd = clib::pclsync_lib::get_lib().get_crypto_pass().c_str(); - if(pstatus_get(PSTATUS_TYPE_ONLINE) == PSTATUS_ONLINE_OFFLINE) { std::cout << "Cannot unlock crypto folder, pcloudcc is offline" << std::endl; return PSYNC_CRYPTO_CANT_CONNECT; } + const char *pwd = clib::pclsync_lib::get_lib().get_crypto_pass().c_str(); if(!pcryptofolder_issetup()) { std::cout << "crypto is not setup, setting it up now..." << std::endl; if(int ret = pcryptofolder_setup(pwd, "no hint") != PSYNC_CRYPTO_SETUP_SUCCESS) { std::cout << "crypto setup failed, error code was " << ret << std::endl; + clib::pclsync_lib::get_lib().wipe_crypto_pass(); return ret; } if(int ret = pcryptofolder_mkdir(0, "Crypto", NULL, NULL) != PSYNC_CRYPTO_SUCCESS) { std::cout << "failed to create crypto directory, error code was" << ret << std::endl; + clib::pclsync_lib::get_lib().wipe_crypto_pass(); return ret; } std::cout << "crypto folder was setup using the provided password, " @@ -225,9 +233,11 @@ static int lib_setup_cripto() { if(int ret = pcryptofolder_unlock(pwd) != PSYNC_CRYPTO_START_SUCCESS) { std::cout << "Failed to unlock crypto folder: error code was " << ret << std::endl; + clib::pclsync_lib::get_lib().wipe_crypto_pass(); return ret; } + clib::pclsync_lib::get_lib().wipe_crypto_pass(); clib::pclsync_lib::get_lib().crypto_on_ = true; return 0; } @@ -286,7 +296,7 @@ static void status_change(pstatus_t *status) { *clib::pclsync_lib::get_lib().status_ = *status; if (status->status == PSTATUS_LOGIN_REQUIRED) { if (clib::pclsync_lib::get_lib().get_password().empty()) { - clib::pclsync_lib::get_lib().get_pass_from_console(); + clib::pclsync_lib::get_lib().read_password(); } psync_set_user_pass(clib::pclsync_lib::get_lib().get_username().c_str(), @@ -295,7 +305,7 @@ static void status_change(pstatus_t *status) { std::cout << "logging in" << std::endl; } else if (status->status == PSTATUS_TFA_REQUIRED) { if (clib::pclsync_lib::get_lib().get_tfa_code().empty()) { - clib::pclsync_lib::get_lib().get_tfa_code_from_console(); + clib::pclsync_lib::get_lib().read_tfa_code(); } psync_tfa_set_code(clib::pclsync_lib::get_lib().get_tfa_code().c_str(), @@ -303,7 +313,7 @@ static void status_change(pstatus_t *status) { 0); } else if (status->status == PSTATUS_BAD_LOGIN_DATA) { if (!clib::pclsync_lib::get_lib().newuser_) { - clib::pclsync_lib::get_lib().get_pass_from_console(); + clib::pclsync_lib::get_lib().read_password(); psync_set_user_pass(clib::pclsync_lib::get_lib().get_username().c_str(), clib::pclsync_lib::get_lib().get_password().c_str(), (int)clib::pclsync_lib::get_lib().save_pass_); @@ -470,22 +480,33 @@ int clib::pclsync_lib::init() { } int clib::pclsync_lib::login(const char *user, const char *pass, int save) { - set_username(user); - set_password(pass); - set_savepass(bool(save)); + username_ = user; + password_ = pass; + save_pass_ = save; psync_set_user_pass(user, pass, save); return 0; } int clib::pclsync_lib::logout() { - set_password(""); - psync_logout(); + wipe_password(); + psync_logout(PSTATUS_AUTH_REQUIRED, 1); return 0; } int clib::pclsync_lib::unlink() { set_username(""); - set_password(""); + wipe_password(); psync_unlink(); return 0; } + +void clib::pclsync_lib::wipe(std::string& s) { + if (s.empty()) { + return; + } + + void* mem = &s[0]; + size_t sz = s.size(); + putil_wipe(mem, sz); + s.clear(); +} \ No newline at end of file diff --git a/pclsync_lib.h b/pclsync_lib.h index 6b3cb08..ca1faf7 100644 --- a/pclsync_lib.h +++ b/pclsync_lib.h @@ -68,7 +68,6 @@ public: void set_trusted_device(bool arg); void set_tfa_code(const std::string& arg); void set_username(const std::string &arg); - void set_password(const std::string &arg); void set_crypto_pass(const std::string &arg); void set_mount(const std::string &arg); void set_savepass(bool s); @@ -77,13 +76,19 @@ public: void set_daemon(bool p); void set_status_callback(status_callback_t p); + // FIXME: not ideal, better if programmer does not have to remember to do + // this, but good enough for now... + void wipe_password(); + void wipe_crypto_pass(); + void wipe_tfa_code(); + // Singleton static pclsync_lib &get_lib(); // Console - void get_tfa_code_from_console(); - void get_pass_from_console(); - void get_cryptopass_from_console(); + void read_tfa_code(); + void read_password(); + void read_cryptopass(); // API calls int init(); @@ -103,16 +108,17 @@ public: private: std::string username_; - std::string password_; - std::string tfa_code_; - std::string crypto_pass_; + std::string password_; // SENSITIVE, use wipe function + std::string tfa_code_; // SENSITIVE, use wipe function + std::string crypto_pass_; // SENSITIVE, use wipe function std::string mount_; bool to_set_mount_; bool daemon_; - void do_get_pass_from_console(std::string &password); + void read_from_stdin(std::string &s); + void wipe(std::string& s); }; } // namespace clibrary } // namespace console_client diff --git a/rpcclient.cpp b/rpcclient.cpp index b408be9..5641db4 100644 --- a/rpcclient.cpp +++ b/rpcclient.cpp @@ -11,6 +11,7 @@ #include "rpcclient.h" #include "plibs.h" #include "prpc.h" +#include "putil.h" #define POVERLAY_BUFSIZE 512 @@ -97,12 +98,12 @@ int RpcClient::writeRequest(int fd, int msgtype, const char *value, char **out, writeerr = POVERLAY_WRITE_COMM_ERR; } + putil_wipe(buf, size); free(buf); return writeerr; } int RpcClient::readResponse(int fd, char **out, size_t *out_size) { - rpc_message_t *msg = (rpc_message_t *)malloc(POVERLAY_BUFSIZE); if (msg == NULL) { const char *error_msg = "Memory allocation failed"; @@ -116,6 +117,7 @@ int RpcClient::readResponse(int fd, char **out, size_t *out_size) { const char *error_msg = (bytes_read == 0) ? "Connection closed" : "Read error"; *out = strdup(error_msg); *out_size = strlen(error_msg) + 1; + putil_wipe(msg, POVERLAY_BUFSIZE); free(msg); return -1; } @@ -124,6 +126,7 @@ int RpcClient::readResponse(int fd, char **out, size_t *out_size) { memcpy(*out, msg->value, msg->length); *out_size = msg->length; + putil_wipe(msg, POVERLAY_BUFSIZE); free(msg); return 0; }