diff --git a/platform-independent/c/cli/src/mpw-cli.c b/platform-independent/c/cli/src/mpw-cli.c index 20ed58a7..d379cff3 100644 --- a/platform-independent/c/cli/src/mpw-cli.c +++ b/platform-independent/c/cli/src/mpw-cli.c @@ -185,6 +185,7 @@ void cli_save(Arguments *args, Operation *operation); MPMasterKeyProvider cli_masterKeyProvider_op(Operation *operation); MPMasterKeyProvider cli_masterKeyProvider_str(const char *masterPassword); +void cli_masterKeyProvider_free(); /** ======================================================================== * MAIN */ @@ -274,6 +275,7 @@ void cli_free(Arguments *args, Operation *operation) { mpw_marshal_free( &operation->user ); operation->site = NULL; operation->question = NULL; + cli_masterKeyProvider_free(); } } @@ -457,22 +459,30 @@ void cli_user(Arguments *args, Operation *operation) { // Find mpsites file from parameters. FILE *sitesFile = NULL; - mpw_free_string( &operation->sitesPath ); - operation->sitesPath = mpw_path( operation->fullName, mpw_marshal_format_extension( operation->sitesFormat ) ); - if (!operation->sitesPath || !(sitesFile = fopen( operation->sitesPath, "r" ))) { - dbg( "Couldn't open configuration file:\n %s: %s", operation->sitesPath, strerror( errno ) ); + const char **extensions = NULL; + int count = mpw_marshal_format_extensions( operation->sitesFormat, &extensions ); + for (int e = 0; !sitesFile && e < count; ++e) { + mpw_free_string( &operation->sitesPath ); + operation->sitesPath = mpw_path( operation->fullName, extensions[e] ); - // Try to fall back to the flat format. - if (!operation->sitesFormatFixed) { - mpw_free_string( &operation->sitesPath ); - operation->sitesPath = mpw_path( operation->fullName, mpw_marshal_format_extension( MPMarshalFormatFlat ) ); - if (operation->sitesPath && (sitesFile = fopen( operation->sitesPath, "r" ))) - operation->sitesFormat = MPMarshalFormatFlat; - else - dbg( "Couldn't open configuration file:\n %s: %s", operation->sitesPath, strerror( errno ) ); - } + if (!operation->sitesPath || !(sitesFile = fopen( operation->sitesPath, "r" ))) + dbg( "Couldn't open configuration file:\n %s: %s", operation->sitesPath, strerror( errno ) ); } + if (!sitesFile && !operation->sitesFormatFixed) + for (MPMarshalFormat format = MPMarshalFormatFirst; !sitesFile && format <= MPMarshalFormatLast; ++format) { + count = mpw_marshal_format_extensions( operation->sitesFormat, &extensions ); + + for (int e = 0; !sitesFile && e < count; ++e) { + mpw_free_string( &operation->sitesPath ); + operation->sitesPath = mpw_path( operation->fullName, extensions[e] ); + + if (!operation->sitesPath || !(sitesFile = fopen( operation->sitesPath, "r" ))) + dbg( "Couldn't open configuration file:\n %s: %s", operation->sitesPath, strerror( errno ) ); + } + } + free( extensions ); + // Load the user object from mpsites. if (!sitesFile) mpw_free_string( &operation->sitesPath ); @@ -490,7 +500,8 @@ 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, cli_masterKeyProvider_op( operation ), &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) { @@ -498,14 +509,16 @@ void cli_user(Arguments *args, Operation *operation) { inf( "To update the configuration with this new master password, first confirm the old master password." ); const char *importMasterPassword = NULL; - while (!importMasterPassword || !strlen( importMasterPassword )) + while (!importMasterPassword || !strlen( importMasterPassword )) { + mpw_free_string( &importMasterPassword ); importMasterPassword = mpw_getpass( "Old master password: " ); + } mpw_marshal_free( &operation->user ); - operation->user = mpw_marshal_read( sitesInputData, sitesInputFormat, cli_masterKeyProvider_str( importMasterPassword ), &marshalError ); - mpw_free_string( &importMasterPassword ); - + operation->user = mpw_marshal_read( sitesInputData, sitesInputFormat, + cli_masterKeyProvider_str( importMasterPassword ), &marshalError ); operation->user->masterKeyProvider = cli_masterKeyProvider_op( operation ); + mpw_free_string( &importMasterPassword ); } } mpw_free_string( &sitesInputData ); @@ -772,15 +785,17 @@ void cli_mpw(Arguments *args, Operation *operation) { void cli_save(Arguments *args, Operation *operation) { - if (operation->sitesFormat == MPMarshalFormatNone) - return; - if (!operation->sitesFormatFixed) operation->sitesFormat = MPMarshalFormatDefault; + const char **extensions = NULL; + if (!mpw_marshal_format_extensions( operation->sitesFormat, &extensions )) + return; + mpw_free_string( &operation->sitesPath ); - operation->sitesPath = mpw_path( operation->user->fullName, mpw_marshal_format_extension( operation->sitesFormat ) ); - dbg( "Updating: %s (%s)", operation->sitesPath, mpw_nameForFormat( operation->sitesFormat ) ); + operation->sitesPath = mpw_path( operation->user->fullName, extensions[0] ); + dbg( "Updating: %s (%s)", operation->sitesPath, mpw_format_name( operation->sitesFormat ) ); + free( extensions ); FILE *sitesFile = NULL; if (!operation->sitesPath || !mpw_mkdirs( operation->sitesPath ) || !(sitesFile = fopen( operation->sitesPath, "w" ))) { @@ -800,31 +815,48 @@ void cli_save(Arguments *args, Operation *operation) { 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_currentKey = NULL; +static MPAlgorithmVersion __cli_masterKeyProvider_currentAlgorithm = (MPAlgorithmVersion)-1; +static const char *__cli_masterKeyProvider_currentPassword = NULL; +static Operation *__cli_masterKeyProvider_currentOperation = NULL; + 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; - + + if (mpw_update_master_key( &__cli_masterKeyProvider_currentKey, &__cli_masterKeyProvider_currentAlgorithm, + algorithm, fullName, __cli_masterKeyProvider_currentOperation->masterPassword )) + return mpw_memdup( __cli_masterKeyProvider_currentKey, MPMasterKeySize ); + 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; - + + if (mpw_update_master_key( &__cli_masterKeyProvider_currentKey, &__cli_masterKeyProvider_currentAlgorithm, + algorithm, fullName, __cli_masterKeyProvider_currentPassword )) + return mpw_memdup( __cli_masterKeyProvider_currentKey, MPMasterKeySize ); + return NULL; } MPMasterKeyProvider cli_masterKeyProvider_op(Operation *operation) { + + mpw_free_string( &__cli_masterKeyProvider_currentPassword ); __cli_masterKeyProvider_currentOperation = operation; return __cli_masterKeyProvider_op; } MPMasterKeyProvider cli_masterKeyProvider_str(const char *masterPassword) { - __cli_masterKeyProvider_currentPassword = masterPassword; + + mpw_free_string( &__cli_masterKeyProvider_currentPassword ); + __cli_masterKeyProvider_currentPassword = mpw_strdup( masterPassword ); return __cli_masterKeyProvider_str; } + +void cli_masterKeyProvider_free() { + + mpw_free( &__cli_masterKeyProvider_currentKey, MPMasterKeySize ); + __cli_masterKeyProvider_currentAlgorithm = (MPAlgorithmVersion)-1; + mpw_free_string( &__cli_masterKeyProvider_currentPassword ); + __cli_masterKeyProvider_currentOperation = NULL; + +} diff --git a/platform-independent/c/core/src/mpw-marshal.c b/platform-independent/c/core/src/mpw-marshal.c index 5fe9bdd6..743204cd 100644 --- a/platform-independent/c/core/src/mpw-marshal.c +++ b/platform-independent/c/core/src/mpw-marshal.c @@ -181,7 +181,7 @@ static bool mpw_marshal_write_flat( if (!user->redacted) { // Clear Text mpw_free( &masterKey, MPMasterKeySize ); - if (!(masterKey = user->masterKeyProvider( user->algorithm, user->fullName ))) { + if (!(masterKey = user->masterKeyProvider( site->algorithm, user->fullName ))) { *error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." }; return false; } @@ -212,6 +212,7 @@ static bool mpw_marshal_write_flat( } #if MPW_JSON + static bool mpw_marshal_write_json( char **out, const MPMarshalledUser *user, MPMarshalError *error) { @@ -263,7 +264,7 @@ static bool mpw_marshal_write_json( if (!user->redacted) { // Clear Text mpw_free( &masterKey, MPMasterKeySize ); - if (!(masterKey = user->masterKeyProvider( user->algorithm, user->fullName ))) { + if (!(masterKey = user->masterKeyProvider( site->algorithm, user->fullName ))) { *error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." }; return false; } @@ -339,6 +340,7 @@ static bool mpw_marshal_write_json( *error = (MPMarshalError){ .type = MPMarshalSuccess }; return true; } + #endif bool mpw_marshal_write( @@ -593,7 +595,7 @@ static MPMarshalledUser *mpw_marshal_read_flat( if (!user->redacted) { // Clear Text mpw_free( &masterKey, MPMasterKeySize ); - if (!(masterKey = masterKeyProvider( user->algorithm, user->fullName ))) { + if (!(masterKey = masterKeyProvider( site->algorithm, user->fullName ))) { *error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." }; return NULL; } @@ -632,6 +634,7 @@ static MPMarshalledUser *mpw_marshal_read_flat( } #if MPW_JSON + static void mpw_marshal_read_json_info( const char *in, MPMarshalInfo *info) { @@ -713,7 +716,7 @@ static MPMarshalledUser *mpw_marshal_read_json( *error = (MPMarshalError){ MPMarshalErrorMissing, "Missing value for full name." }; return NULL; } - if (!(masterKey = masterKeyProvider( user->algorithm, user->fullName ))) { + if (!(masterKey = masterKeyProvider( algorithm, fullName ))) { *error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." }; return NULL; } @@ -779,7 +782,7 @@ static MPMarshalledUser *mpw_marshal_read_json( if (!user->redacted) { // Clear Text mpw_free( &masterKey, MPMasterKeySize ); - if (!(masterKey = masterKeyProvider( user->algorithm, user->fullName ))) { + if (!(masterKey = masterKeyProvider( site->algorithm, user->fullName ))) { *error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." }; return NULL; } @@ -827,6 +830,7 @@ static MPMarshalledUser *mpw_marshal_read_json( *error = (MPMarshalError){ .type = MPMarshalSuccess }; return user; } + #endif MPMarshalInfo *mpw_marshal_read_info( @@ -913,10 +917,41 @@ const char *mpw_marshal_format_extension( case MPMarshalFormatFlat: return "mpsites"; case MPMarshalFormatJSON: - return "mpsites.json"; + return "mpjson"; default: { dbg( "Unknown format: %d", format ); return NULL; } } } + +int mpw_marshal_format_extensions( + const MPMarshalFormat format, const char ***extensions) { + + int count = 0; + switch (format) { + case MPMarshalFormatNone: { + break; + } + case MPMarshalFormatFlat: { + const char *array[3] = { mpw_marshal_format_extension( format ), "mpsites.txt", "txt" }; + count = sizeof( array ) / sizeof( *array ); + *extensions = realloc( *extensions, count * sizeof( const char * ) ); + memcpy( *extensions, array, count * sizeof( const char * ) ); + break; + } + case MPMarshalFormatJSON: { + const char *array[3] = { mpw_marshal_format_extension( format ), "mpsites.json", "json" }; + count = sizeof( array ) / sizeof( *array ); + *extensions = realloc( *extensions, sizeof( array ) ); + memcpy( *extensions, array, sizeof( array ) ); + break; + } + default: { + dbg( "Unknown format: %d", format ); + break; + } + } + + return count; +} diff --git a/platform-independent/c/core/src/mpw-marshal.h b/platform-independent/c/core/src/mpw-marshal.h index 6d4210a2..f4f3a45e 100644 --- a/platform-independent/c/core/src/mpw-marshal.h +++ b/platform-independent/c/core/src/mpw-marshal.h @@ -38,6 +38,8 @@ typedef mpw_enum( unsigned int, MPMarshalFormat ) { #else MPMarshalFormatDefault = MPMarshalFormatFlat, #endif + MPMarshalFormatFirst = MPMarshalFormatFlat, + MPMarshalFormatLast = MPMarshalFormatJSON, }; typedef mpw_enum( unsigned int, MPMarshalErrorType ) { @@ -162,5 +164,12 @@ const char *mpw_nameForFormat( */ const char *mpw_marshal_format_extension( const MPMarshalFormat format); +/** + * @param extensions An array of filename extensions that are used for files of this format, + * the first being the currently preferred/output extension. Free after use. + * @return The amount of filename extensions returned in the array. + */ +int mpw_marshal_format_extensions( + const MPMarshalFormat format, const char ***extensions); #endif // _MPW_MARSHAL_H diff --git a/platform-independent/c/core/src/mpw-util.c b/platform-independent/c/core/src/mpw-util.c index 55cbf05a..8164d87f 100644 --- a/platform-independent/c/core/src/mpw-util.c +++ b/platform-independent/c/core/src/mpw-util.c @@ -490,17 +490,25 @@ const size_t mpw_utf8_strlen(const char *utf8String) { return charlen; } +void *mpw_memdup(const void *src, size_t len) { + + if (!src) + return NULL; + + char *dst = malloc( len ); + if (dst) + memcpy( dst, src, len ); + + return dst; +} + char *mpw_strdup(const char *src) { if (!src) return NULL; size_t len = strlen( src ); - char *dst = malloc( len + 1 ); - memcpy( dst, src, len ); - dst[len] = '\0'; - - return dst; + return mpw_memdup( src, len + 1 ); } char *mpw_strndup(const char *src, size_t max) { diff --git a/platform-independent/c/core/src/mpw-util.h b/platform-independent/c/core/src/mpw-util.h index 8765a9ef..38adac95 100644 --- a/platform-independent/c/core/src/mpw-util.h +++ b/platform-independent/c/core/src/mpw-util.h @@ -223,6 +223,8 @@ bool mpw_id_buf_equals(const char *id1, const char *id2); /** @return The amount of display characters in the given UTF-8 string. */ const size_t mpw_utf8_strlen(const char *utf8String); +/** Drop-in for memdup(3). */ +void *mpw_memdup(const void *src, size_t len); /** Drop-in for POSIX strdup(3). */ char *mpw_strdup(const char *src); /** Drop-in for POSIX strndup(3). */