diff --git a/core/c/mpw-marshall.c b/core/c/mpw-marshall.c index 7c85e915..4cee3a2e 100644 --- a/core/c/mpw-marshall.c +++ b/core/c/mpw-marshall.c @@ -109,53 +109,49 @@ bool mpw_marshal_free( return success; } -#define try_asprintf(...) ({ if (asprintf( __VA_ARGS__ ) < 0) return false; }) - static bool mpw_marshall_write_flat( char **out, const MPMarshalledUser *user, MPMarshallError *error) { - *error = MPMarshallErrorInternal; + *error = (MPMarshallError){ MPMarshallErrorInternal, "Unexpected internal error." }; if (!user->name || !strlen( user->name )) { - err( "Missing full name.\n" ); - *error = MPMarshallErrorMissing; + *error = (MPMarshallError){ MPMarshallErrorMissing, "Missing full name." }; return false; } if (!user->masterPassword || !strlen( user->masterPassword )) { - err( "Missing master password.\n" ); - *error = MPMarshallErrorMasterPassword; + *error = (MPMarshallError){ MPMarshallErrorMasterPassword, "Missing master password." }; return false; } MPMasterKey masterKey = NULL; MPAlgorithmVersion masterKeyAlgorithm = user->algorithm - 1; if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, user->algorithm, user->name, user->masterPassword )) { - err( "Couldn't derive master key.\n" ); + *error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." }; return false; } - try_asprintf( out, "# Master Password site export\n" ); + mpw_string_pushf( out, "# Master Password site export\n" ); if (user->redacted) - try_asprintf( out, "# Export of site names and passwords in clear-text.\n" ); + mpw_string_pushf( out, "# Export of site names and passwords in clear-text.\n" ); else - try_asprintf( out, "# Export of site names and stored passwords (unless device-private) encrypted with the master key.\n" ); - try_asprintf( out, "# \n" ); - try_asprintf( out, "##\n" ); - try_asprintf( out, "# Format: %d\n", 1 ); + mpw_string_pushf( out, "# Export of site names and stored passwords (unless device-private) encrypted with the master key.\n" ); + mpw_string_pushf( out, "# \n" ); + mpw_string_pushf( out, "##\n" ); + mpw_string_pushf( out, "# Format: %d\n", 1 ); char dateString[21]; time_t now = time( NULL ); if (strftime( dateString, sizeof( dateString ), "%FT%TZ", gmtime( &now ) )) - try_asprintf( out, "# Date: %s\n", dateString ); - try_asprintf( out, "# User Name: %s\n", user->name ); - try_asprintf( out, "# Full Name: %s\n", user->name ); - try_asprintf( out, "# Avatar: %u\n", user->avatar ); - try_asprintf( out, "# Key ID: %s\n", mpw_id_buf( masterKey, MPMasterKeySize ) ); - try_asprintf( out, "# Algorithm: %d\n", user->algorithm ); - try_asprintf( out, "# Default Type: %d\n", user->defaultType ); - try_asprintf( out, "# Passwords: %s\n", user->redacted? "PROTECTED": "VISIBLE" ); - try_asprintf( out, "##\n" ); - try_asprintf( out, "#\n" ); - try_asprintf( out, "# Last Times Password Login\t Site\tSite\n" ); - try_asprintf( out, "# used used type name\t name\tpassword\n" ); + mpw_string_pushf( out, "# Date: %s\n", dateString ); + mpw_string_pushf( out, "# User Name: %s\n", user->name ); + mpw_string_pushf( out, "# Full Name: %s\n", user->name ); + mpw_string_pushf( out, "# Avatar: %u\n", user->avatar ); + mpw_string_pushf( out, "# Key ID: %s\n", mpw_id_buf( masterKey, MPMasterKeySize ) ); + mpw_string_pushf( out, "# Algorithm: %d\n", user->algorithm ); + mpw_string_pushf( out, "# Default Type: %d\n", user->defaultType ); + mpw_string_pushf( out, "# Passwords: %s\n", user->redacted? "PROTECTED": "VISIBLE" ); + mpw_string_pushf( out, "##\n" ); + mpw_string_pushf( out, "#\n" ); + mpw_string_pushf( out, "# Last Times Password Login\t Site\tSite\n" ); + mpw_string_pushf( out, "# used used type name\t name\tpassword\n" ); // Sites. for (size_t s = 0; s < user->sites_count; ++s) { @@ -166,7 +162,7 @@ static bool mpw_marshall_write_flat( const char *content = site.type & MPSiteFeatureExportContent? site.content: NULL; if (!user->redacted) { if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, site.algorithm, user->name, user->masterPassword )) { - err( "Couldn't derive master key.\n" ); + *error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." }; return false; } @@ -182,34 +178,32 @@ static bool mpw_marshall_write_flat( } if (strftime( dateString, sizeof( dateString ), "%FT%TZ", gmtime( &site.lastUsed ) )) - try_asprintf( out, "%s %8ld %lu:%lu:%lu %25s\t%25s\t%s\n", + mpw_string_pushf( out, "%s %8ld %lu:%lu:%lu %25s\t%25s\t%s\n", dateString, (long)site.uses, (long)site.type, (long)site.algorithm, (long)site.counter, site.loginName?: "", site.name, content?: "" ); } mpw_free( masterKey, MPMasterKeySize ); - *error = MPMarshallSuccess; + *error = (MPMarshallError){ MPMarshallSuccess }; return true; } static bool mpw_marshall_write_json( char **out, const MPMarshalledUser *user, MPMarshallError *error) { - *error = MPMarshallErrorInternal; + *error = (MPMarshallError){ MPMarshallErrorInternal, "Unexpected internal error." }; if (!user->name || !strlen( user->name )) { - err( "Missing full name.\n" ); - *error = MPMarshallErrorMissing; + *error = (MPMarshallError){ MPMarshallErrorMissing, "Missing full name." }; return false; } if (!user->masterPassword || !strlen( user->masterPassword )) { - err( "Missing master password.\n" ); - *error = MPMarshallErrorMasterPassword; + *error = (MPMarshallError){ MPMarshallErrorMasterPassword, "Missing master password." }; return false; } MPMasterKey masterKey = NULL; MPAlgorithmVersion masterKeyAlgorithm = user->algorithm - 1; if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, user->algorithm, user->name, user->masterPassword )) { - err( "Couldn't derive master key.\n" ); + *error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." }; return false; } @@ -249,7 +243,7 @@ static bool mpw_marshall_write_json( const char *content = site.type & MPSiteFeatureExportContent? site.content: NULL; if (!user->redacted) { if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, site.algorithm, user->name, user->masterPassword )) { - err( "Couldn't derive master key.\n" ); + *error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." }; return false; } @@ -304,11 +298,11 @@ static bool mpw_marshall_write_json( json_object_object_add( json_site_mpw, "url", json_object_new_string( site.url ) ); } - try_asprintf( out, "%s\n", json_object_to_json_string_ext( json_file, JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED ) ); + mpw_string_pushf( out, "%s\n", json_object_to_json_string_ext( json_file, JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED ) ); mpw_free( masterKey, MPMasterKeySize ); json_object_put( json_file ); - *error = MPMarshallSuccess; + *error = (MPMarshallError){ MPMarshallSuccess }; return true; } @@ -322,15 +316,14 @@ bool mpw_marshall_write( return mpw_marshall_write_json( out, marshalledUser, error ); } - err( "Unsupported output format: %u\n", outFormat ); - *error = MPMarshallErrorFormat; + *error = (MPMarshallError){ MPMarshallErrorFormat, mpw_str( "Unsupported output format: %u", outFormat ) }; return false; } static MPMarshalledUser *mpw_marshall_read_flat( char *in, const char *masterPassword, MPMarshallError *error) { - *error = MPMarshallErrorInternal; + *error = (MPMarshallError){ MPMarshallErrorInternal, "Unexpected internal error." }; // Parse import data. MPMasterKey masterKey = NULL; @@ -366,8 +359,8 @@ static MPMarshalledUser *mpw_marshall_read_flat( char *headerName = mpw_get_token( &positionInLine, endOfLine, ":\n" ); char *headerValue = mpw_get_token( &positionInLine, endOfLine, "\n" ); if (!headerName || !headerValue) { - err( "Invalid header: %s\n", strndup( positionInLine, (size_t)(endOfLine - positionInLine) ) ); - *error = MPMarshallErrorStructure; + error->type = MPMarshallErrorStructure; + error->description = mpw_str( "Invalid header: %s", strndup( positionInLine, (size_t)(endOfLine - positionInLine) ) ); return NULL; } @@ -382,8 +375,7 @@ static MPMarshalledUser *mpw_marshall_read_flat( if (strcmp( headerName, "Algorithm" ) == 0) { int value = atoi( headerValue ); if (value < MPAlgorithmVersionFirst || value > MPAlgorithmVersionLast) { - err( "Invalid algorithm version: %s\n", headerValue ); - *error = MPMarshallErrorIllegal; + *error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid user algorithm version: %s", headerValue ) }; return NULL; } algorithm = (MPAlgorithmVersion)value; @@ -391,8 +383,7 @@ static MPMarshalledUser *mpw_marshall_read_flat( if (strcmp( headerName, "Default Type" ) == 0) { int value = atoi( headerValue ); if (!mpw_nameForType( (MPPasswordType)value )) { - err( "Invalid user default type: %s\n", headerValue ); - *error = MPMarshallErrorIllegal; + *error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid user default type: %s", headerValue ) }; return NULL; } defaultType = (MPPasswordType)value; @@ -407,8 +398,7 @@ static MPMarshalledUser *mpw_marshall_read_flat( if (!headerEnded) continue; if (!fullName) { - err( "Missing header: Full Name\n" ); - *error = MPMarshallErrorMissing; + *error = (MPMarshallError){ MPMarshallErrorMissing, "Missing header: Full Name" }; return NULL; } if (positionInLine >= endOfLine) @@ -416,16 +406,15 @@ static MPMarshalledUser *mpw_marshall_read_flat( if (!user) { if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, algorithm, fullName, masterPassword )) { - err( "Couldn't derive master key.\n" ); + *error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." }; return NULL; } if (keyID && !mpw_id_buf_equals( keyID, mpw_id_buf( masterKey, MPMasterKeySize ) )) { - err( "Incorrect master password for user import file: %s != %s\n", keyID, mpw_id_buf( masterKey, MPMasterKeySize ) ); - *error = MPMarshallErrorMasterPassword; + *error = (MPMarshallError){ MPMarshallErrorMasterPassword, "Incorrect master password for import file." }; return NULL; } if (!(user = mpw_marshall_user( fullName, masterPassword, algorithm ))) { - err( "Couldn't allocate a new user.\n" ); + *error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't allocate a new user." }; return NULL; } @@ -469,8 +458,7 @@ static MPMarshalledUser *mpw_marshall_read_flat( break; } default: { - err( "Unexpected import format: %u\n", format ); - *error = MPMarshallErrorFormat; + *error = (MPMarshallError){ MPMarshallErrorFormat, mpw_str( "Unexpected import format: %u", format ) }; return NULL; } } @@ -478,28 +466,25 @@ static MPMarshalledUser *mpw_marshall_read_flat( if (siteName && str_type && str_counter && str_algorithm && str_uses && str_lastUsed) { MPPasswordType siteType = (MPPasswordType)atoi( str_type ); if (!mpw_nameForType( siteType )) { - err( "Invalid site algorithm version: %s: %s\n", siteName, str_type ); - *error = MPMarshallErrorIllegal; + *error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid site type: %s: %s", siteName, str_type ) }; return NULL; } int value = atoi( str_algorithm ); if (value < MPAlgorithmVersionFirst || value > MPAlgorithmVersionLast) { - err( "Invalid site algorithm version: %s: %s\n", siteName, str_algorithm ); - *error = MPMarshallErrorIllegal; + *error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid site algorithm: %s: %s", siteName, str_algorithm ) }; return NULL; } MPAlgorithmVersion siteAlgorithm = (MPAlgorithmVersion)value; time_t siteLastUsed = mpw_mktime( str_lastUsed ); if (!siteLastUsed) { - err( "Invalid site last used date: %s: %s\n", siteName, str_lastUsed ); - *error = MPMarshallErrorIllegal; + *error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid site last used: %s: %s", siteName, str_lastUsed ) }; return NULL; } MPMarshalledSite *site = mpw_marshall_site( user, siteName, siteType, (uint32_t)atoi( str_counter ), siteAlgorithm ); if (!site) { - err( "Couldn't allocate a new site.\n" ); + *error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't allocate a new site." }; return NULL; } @@ -509,7 +494,7 @@ static MPMarshalledUser *mpw_marshall_read_flat( if (siteContent && strlen( siteContent )) { if (user->redacted) { if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, site->algorithm, fullName, masterPassword )) { - err( "Couldn't derive master key.\n" ); + *error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." }; return NULL; } @@ -520,9 +505,13 @@ static MPMarshalledUser *mpw_marshall_read_flat( site->content = strdup( siteContent ); } } - else - wrn( "Skipping: lastUsed=%s, uses=%s, type=%s, version=%s, counter=%s, loginName=%s, siteName=%s\n", + else { + error->type = MPMarshallErrorMissing; + error->description = mpw_str( + "Missing one of: lastUsed=%s, uses=%s, type=%s, version=%s, counter=%s, loginName=%s, siteName=%s", str_lastUsed, str_uses, str_type, str_algorithm, str_counter, siteLoginName, siteName ); + return NULL; + } mpw_free_string( str_lastUsed ); mpw_free_string( str_uses ); @@ -537,22 +526,20 @@ static MPMarshalledUser *mpw_marshall_read_flat( mpw_free_string( keyID ); mpw_free( masterKey, MPMasterKeySize ); - *error = MPMarshallSuccess; + *error = (MPMarshallError){ MPMarshallSuccess }; return user; } static MPMarshalledUser *mpw_marshall_read_json( char *in, const char *masterPassword, MPMarshallError *error) { - *error = MPMarshallErrorInternal; + *error = (MPMarshallError){ MPMarshallErrorInternal }; // Parse JSON. enum json_tokener_error json_error = json_tokener_success; json_object *json_file = json_tokener_parse_verbose( in, &json_error ); - if (json_error != json_tokener_success) - err( "JSON error: %s\n", json_tokener_error_desc( json_error ) ); - if (!json_file) { - *error = MPMarshallErrorStructure; + if (!json_file || json_error != json_tokener_success) { + *error = (MPMarshallError){ MPMarshallErrorStructure, mpw_str( "JSON error: %s", json_tokener_error_desc( json_error ) ) }; return NULL; } @@ -564,8 +551,7 @@ static MPMarshalledUser *mpw_marshall_read_json( // Section: "export" unsigned int fileFormat = (unsigned int)mpw_get_json_int( json_file, "export.format", 0 ); if (fileFormat < 1) { - err( "Unsupported format: %u\n", fileFormat ); - *error = MPMarshallErrorFormat; + *error = (MPMarshallError){ MPMarshallErrorFormat, mpw_str( "Unsupported format: %u", fileFormat ) }; return NULL; } bool fileRedacted = mpw_get_json_boolean( json_file, "export.redacted", true ); @@ -577,39 +563,34 @@ static MPMarshalledUser *mpw_marshall_read_json( const char *keyID = mpw_get_json_string( json_file, "user.key_id", NULL ); int value = mpw_get_json_int( json_file, "user.algorithm", MPAlgorithmVersionCurrent ); if (value < MPAlgorithmVersionFirst || value > MPAlgorithmVersionLast) { - err( "Invalid user algorithm version: %u\n", value ); - *error = MPMarshallErrorIllegal; + *error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid user algorithm version: %u", value ) }; return NULL; } MPAlgorithmVersion algorithm = (MPAlgorithmVersion)value; MPPasswordType defaultType = (MPPasswordType)mpw_get_json_int( json_file, "user.default_type", MPPasswordTypeDefault ); if (!mpw_nameForType( defaultType )) { - err( "Invalid user default type: %u\n", defaultType ); - *error = MPMarshallErrorIllegal; + *error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid user default type: %u", defaultType ) }; return NULL; } time_t lastUsed = mpw_mktime( str_lastUsed ); if (!lastUsed) { - err( "Invalid last used date: %s\n", str_lastUsed ); - *error = MPMarshallErrorIllegal; + *error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid user last used: %s", str_lastUsed ) }; return NULL; } if (!fullName || !strlen( fullName )) { - err( "Missing value for full name.\n" ); - *error = MPMarshallErrorMissing; + *error = (MPMarshallError){ MPMarshallErrorMissing, "Missing value for full name." }; return NULL; } if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, algorithm, fullName, masterPassword )) { - err( "Couldn't derive master key.\n" ); + *error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." }; return NULL; } if (keyID && !mpw_id_buf_equals( keyID, mpw_id_buf( masterKey, MPMasterKeySize ) )) { - err( "Incorrect master password for user import file: %s != %s\n", keyID, mpw_id_buf( masterKey, MPMasterKeySize ) ); - *error = MPMarshallErrorMasterPassword; + *error = (MPMarshallError){ MPMarshallErrorMasterPassword, "Incorrect master password for import file." }; return NULL; } if (!(user = mpw_marshall_user( fullName, masterPassword, algorithm ))) { - err( "Couldn't allocate a new user.\n" ); + *error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't allocate a new user." }; return NULL; } user->redacted = fileRedacted; @@ -621,17 +602,16 @@ static MPMarshalledUser *mpw_marshall_read_json( json_object_iter json_site; json_object *json_sites = mpw_get_json_section( json_file, "sites" ); json_object_object_foreachC( json_sites, json_site ) { + const char *siteName = json_site.key; value = mpw_get_json_int( json_site.val, "algorithm", (int)user->algorithm ); if (value < MPAlgorithmVersionFirst || value > MPAlgorithmVersionLast) { - err( "Invalid site algorithm version: %u\n", value ); - *error = MPMarshallErrorIllegal; + *error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid site algorithm version: %s: %u", siteName, value ) }; return NULL; } MPAlgorithmVersion siteAlgorithm = (MPAlgorithmVersion)value; MPPasswordType siteType = (MPPasswordType)mpw_get_json_int( json_site.val, "type", (int)user->defaultType ); if (!mpw_nameForType( siteType )) { - err( "Invalid site type: %u\n", siteType ); - *error = MPMarshallErrorIllegal; + *error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid site type: %s: %u", siteName, siteType ) }; return NULL; } uint32_t siteCounter = (uint32_t)mpw_get_json_int( json_site.val, "counter", 1 ); @@ -642,17 +622,16 @@ static MPMarshalledUser *mpw_marshall_read_json( str_lastUsed = mpw_get_json_string( json_site.val, "last_used", NULL ); time_t siteLastUsed = mpw_mktime( str_lastUsed ); if (!siteLastUsed) { - err( "Invalid last used date: %s\n", str_lastUsed ); - *error = MPMarshallErrorIllegal; + *error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid site last used: %s: %s", siteName, str_lastUsed ) }; return NULL; } json_object *json_site_mpw = mpw_get_json_section( json_site.val, "_ext_mpw" ); const char *siteURL = mpw_get_json_string( json_site_mpw, "url", NULL ); - MPMarshalledSite *site = mpw_marshall_site( user, json_site.key, siteType, siteCounter, siteAlgorithm ); + MPMarshalledSite *site = mpw_marshall_site( user, siteName, siteType, siteCounter, siteAlgorithm ); if (!site) { - err( "Couldn't allocate a new site.\n" ); + *error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't allocate a new site." }; return NULL; } @@ -664,7 +643,7 @@ static MPMarshalledUser *mpw_marshall_read_json( if (siteContent && strlen( siteContent )) { if (user->redacted) { if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, site->algorithm, fullName, masterPassword )) { - err( "Couldn't derive master key.\n" ); + *error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." }; return NULL; } @@ -682,7 +661,7 @@ static MPMarshalledUser *mpw_marshall_read_json( } json_object_put( json_file ); - *error = MPMarshallSuccess; + *error = (MPMarshallError){ MPMarshallSuccess }; return user; } @@ -696,28 +675,6 @@ MPMarshalledUser *mpw_marshall_read( return mpw_marshall_read_json( in, masterPassword, error ); } - err( "Unsupported input format: %u\n", inFormat ); - *error = MPMarshallErrorFormat; + *error = (MPMarshallError){ MPMarshallErrorFormat, mpw_str( "Unsupported input format: %u", inFormat ) }; return NULL; } - -const char *mpw_explainMarshallError(const MPMarshallError error) { - switch (error) { - case MPMarshallSuccess: - return "The marshalling operation completed successfully."; - case MPMarshallErrorStructure: - return "An error in the structure of the marshall file interrupted marshalling."; - case MPMarshallErrorFormat: - return "The marshall file uses an unsupported format version."; - case MPMarshallErrorMissing: - return "A required value is missing or not specified."; - case MPMarshallErrorMasterPassword: - return "The given master password is not valid."; - case MPMarshallErrorIllegal: - return "An illegal value was specified."; - case MPMarshallErrorInternal: - return "An internal system error interrupted marshalling."; - } - - return "An unrecognized error occurred."; -} diff --git a/core/c/mpw-marshall.h b/core/c/mpw-marshall.h index 8c00d85d..afd708f7 100644 --- a/core/c/mpw-marshall.h +++ b/core/c/mpw-marshall.h @@ -32,7 +32,7 @@ typedef enum( unsigned int, MPMarshallFormat ) { MPMarshallFormatJSON, }; -typedef enum( unsigned int, MPMarshallError ) { +typedef enum( unsigned int, MPMarshallErrorType ) { /** The marshalling operation completed successfully. */ MPMarshallSuccess, /** An error in the structure of the marshall file interrupted marshalling. */ @@ -48,7 +48,10 @@ typedef enum( unsigned int, MPMarshallError ) { /** An internal system error interrupted marshalling. */ MPMarshallErrorInternal, }; -const char *mpw_explainMarshallError(const MPMarshallError error); +typedef struct MPMarshallError { + MPMarshallErrorType type; + const char *description; +} MPMarshallError; typedef struct MPMarshalledQuestion { const char *keyword; diff --git a/core/c/mpw-types.h b/core/c/mpw-types.h index dea5e436..ea944129 100644 --- a/core/c/mpw-types.h +++ b/core/c/mpw-types.h @@ -62,26 +62,26 @@ typedef enum( unsigned int, MPSiteFeature ) { typedef enum( unsigned int, MPPasswordType ) { /** pg^VMAUBk5x3p%HP%i4= */ - MPPasswordTypeGeneratedMaximum = 0x0 | MPPasswordTypeClassGenerated | 0x0, + MPPasswordTypeGeneratedMaximum = 0x0 | MPPasswordTypeClassGenerated | 0x0, /** BiroYena8:Kixa */ - MPPasswordTypeGeneratedLong = 0x1 | MPPasswordTypeClassGenerated | 0x0, + MPPasswordTypeGeneratedLong = 0x1 | MPPasswordTypeClassGenerated | 0x0, /** BirSuj0- */ - MPPasswordTypeGeneratedMedium = 0x2 | MPPasswordTypeClassGenerated | 0x0, + MPPasswordTypeGeneratedMedium = 0x2 | MPPasswordTypeClassGenerated | 0x0, /** pO98MoD0 */ - MPPasswordTypeGeneratedBasic = 0x4 | MPPasswordTypeClassGenerated | 0x0, + MPPasswordTypeGeneratedBasic = 0x4 | MPPasswordTypeClassGenerated | 0x0, /** Bir8 */ - MPPasswordTypeGeneratedShort = 0x3 | MPPasswordTypeClassGenerated | 0x0, + MPPasswordTypeGeneratedShort = 0x3 | MPPasswordTypeClassGenerated | 0x0, /** 2798 */ - MPPasswordTypeGeneratedPIN = 0x5 | MPPasswordTypeClassGenerated | 0x0, + MPPasswordTypeGeneratedPIN = 0x5 | MPPasswordTypeClassGenerated | 0x0, /** birsujano */ - MPPasswordTypeGeneratedName = 0xE | MPPasswordTypeClassGenerated | 0x0, + MPPasswordTypeGeneratedName = 0xE | MPPasswordTypeClassGenerated | 0x0, /** bir yennoquce fefi */ - MPPasswordTypeGeneratedPhrase = 0xF | MPPasswordTypeClassGenerated | 0x0, + MPPasswordTypeGeneratedPhrase = 0xF | MPPasswordTypeClassGenerated | 0x0, /** Custom saved password. */ - MPPasswordTypeStoredPersonal = 0x0 | MPPasswordTypeClassStored | MPSiteFeatureExportContent, + MPPasswordTypeStoredPersonal = 0x0 | MPPasswordTypeClassStored | MPSiteFeatureExportContent, /** Custom saved password that should not be exported from the device. */ - MPPasswordTypeStoredDevice = 0x1 | MPPasswordTypeClassStored | MPSiteFeatureDevicePrivate, + MPPasswordTypeStoredDevice = 0x1 | MPPasswordTypeClassStored | MPSiteFeatureDevicePrivate, MPPasswordTypeDefault = MPPasswordTypeGeneratedLong, }; diff --git a/core/c/mpw-util.c b/core/c/mpw-util.c index da6ccf50..2c4eb974 100644 --- a/core/c/mpw-util.c +++ b/core/c/mpw-util.c @@ -60,11 +60,29 @@ bool mpw_push_buf(uint8_t **const buffer, size_t *const bufferSize, const void * return true; } -bool mpw_push_string(uint8_t **buffer, size_t *const bufferSize, const char *pushString) { +bool mpw_push_string(uint8_t **const buffer, size_t *const bufferSize, const char *pushString) { return pushString && mpw_push_buf( buffer, bufferSize, pushString, strlen( pushString ) ); } +bool mpw_string_push(char **const string, const char *pushString) { + + size_t stringLength = strlen( *string ); + return pushString && mpw_push_buf( (uint8_t **const)string, &stringLength, pushString, strlen( pushString ) + 1 ); +} + +bool mpw_string_pushf(char **const string, const char *pushFormat, ...) { + + va_list args; + va_start( args, pushFormat ); + char *pushString = NULL; + bool success = vasprintf( &pushString, pushFormat, args ) >= 0 && mpw_string_push( string, pushString ); + va_end( args ); + mpw_free_string( pushString ); + + return success; +} + bool mpw_push_int(uint8_t **const buffer, size_t *const bufferSize, const uint32_t pushInt) { return mpw_push_buf( buffer, bufferSize, &pushInt, sizeof( pushInt ) ); @@ -167,17 +185,26 @@ bool mpw_id_buf_equals(const char *id1, const char *id2) { return true; } -static char **mpw_hex_buf = NULL; -static unsigned int mpw_hex_buf_i = 0; +static char *str_str; + +const char *mpw_str(const char *format, ...) { + + va_list args; + va_start( args, format ); + vasprintf( &str_str, format, args ); + va_end( args ); + + return str_str; +} + +static char **mpw_hex_buf; +static unsigned int mpw_hex_buf_i; const char *mpw_hex(const void *buf, size_t length) { // FIXME: Not thread-safe - if (!mpw_hex_buf) { - mpw_hex_buf = malloc( 10 * sizeof( char * ) ); - for (uint8_t i = 0; i < 10; ++i) - mpw_hex_buf[i] = NULL; - } + if (!mpw_hex_buf) + mpw_hex_buf = calloc( 10, sizeof( char * ) ); mpw_hex_buf_i = (mpw_hex_buf_i + 1) % 10; mpw_hex_buf[mpw_hex_buf_i] = realloc( mpw_hex_buf[mpw_hex_buf_i], length * 2 + 1 ); diff --git a/core/c/mpw-util.h b/core/c/mpw-util.h index 7974fd6b..1353df9a 100644 --- a/core/c/mpw-util.h +++ b/core/c/mpw-util.h @@ -20,6 +20,7 @@ #define _MPW_UTIL_H #include +#include #include "mpw-types.h" @@ -27,41 +28,42 @@ #ifndef trc extern int mpw_verbosity; - #define trc_level 3 - #define trc(...) ({ \ - if (mpw_verbosity >= 3) \ - fprintf( stderr, __VA_ARGS__ ); }) +#define trc_level 3 +#define trc(...) ({ \ + if (mpw_verbosity >= 3) \ + fprintf( stderr, __VA_ARGS__ ); }) #endif #ifndef dbg - #define dbg_level 2 - #define dbg(...) ({ \ - if (mpw_verbosity >= 2) \ - fprintf( stderr, __VA_ARGS__ ); }) +#define dbg_level 2 +#define dbg(...) ({ \ + if (mpw_verbosity >= 2) \ + fprintf( stderr, __VA_ARGS__ ); }) #endif #ifndef inf - #define inf_level 1 - #define inf(...) ({ \ - if (mpw_verbosity >= 1) \ - fprintf( stderr, __VA_ARGS__ ); }) +#define inf_level 1 +#define inf(...) ({ \ + if (mpw_verbosity >= 1) \ + fprintf( stderr, __VA_ARGS__ ); }) #endif #ifndef wrn - #define wrn_level 0 - #define wrn(...) ({ \ - if (mpw_verbosity >= 0) \ - fprintf( stderr, __VA_ARGS__ ); }) +#define wrn_level 0 +#define wrn(...) ({ \ + if (mpw_verbosity >= 0) \ + fprintf( stderr, __VA_ARGS__ ); }) #endif #ifndef err - #define err_level -1 - #define err(...) ({ \ - if (mpw_verbosity >= -1) \ - fprintf( stderr, __VA_ARGS__ ); }) +#define err_level -1 +#define err(...) ({ \ + if (mpw_verbosity >= -1) \ + fprintf( stderr, __VA_ARGS__ ); }) #endif #ifndef ftl - #define ftl_level -2 - #define ftl(...) ({ \ - if (mpw_verbosity >= -2) \ - fprintf( stderr, __VA_ARGS__ ); }) +#define ftl_level -2 +#define ftl(...) ({ \ + if (mpw_verbosity >= -2) \ + fprintf( stderr, __VA_ARGS__ ); }) #endif + #ifndef min #define min(a, b) ({ \ __typeof__ (a) _a = (a); \ @@ -93,6 +95,11 @@ bool mpw_push_buf( /** Push a string onto a buffer. reallocs the given buffer and appends the given string. */ bool mpw_push_string( uint8_t **buffer, size_t *const bufferSize, const char *pushString); +/** Push a string onto another string. reallocs the target string and appends the source string. */ +bool mpw_string_push( + char **const string, const char *pushString); +bool mpw_string_pushf( + char **const string, const char *pushFormat, ...); /** Push an integer onto a buffer. reallocs the given buffer and appends the given integer. */ bool mpw_push_int( uint8_t **const buffer, size_t *const bufferSize, const uint32_t pushInt); @@ -117,6 +124,9 @@ uint8_t const *mpw_hmac_sha256( //// Visualizers. +/** Compose a formatted string. + * @return A C-string in a reused buffer, do not free or store it. */ +const char *mpw_str(const char *format, ...); /** Encode a buffer as a string of hexadecimal characters. * @return A C-string in a reused buffer, do not free or store it. */ const char *mpw_hex(const void *buf, size_t length); diff --git a/platform-independent/cli-c/cli/mpw-cli.c b/platform-independent/cli-c/cli/mpw-cli.c index 9571e727..d9db6a0d 100644 --- a/platform-independent/cli-c/cli/mpw-cli.c +++ b/platform-independent/cli-c/cli/mpw-cli.c @@ -207,8 +207,7 @@ int main(int argc, char *const argv[]) { mpwSitesFormat = MPMarshallFormatFlat; mpwSitesPath = mpwPath( fullName, "mpsites" ); if (!mpwSitesPath || !(mpwSites = fopen( mpwSitesPath, "r" ))) - dbg( "Couldn't open configuration file:\n %s: %s\n", - mpwSitesPath, strerror( errno ) ); + dbg( "Couldn't open configuration file:\n %s: %s\n", mpwSitesPath, strerror( errno ) ); } // Read the user's sites file. @@ -220,17 +219,15 @@ int main(int argc, char *const argv[]) { (bufPointer += (readSize = fread( buf + bufPointer, 1, readAmount, mpwSites ))) && (readSize == readAmount)); if (ferror( mpwSites )) - wrn( "Error while reading configuration file:\n %s: %d", - mpwSitesPath, ferror( mpwSites ) ); + wrn( "Error while reading configuration file:\n %s: %d", mpwSitesPath, ferror( mpwSites ) ); fclose( mpwSites ); // Parse file. - MPMarshallError marshallError = MPMarshallSuccess; + MPMarshallError marshallError = { MPMarshallSuccess }; MPMarshalledUser *user = mpw_marshall_read( buf, mpwSitesFormat, masterPassword, &marshallError ); mpw_free_string( buf ); - if (!user || marshallError != MPMarshallSuccess) - wrn( "Couldn't parse configuration file:\n %s: %s\n", - mpwSitesPath, mpw_explainMarshallError( marshallError ) ); + if (!user || marshallError.type != MPMarshallSuccess) + wrn( "Couldn't parse configuration file:\n %s: %s\n", mpwSitesPath, marshallError.description ); else { // Load defaults. @@ -254,18 +251,15 @@ int main(int argc, char *const argv[]) { if (mpwSitesFormat != MPMarshallFormatJSON) { mpwSitesPath = mpwPath( fullName, "mpsites.json" ); if (!mpwSitesPath || !(mpwSites = fopen( mpwSitesPath, "w" ))) - wrn( "Couldn't create updated configuration file:\n %s: %s\n", - mpwSitesPath, strerror( errno ) ); + wrn( "Couldn't create updated configuration file:\n %s: %s\n", mpwSitesPath, strerror( errno ) ); else { buf = NULL; - if (!mpw_marshall_write( &buf, MPMarshallFormatJSON, user, &marshallError ) || marshallError != MPMarshallSuccess) - wrn( "Couldn't encode updated configuration file:\n %s: %s", - mpwSitesPath, mpw_explainMarshallError( marshallError ) ); + if (!mpw_marshall_write( &buf, MPMarshallFormatJSON, user, &marshallError ) || marshallError.type != MPMarshallSuccess) + wrn( "Couldn't encode updated configuration file:\n %s: %s", mpwSitesPath, marshallError.description ); else if (fwrite( buf, sizeof( char ), strlen( buf ), mpwSites ) != strlen( buf )) - wrn( "Error while writing updated configuration file:\n %s: %d\n", - mpwSitesPath, ferror( mpwSites ) ); + wrn( "Error while writing updated configuration file:\n %s: %d\n", mpwSitesPath, ferror( mpwSites ) ); mpw_free_string( buf ); fclose( mpwSites );