diff --git a/platform-independent/c/cli/src/mpw-cli.c b/platform-independent/c/cli/src/mpw-cli.c index 849a84d7..707448e6 100644 --- a/platform-independent/c/cli/src/mpw-cli.c +++ b/platform-independent/c/cli/src/mpw-cli.c @@ -29,6 +29,7 @@ #include "mpw-algorithm.h" #include "mpw-util.h" #include "mpw-marshal.h" +#include "mpw-marshal-util.h" /** Output the program's usage documentation. */ static void usage() { @@ -182,6 +183,9 @@ void cli_sitesRedacted(Arguments *args, Operation *operation); void cli_mpw(Arguments *args, Operation *operation); void cli_save(Arguments *args, Operation *operation); +MPMasterKeyProvider cli_masterKeyProvider_op(Operation *operation); +MPMasterKeyProvider cli_masterKeyProvider_str(const char *masterPassword); + /** ======================================================================== * MAIN */ int main(const int argc, char *const argv[]) { @@ -230,7 +234,6 @@ int main(const int argc, char *const argv[]) { dbg( "-----------------" ); if (operation.user) { dbg( "fullName : %s", operation.user->fullName ); - trc( "masterPassword : %s", operation.user->masterPassword ); dbg( "identicon : %s", operation.identicon ); dbg( "sitesFormat : %s%s", mpw_nameForFormat( operation.sitesFormat ), operation.sitesFormatFixed? " (fixed)": "" ); dbg( "sitesPath : %s", operation.sitesPath ); @@ -247,11 +250,11 @@ int main(const int argc, char *const argv[]) { dbg( "-----------------" ); // Finally ready to perform the actual operation. - cli_mpw( &args, &operation ); + cli_mpw( NULL, &operation ); // Save changes and clean up. - cli_save( &args, &operation ); - cli_free( &args, &operation ); + cli_save( NULL, &operation ); + cli_free( NULL, &operation ); return EX_OK; } @@ -487,7 +490,7 @@ void cli_user(Arguments *args, Operation *operation) { MPMarshalError marshalError = { .type = MPMarshalSuccess }; mpw_marshal_info_free( &sitesInputInfo ); mpw_marshal_free( &operation->user ); - operation->user = mpw_marshal_read( sitesInputData, sitesInputFormat, operation->masterPassword, &marshalError ); + operation->user = mpw_marshal_read( sitesInputData, sitesInputFormat, cli_masterKeyProvider_op( operation ), &marshalError ); if (marshalError.type == MPMarshalErrorMasterPassword && operation->allowPasswordUpdate) { // Update master password in mpsites. while (marshalError.type == MPMarshalErrorMasterPassword) { @@ -499,12 +502,10 @@ void cli_user(Arguments *args, Operation *operation) { importMasterPassword = mpw_getpass( "Old master password: " ); mpw_marshal_free( &operation->user ); - operation->user = mpw_marshal_read( sitesInputData, sitesInputFormat, importMasterPassword, &marshalError ); + operation->user = mpw_marshal_read( sitesInputData, sitesInputFormat, cli_masterKeyProvider_str( importMasterPassword ), &marshalError ); mpw_free_string( &importMasterPassword ); - } - if (operation->user) { - mpw_free_string( &operation->user->masterPassword ); - operation->user->masterPassword = mpw_strdup( operation->masterPassword ); + + operation->user->masterKeyProvider = cli_masterKeyProvider_op( operation ); } } mpw_free_string( &sitesInputData ); @@ -527,7 +528,7 @@ void cli_user(Arguments *args, Operation *operation) { // If no user from mpsites, create a new one. if (!operation->user) operation->user = mpw_marshal_user( - operation->fullName, operation->masterPassword, MPAlgorithmVersionCurrent ); + operation->fullName, cli_masterKeyProvider_op( operation ), MPAlgorithmVersionCurrent ); } void cli_site(Arguments *args, Operation *operation) { @@ -572,7 +573,7 @@ void cli_question(Arguments *args, Operation *operation) { void cli_operation(Arguments *args, Operation *operation) { mpw_free_string( &operation->identicon ); - operation->identicon = mpw_identicon_str( mpw_identicon( operation->user->fullName, operation->user->masterPassword ) ); + operation->identicon = mpw_identicon_str( mpw_identicon( operation->user->fullName, operation->masterPassword ) ); if (!operation->site) abort(); @@ -702,8 +703,7 @@ void cli_mpw(Arguments *args, Operation *operation) { operation->user->fullName, operation->purposeResult, operation->site->name, operation->identicon ); // Determine master key. - MPMasterKey masterKey = mpw_masterKey( - operation->user->fullName, operation->user->masterPassword, operation->site->algorithm ); + MPMasterKey masterKey = operation->user->masterKeyProvider( operation->site->algorithm, operation->user->fullName ); if (!masterKey) { ftl( "Couldn't derive master key." ); cli_free( args, operation ); @@ -799,3 +799,32 @@ void cli_save(Arguments *args, Operation *operation) { mpw_free_string( &buf ); fclose( sitesFile ); } + +static MPMasterKey __cli_masterKeyProvider_currentKey; +static MPAlgorithmVersion __cli_masterKeyProvider_currentAlgorithm; +static const char *__cli_masterKeyProvider_currentPassword; +static Operation *__cli_masterKeyProvider_currentOperation; +static MPMasterKey __cli_masterKeyProvider_op(MPAlgorithmVersion algorithm, const char *fullName) { + if (mpw_update_masterKey(&__cli_masterKeyProvider_currentKey, &__cli_masterKeyProvider_currentAlgorithm, + algorithm, fullName, __cli_masterKeyProvider_currentOperation->masterPassword)) + return __cli_masterKeyProvider_currentKey; + + return NULL; +} +static MPMasterKey __cli_masterKeyProvider_str(MPAlgorithmVersion algorithm, const char *fullName) { + if (mpw_update_masterKey(&__cli_masterKeyProvider_currentKey, &__cli_masterKeyProvider_currentAlgorithm, + algorithm, fullName, __cli_masterKeyProvider_currentPassword)) + return __cli_masterKeyProvider_currentKey; + + return NULL; +} + +MPMasterKeyProvider cli_masterKeyProvider_op(Operation *operation) { + __cli_masterKeyProvider_currentOperation = operation; + return __cli_masterKeyProvider_op; +} + +MPMasterKeyProvider cli_masterKeyProvider_str(const char *masterPassword) { + __cli_masterKeyProvider_currentPassword = masterPassword; + return __cli_masterKeyProvider_str; +} diff --git a/platform-independent/c/core/src/mpw-marshal-util.c b/platform-independent/c/core/src/mpw-marshal-util.c index cfbd0a7e..ab67a26e 100644 --- a/platform-independent/c/core/src/mpw-marshal-util.c +++ b/platform-independent/c/core/src/mpw-marshal-util.c @@ -106,7 +106,7 @@ bool mpw_get_json_boolean( bool mpw_update_masterKey(MPMasterKey *masterKey, MPAlgorithmVersion *masterKeyAlgorithm, MPAlgorithmVersion targetKeyAlgorithm, const char *fullName, const char *masterPassword) { - if (*masterKeyAlgorithm != targetKeyAlgorithm) { + if (masterKey && (!*masterKey || *masterKeyAlgorithm != targetKeyAlgorithm)) { mpw_free( masterKey, MPMasterKeySize ); *masterKeyAlgorithm = targetKeyAlgorithm; *masterKey = mpw_masterKey( fullName, masterPassword, *masterKeyAlgorithm ); diff --git a/platform-independent/c/core/src/mpw-marshal.c b/platform-independent/c/core/src/mpw-marshal.c index e474024b..38eaf478 100644 --- a/platform-independent/c/core/src/mpw-marshal.c +++ b/platform-independent/c/core/src/mpw-marshal.c @@ -26,15 +26,15 @@ #include "mpw-marshal-util.h" MPMarshalledUser *mpw_marshal_user( - const char *fullName, const char *masterPassword, const MPAlgorithmVersion algorithmVersion) { + const char *fullName, MPMasterKeyProvider masterKeyProvider, const MPAlgorithmVersion algorithmVersion) { MPMarshalledUser *user; - if (!fullName || !masterPassword || !(user = malloc( sizeof( MPMarshalledUser ) ))) + if (!fullName || !masterKeyProvider || !(user = malloc( sizeof( MPMarshalledUser ) ))) return NULL; *user = (MPMarshalledUser){ .fullName = mpw_strdup( fullName ), - .masterPassword = mpw_strdup( masterPassword ), + .masterKeyProvider = masterKeyProvider, .algorithm = algorithmVersion, .redacted = true, @@ -113,7 +113,7 @@ bool mpw_marshal_free( return true; bool success = true; - success &= mpw_free_strings( &(*user)->fullName, &(*user)->masterPassword, NULL ); + success &= mpw_free_strings( &(*user)->fullName, NULL ); for (size_t s = 0; s < (*user)->sites_count; ++s) { MPMarshalledSite *site = &(*user)->sites[s]; @@ -140,13 +140,8 @@ static bool mpw_marshal_write_flat( *error = (MPMarshalError){ MPMarshalErrorMissing, "Missing full name." }; return false; } - if (!user->masterPassword || !strlen( user->masterPassword )) { - *error = (MPMarshalError){ MPMarshalErrorMasterPassword, "Missing master password." }; - return false; - } - MPMasterKey masterKey = NULL; - MPAlgorithmVersion masterKeyAlgorithm = user->algorithm - 1; - if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, user->algorithm, user->fullName, user->masterPassword )) { + MPMasterKey masterKey = user->masterKeyProvider( user->algorithm, user->fullName ); + if (!masterKey) { *error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." }; return false; } @@ -185,7 +180,8 @@ static bool mpw_marshal_write_flat( const char *content = NULL, *loginContent = NULL; if (!user->redacted) { // Clear Text - if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, site->algorithm, user->fullName, user->masterPassword )) { + mpw_free( &masterKey, MPMasterKeySize ); + if (!(masterKey = user->masterKeyProvider( user->algorithm, user->fullName ))) { *error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." }; return false; } @@ -224,13 +220,8 @@ static bool mpw_marshal_write_json( *error = (MPMarshalError){ MPMarshalErrorMissing, "Missing full name." }; return false; } - if (!user->masterPassword || !strlen( user->masterPassword )) { - *error = (MPMarshalError){ MPMarshalErrorMasterPassword, "Missing master password." }; - return false; - } - MPMasterKey masterKey = NULL; - MPAlgorithmVersion masterKeyAlgorithm = user->algorithm - 1; - if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, user->algorithm, user->fullName, user->masterPassword )) { + MPMasterKey masterKey = user->masterKeyProvider( user->algorithm, user->fullName ); + if (!masterKey) { *error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." }; return false; } @@ -271,7 +262,8 @@ static bool mpw_marshal_write_json( const char *content = NULL, *loginContent = NULL; if (!user->redacted) { // Clear Text - if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, site->algorithm, user->fullName, user->masterPassword )) { + mpw_free( &masterKey, MPMasterKeySize ); + if (!(masterKey = user->masterKeyProvider( user->algorithm, user->fullName ))) { *error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." }; return false; } @@ -341,8 +333,8 @@ static bool mpw_marshal_write_json( mpw_string_pushf( out, "%s\n", json_object_to_json_string_ext( json_file, JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED | JSON_C_TO_STRING_NOSLASHESCAPE ) ); - mpw_free( &masterKey, MPMasterKeySize ); json_object_put( json_file ); + mpw_free( &masterKey, MPMasterKeySize ); *error = (MPMarshalError){ .type = MPMarshalSuccess }; return true; @@ -416,7 +408,7 @@ static void mpw_marshal_read_flat_info( } static MPMarshalledUser *mpw_marshal_read_flat( - const char *in, const char *masterPassword, MPMarshalError *error) { + const char *in, MPMasterKeyProvider masterKeyProvider, MPMarshalError *error) { *error = (MPMarshalError){ MPMarshalErrorInternal, "Unexpected internal error." }; if (!in || !strlen( in )) { @@ -430,7 +422,7 @@ static MPMarshalledUser *mpw_marshal_read_flat( MPMarshalledUser *user = NULL; unsigned int format = 0, avatar = 0; char *fullName = NULL, *keyID = NULL; - MPAlgorithmVersion algorithm = MPAlgorithmVersionCurrent, masterKeyAlgorithm = (MPAlgorithmVersion)-1; + MPAlgorithmVersion algorithm = MPAlgorithmVersionCurrent; MPResultType defaultType = MPResultTypeDefault; bool headerStarted = false, headerEnded = false, importRedacted = false; for (const char *endOfLine, *positionInLine = in; (endOfLine = strstr( positionInLine, "\n" )); positionInLine = endOfLine + 1) { @@ -504,7 +496,8 @@ static MPMarshalledUser *mpw_marshal_read_flat( continue; if (!user) { - if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, algorithm, fullName, masterPassword )) { + mpw_free( &masterKey, MPMasterKeySize ); + if (!(masterKey = masterKeyProvider( algorithm, fullName ))) { *error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." }; return NULL; } @@ -512,7 +505,7 @@ static MPMarshalledUser *mpw_marshal_read_flat( *error = (MPMarshalError){ MPMarshalErrorMasterPassword, "Master password doesn't match key ID." }; return NULL; } - if (!(user = mpw_marshal_user( fullName, masterPassword, algorithm ))) { + if (!(user = mpw_marshal_user( fullName, masterKeyProvider, algorithm ))) { *error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't allocate a new user." }; return NULL; } @@ -597,7 +590,8 @@ static MPMarshalledUser *mpw_marshal_read_flat( site->lastUsed = siteLastUsed; if (!user->redacted) { // Clear Text - if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, site->algorithm, fullName, masterPassword )) { + mpw_free( &masterKey, MPMasterKeySize ); + if (!(masterKey = masterKeyProvider( user->algorithm, user->fullName ))) { *error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." }; return NULL; } @@ -661,7 +655,7 @@ static void mpw_marshal_read_json_info( } static MPMarshalledUser *mpw_marshal_read_json( - const char *in, const char *masterPassword, MPMarshalError *error) { + const char *in, MPMasterKeyProvider masterKeyProvider, MPMarshalError *error) { *error = (MPMarshalError){ MPMarshalErrorInternal, "Unexpected internal error." }; if (!in || !strlen( in )) { @@ -680,7 +674,6 @@ static MPMarshalledUser *mpw_marshal_read_json( // Parse import data. MPMasterKey masterKey = NULL; - MPAlgorithmVersion masterKeyAlgorithm = (MPAlgorithmVersion)-1; MPMarshalledUser *user = NULL; // Section: "export" @@ -716,7 +709,7 @@ static MPMarshalledUser *mpw_marshal_read_json( *error = (MPMarshalError){ MPMarshalErrorMissing, "Missing value for full name." }; return NULL; } - if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, algorithm, fullName, masterPassword )) { + if (!(masterKey = masterKeyProvider( user->algorithm, user->fullName ))) { *error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." }; return NULL; } @@ -724,7 +717,7 @@ static MPMarshalledUser *mpw_marshal_read_json( *error = (MPMarshalError){ MPMarshalErrorMasterPassword, "Master password doesn't match key ID." }; return NULL; } - if (!(user = mpw_marshal_user( fullName, masterPassword, algorithm ))) { + if (!(user = mpw_marshal_user( fullName, masterKeyProvider, algorithm ))) { *error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't allocate a new user." }; return NULL; } @@ -781,7 +774,8 @@ static MPMarshalledUser *mpw_marshal_read_json( site->lastUsed = siteLastUsed; if (!user->redacted) { // Clear Text - if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, site->algorithm, fullName, masterPassword )) { + mpw_free( &masterKey, MPMasterKeySize ); + if (!(masterKey = masterKeyProvider( user->algorithm, user->fullName ))) { *error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." }; return NULL; } @@ -824,6 +818,7 @@ static MPMarshalledUser *mpw_marshal_read_json( } } json_object_put( json_file ); + mpw_free( &masterKey, MPMasterKeySize ); *error = (MPMarshalError){ .type = MPMarshalSuccess }; return user; @@ -853,17 +848,17 @@ MPMarshalInfo *mpw_marshal_read_info( } MPMarshalledUser *mpw_marshal_read( - const char *in, const MPMarshalFormat inFormat, const char *masterPassword, MPMarshalError *error) { + const char *in, const MPMarshalFormat inFormat, MPMasterKeyProvider masterKeyProvider, MPMarshalError *error) { switch (inFormat) { case MPMarshalFormatNone: *error = (MPMarshalError){ .type = MPMarshalSuccess }; return false; case MPMarshalFormatFlat: - return mpw_marshal_read_flat( in, masterPassword, error ); + return mpw_marshal_read_flat( in, masterKeyProvider, error ); #if MPW_JSON case MPMarshalFormatJSON: - return mpw_marshal_read_json( in, masterPassword, error ); + return mpw_marshal_read_json( in, masterKeyProvider, error ); #endif default: *error = (MPMarshalError){ MPMarshalErrorFormat, mpw_str( "Unsupported input format: %u", inFormat ) }; diff --git a/platform-independent/c/core/src/mpw-marshal.h b/platform-independent/c/core/src/mpw-marshal.h index 3a75d8a7..e5e6546c 100644 --- a/platform-independent/c/core/src/mpw-marshal.h +++ b/platform-independent/c/core/src/mpw-marshal.h @@ -56,6 +56,9 @@ typedef mpw_enum( unsigned int, MPMarshalErrorType ) { /** An internal system error interrupted marshalling. */ MPMarshalErrorInternal, }; + +typedef MPMasterKey (*MPMasterKeyProvider)(MPAlgorithmVersion algorithm, const char *fullName); + typedef struct MPMarshalError { MPMarshalErrorType type; const char *description; @@ -87,7 +90,7 @@ typedef struct MPMarshalledSite { typedef struct MPMarshalledUser { const char *fullName; - const char *masterPassword; + MPMasterKeyProvider masterKeyProvider; MPAlgorithmVersion algorithm; bool redacted; @@ -118,13 +121,13 @@ MPMarshalInfo *mpw_marshal_read_info( const char *in); /** Unmarshall sites in the given input buffer by parsing it using the given marshalling format. */ MPMarshalledUser *mpw_marshal_read( - const char *in, const MPMarshalFormat inFormat, const char *masterPassword, MPMarshalError *error); + const char *in, const MPMarshalFormat inFormat, MPMasterKeyProvider masterKeyProvider, MPMarshalError *error); //// Utilities. /** Create a new user object ready for marshalling. */ MPMarshalledUser *mpw_marshal_user( - const char *fullName, const char *masterPassword, const MPAlgorithmVersion algorithmVersion); + const char *fullName, MPMasterKeyProvider masterKeyProvider, const MPAlgorithmVersion algorithmVersion); /** Create a new site attached to the given user object, ready for marshalling. */ MPMarshalledSite *mpw_marshal_site( MPMarshalledUser *user,