diff --git a/platform-darwin/External/Pearl b/platform-darwin/External/Pearl index 80733afc..34808970 160000 --- a/platform-darwin/External/Pearl +++ b/platform-darwin/External/Pearl @@ -1 +1 @@ -Subproject commit 80733afc7a3ea25e3684840d59350ed533ce8634 +Subproject commit 3480897054f651ee59715aa5534c62928f8abcfb diff --git a/platform-independent/c/cli/src/mpw-cli.c b/platform-independent/c/cli/src/mpw-cli.c index 6d2667e0..ef13eff6 100644 --- a/platform-independent/c/cli/src/mpw-cli.c +++ b/platform-independent/c/cli/src/mpw-cli.c @@ -385,7 +385,7 @@ void cli_masterPassword(Arguments *args, Operation *operation) { mpw_free_string( &operation->masterPassword ); if (args->masterPasswordFD) { - operation->masterPassword = mpw_read_fd( atoi( args->masterPasswordFD ) ); + operation->masterPassword = mpw_read_fd( (int)strtol( args->masterPasswordFD, NULL, 10 ) ); if (!operation->masterPassword && errno) wrn( "Error reading master password from FD %s: %s", args->masterPasswordFD, strerror( errno ) ); } @@ -660,7 +660,7 @@ void cli_siteCounter(Arguments *args, Operation *operation) { if (!operation->site) abort(); - long long int siteCounterInt = atoll( args->siteCounter ); + long long int siteCounterInt = strtoll( args->siteCounter, NULL, 0 ); if (siteCounterInt < MPCounterValueFirst || siteCounterInt > MPCounterValueLast) { ftl( "Invalid site counter: %s", args->siteCounter ); cli_free( args, operation ); @@ -694,19 +694,19 @@ void cli_algorithmVersion(Arguments *args, Operation *operation) { if (!operation->site) abort(); - int algorithmVersionInt = atoi( args->algorithmVersion ); - if (algorithmVersionInt < MPAlgorithmVersionFirst || algorithmVersionInt > MPAlgorithmVersionLast) { + unsigned long algorithmVersion = strtoul( args->algorithmVersion, NULL, 10 ); + if (algorithmVersion < MPAlgorithmVersionFirst || algorithmVersion > MPAlgorithmVersionLast) { ftl( "Invalid algorithm version: %s", args->algorithmVersion ); cli_free( args, operation ); exit( EX_USAGE ); } - operation->site->algorithm = (MPAlgorithmVersion)algorithmVersionInt; + operation->site->algorithm = (MPAlgorithmVersion)algorithmVersion; } void cli_sitesRedacted(Arguments *args, Operation *operation) { if (args->sitesRedacted) - operation->user->redacted = strcmp( args->sitesRedacted, "1" ) == OK; + operation->user->redacted = mpw_get_bool( args->sitesRedacted ); else if (!operation->user->redacted) wrn( "Sites configuration is not redacted. Use -R 1 to change this." ); diff --git a/platform-independent/c/cli/src/mpw-tests-util.c b/platform-independent/c/cli/src/mpw-tests-util.c index 2db385e0..48c4fc60 100644 --- a/platform-independent/c/cli/src/mpw-tests-util.c +++ b/platform-independent/c/cli/src/mpw-tests-util.c @@ -86,7 +86,7 @@ uint32_t mpw_xmlTestCaseInteger(xmlNodePtr context, const char *nodeName) { return 0; xmlChar *string = mpw_xmlTestCaseString( context, nodeName ); - uint32_t integer = string? (uint32_t)atol( (char *)string ): 0; + uint32_t integer = string? (uint32_t)strtoul( (char *)string, NULL, 10 ): 0; xmlFree( string ); return integer; diff --git a/platform-independent/c/core/src/mpw-algorithm_v0.c b/platform-independent/c/core/src/mpw-algorithm_v0.c index 1d98ad48..c2db3e45 100644 --- a/platform-independent/c/core/src/mpw-algorithm_v0.c +++ b/platform-independent/c/core/src/mpw-algorithm_v0.c @@ -199,14 +199,14 @@ const char *mpw_site_derived_password_v0( err( "Missing key size parameter." ); return NULL; } - int resultParamInt = atoi( resultParam ); - if (!resultParamInt) - resultParamInt = 512; - if (resultParamInt < 128 || resultParamInt > 512 || resultParamInt % 8 != 0) { + long parameter = strtol( resultParam, NULL, 10 ); + if (!parameter) + parameter = 512; + if (parameter < 128 || parameter > 512 || parameter % 8 != 0) { err( "Parameter is not a valid key size (should be 128 - 512): %s", resultParam ); return NULL; } - uint16_t keySize = (uint16_t)(resultParamInt / 8); + uint16_t keySize = (uint16_t)(parameter / 8); trc( "keySize: %u", keySize ); // Derive key diff --git a/platform-independent/c/core/src/mpw-marshal-util.c b/platform-independent/c/core/src/mpw-marshal-util.c index f4aba58d..f0b233df 100644 --- a/platform-independent/c/core/src/mpw-marshal-util.c +++ b/platform-independent/c/core/src/mpw-marshal-util.c @@ -38,6 +38,11 @@ char *mpw_get_token(const char **in, const char *eol, const char *delim) { return token; } +bool mpw_get_bool(const char *in) { + + return in && (in[0] == 'y' || in[0] == 't' || strtol( in, NULL, 10 ) > 0); +} + time_t mpw_timegm(const char *time) { // TODO: Support for parsing non-UTC time strings diff --git a/platform-independent/c/core/src/mpw-marshal-util.h b/platform-independent/c/core/src/mpw-marshal-util.h index 0f6ff85c..23536bf7 100644 --- a/platform-independent/c/core/src/mpw-marshal-util.h +++ b/platform-independent/c/core/src/mpw-marshal-util.h @@ -36,6 +36,10 @@ MP_LIBS_END * @return A string (allocated) containing the token or NULL if the delim wasn't found before eol. */ char *mpw_get_token( const char **in, const char *eol, const char *delim); +/** Get a boolean value as expressed by the given string. + * @return true if the string is not NULL and holds a number larger than 0, or starts with a t (for true) or y (for yes). */ +bool mpw_get_bool( + const char *in); /** Convert an RFC 3339 time string into epoch time. * @return ERR if the string could not be parsed. */ time_t mpw_timegm( diff --git a/platform-independent/c/core/src/mpw-marshal.c b/platform-independent/c/core/src/mpw-marshal.c index 401d6048..20e81249 100644 --- a/platform-independent/c/core/src/mpw-marshal.c +++ b/platform-independent/c/core/src/mpw-marshal.c @@ -890,29 +890,29 @@ static void mpw_marshal_read_flat( continue; } - if (strcmp( headerName, "Format" ) == OK) - format = (unsigned int)atoi( headerValue ); - if (strcmp( headerName, "Date" ) == OK) + if (mpw_strcasecmp( headerName, "Format" ) == OK) + format = (unsigned int)strtoul( headerValue, NULL, 10 ); + if (mpw_strcasecmp( headerName, "Date" ) == OK) exportDate = mpw_timegm( headerValue ); - if (strcmp( headerName, "Passwords" ) == OK) - importRedacted = strcmp( headerValue, "VISIBLE" ) != OK; - if (strcmp( headerName, "Algorithm" ) == OK) { - int value = atoi( headerValue ); + if (mpw_strcasecmp( headerName, "Passwords" ) == OK) + importRedacted = mpw_strcasecmp( headerValue, "VISIBLE" ) != OK; + if (mpw_strcasecmp( headerName, "Algorithm" ) == OK) { + unsigned long value = strtoul( headerValue, NULL, 10 ); if (value < MPAlgorithmVersionFirst || value > MPAlgorithmVersionLast) file->error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid user algorithm version: %s", headerValue ) }; else algorithm = (MPAlgorithmVersion)value; } - if (strcmp( headerName, "Avatar" ) == OK) - avatar = (unsigned int)atoi( headerValue ); - if (strcmp( headerName, "Full Name" ) == OK || strcmp( headerName, "User Name" ) == OK) + if (mpw_strcasecmp( headerName, "Avatar" ) == OK) + avatar = (unsigned int)strtoul( headerValue, NULL, 10 ); + if (mpw_strcasecmp( headerName, "Full Name" ) == OK || mpw_strcasecmp( headerName, "User Name" ) == OK) fullName = mpw_strdup( headerValue ); - if (strcmp( headerName, "Identicon" ) == OK) + if (mpw_strcasecmp( headerName, "Identicon" ) == OK) identicon = mpw_identicon_encoded( headerValue ); - if (strcmp( headerName, "Key ID" ) == OK) + if (mpw_strcasecmp( headerName, "Key ID" ) == OK) keyID = mpw_strdup( headerValue ); - if (strcmp( headerName, "Default Type" ) == OK) { - int value = atoi( headerValue ); + if (mpw_strcasecmp( headerName, "Default Type" ) == OK) { + unsigned long value = strtoul( headerValue, NULL, 10 ); if (!mpw_type_short_name( (MPResultType)value )) file->error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid user default type: %s", headerValue ) }; else @@ -970,18 +970,18 @@ static void mpw_marshal_read_flat( } if (siteName && str_type && str_counter && str_algorithm && str_uses && str_lastUsed) { - MPResultType siteType = (MPResultType)atoi( str_type ); + MPResultType siteType = (MPResultType)strtoul( str_type, NULL, 10 ); if (!mpw_type_short_name( siteType )) { file->error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid site type: %s: %s", siteName, str_type ) }; continue; } - long long int value = atoll( str_counter ); + long long int value = strtoll( str_counter, NULL, 10 ); if (value < MPCounterValueFirst || value > MPCounterValueLast) { file->error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid site counter: %s: %s", siteName, str_counter ) }; continue; } MPCounterValue siteCounter = (MPCounterValue)value; - value = atoll( str_algorithm ); + value = strtoll( str_algorithm, NULL, 0 ); if (value < MPAlgorithmVersionFirst || value > MPAlgorithmVersionLast) { file->error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid site algorithm: %s: %s", siteName, str_algorithm ) @@ -1001,10 +1001,12 @@ static void mpw_marshal_read_flat( mpw_marshal_data_set_num( siteCounter, file->data, "sites", siteName, "counter", NULL ); mpw_marshal_data_set_num( siteAlgorithm, file->data, "sites", siteName, "algorithm", NULL ); mpw_marshal_data_set_num( siteType, file->data, "sites", siteName, "type", NULL ); - mpw_marshal_data_set_str( siteResultState && strlen( siteResultState )? siteResultState: NULL, file->data, "sites", siteName, "password", NULL ); + mpw_marshal_data_set_str( siteResultState && strlen( siteResultState )? siteResultState: NULL, file->data, "sites", siteName, + "password", NULL ); mpw_marshal_data_set_num( MPResultTypeDefault, file->data, "sites", siteName, "login_type", NULL ); - mpw_marshal_data_set_str( siteLoginState && strlen( siteLoginState )? siteLoginState: NULL, file->data, "sites", siteName, "login_name", NULL ); - mpw_marshal_data_set_num( atoi( str_uses ), file->data, "sites", siteName, "uses", NULL ); + mpw_marshal_data_set_str( siteLoginState && strlen( siteLoginState )? siteLoginState: NULL, file->data, "sites", siteName, + "login_name", NULL ); + mpw_marshal_data_set_num( strtol( str_uses, NULL, 10 ), file->data, "sites", siteName, "uses", NULL ); if (strftime( dateString, sizeof( dateString ), "%FT%TZ", gmtime( &siteLastUsed ) )) mpw_marshal_data_set_str( dateString, file->data, "sites", siteName, "last_used", NULL ); } diff --git a/platform-independent/c/core/src/mpw-marshal.h b/platform-independent/c/core/src/mpw-marshal.h index d3a23b89..29ea37a7 100644 --- a/platform-independent/c/core/src/mpw-marshal.h +++ b/platform-independent/c/core/src/mpw-marshal.h @@ -118,7 +118,7 @@ typedef struct MPMarshalledInfo { /** User metadata: The identicon that was generated to represent this file's user identity. */ MPIdenticon identicon; /** A unique identifier (hex) for the user's master key, primarily for authentication/verification. */ - const char *keyID; + MPKeyID keyID; /** User metadata: Date of the most recent action taken by this user. */ time_t lastUsed; } MPMarshalledInfo; @@ -176,7 +176,7 @@ typedef struct MPMarshalledUser { /** Algorithm version to use for user operations (eg. key ID operations). */ MPAlgorithmVersion algorithm; /** A unique identifier (hex) for the user's master key, primarily for authentication/verification. */ - const char *keyID; + MPKeyID keyID; /** The initial result type to use for new sites created by the user. */ MPResultType defaultType; /** User metadata: Date of the most recent action taken by this user. */ diff --git a/platform-independent/c/core/src/mpw-util.c b/platform-independent/c/core/src/mpw-util.c index fa1ebacb..e87996c9 100644 --- a/platform-independent/c/core/src/mpw-util.c +++ b/platform-independent/c/core/src/mpw-util.c @@ -106,6 +106,9 @@ void mpw_log_ssink(LogLevel level, const char *file, int line, const char *funct if (!sinks_count) mpw_log_sink_file( &record ); + if (record.level <= LogLevelError) { + /* error breakpoint */; + } if (record.level <= LogLevelFatal) abort(); } @@ -495,7 +498,7 @@ const MPKeyID mpw_id_buf(const void *buf, const size_t length) { return mpw_hex( hash, sizeof( hash ) / sizeof( uint8_t ) ); } -bool mpw_id_buf_equals(const char *id1, const char *id2) { +bool mpw_id_buf_equals(MPKeyID id1, MPKeyID id2) { if (!id1 || !id2) return !id1 && !id2; @@ -504,11 +507,7 @@ bool mpw_id_buf_equals(const char *id1, const char *id2) { if (size != strlen( id2 )) return false; - for (size_t c = 0; c < size; ++c) - if (tolower( id1[c] ) != tolower( id2[c] )) - return false; - - return true; + return mpw_strncasecmp( id1, id2, size ) == OK; } const char *mpw_str(const char *format, ...) { @@ -665,10 +664,15 @@ char *mpw_strndup(const char *src, const size_t max) { return dst; } +int mpw_strcasecmp(const char *s1, const char *s2) { + + return mpw_strncasecmp( s1, s2, s1 && s2? min( strlen( s1 ), strlen( s2 ) ): 0 ); +} + int mpw_strncasecmp(const char *s1, const char *s2, size_t max) { - int cmp = 0; - for (; !cmp && max-- > 0 && s1 && s2; ++s1, ++s2) + int cmp = s1 && s2 && max > 0? 0: s1? 1: -1; + for (; !cmp && max && max-- > 0 && s1 && s2; ++s1, ++s2) cmp = tolower( (unsigned char)*s1 ) - tolower( (unsigned char)*s2 ); return cmp; diff --git a/platform-independent/c/core/src/mpw-util.h b/platform-independent/c/core/src/mpw-util.h index 180c4dad..145890f6 100644 --- a/platform-independent/c/core/src/mpw-util.h +++ b/platform-independent/c/core/src/mpw-util.h @@ -252,7 +252,7 @@ const uint8_t *mpw_unhex(const char *hex, size_t *length); const MPKeyID mpw_id_buf(const void *buf, const size_t length); /** Compare two fingerprints for equality. * @return true if the buffers represent identical fingerprints or are both NULL. */ -bool mpw_id_buf_equals(const char *id1, const char *id2); +bool mpw_id_buf_equals(MPKeyID id1, MPKeyID id2); //// String utilities. @@ -269,6 +269,8 @@ char *mpw_strdup(const char *src); /** Drop-in for POSIX strndup(3). * @return A string (allocated) with no more than max bytes copied from src or NULL if src is missing or the buffer could not be allocated. */ char *mpw_strndup(const char *src, const size_t max); +/** Drop-in for POSIX strcasecmp(3). */ +int mpw_strcasecmp(const char *s1, const char *s2); /** Drop-in for POSIX strncasecmp(3). */ int mpw_strncasecmp(const char *s1, const char *s2, const size_t max);