NULL out free'ed references.
This commit is contained in:
parent
0a42579d9e
commit
a8949ca07e
@ -18,7 +18,6 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <arpa/inet.h>
|
|
||||||
|
|
||||||
#include "mpw-types.h"
|
#include "mpw-types.h"
|
||||||
#include "mpw-util.h"
|
#include "mpw-util.h"
|
||||||
@ -71,7 +70,7 @@ static MPMasterKey mpw_masterKey_v0(
|
|||||||
// Calculate the master key.
|
// Calculate the master key.
|
||||||
trc( "masterKey: scrypt( masterPassword, masterKeySalt, N=%lu, r=%u, p=%u )\n", MP_N, MP_r, MP_p );
|
trc( "masterKey: scrypt( masterPassword, masterKeySalt, N=%lu, r=%u, p=%u )\n", MP_N, MP_r, MP_p );
|
||||||
MPMasterKey masterKey = mpw_kdf_scrypt( MPMasterKeySize, masterPassword, masterKeySalt, masterKeySaltSize, MP_N, MP_r, MP_p );
|
MPMasterKey masterKey = mpw_kdf_scrypt( MPMasterKeySize, masterPassword, masterKeySalt, masterKeySaltSize, MP_N, MP_r, MP_p );
|
||||||
mpw_free( masterKeySalt, masterKeySaltSize );
|
mpw_free( &masterKeySalt, masterKeySaltSize );
|
||||||
if (!masterKey) {
|
if (!masterKey) {
|
||||||
err( "Could not allocate master key: %s\n", strerror( errno ) );
|
err( "Could not allocate master key: %s\n", strerror( errno ) );
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -104,9 +103,8 @@ static MPSiteKey mpw_siteKey_v0(
|
|||||||
mpw_push_int( &siteSalt, &siteSaltSize, htonl( mpw_utf8_strlen( keyContext ) ) );
|
mpw_push_int( &siteSalt, &siteSaltSize, htonl( mpw_utf8_strlen( keyContext ) ) );
|
||||||
mpw_push_string( &siteSalt, &siteSaltSize, keyContext );
|
mpw_push_string( &siteSalt, &siteSaltSize, keyContext );
|
||||||
}
|
}
|
||||||
if (!siteSalt || !siteSaltSize) {
|
if (!siteSalt) {
|
||||||
err( "Could not allocate site salt: %s\n", strerror( errno ) );
|
err( "Could not allocate site salt: %s\n", strerror( errno ) );
|
||||||
mpw_free( siteSalt, siteSaltSize );
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
trc( " => siteSalt.id: %s\n", mpw_id_buf( siteSalt, siteSaltSize ) );
|
trc( " => siteSalt.id: %s\n", mpw_id_buf( siteSalt, siteSaltSize ) );
|
||||||
@ -114,7 +112,7 @@ static MPSiteKey mpw_siteKey_v0(
|
|||||||
trc( "siteKey: hmac-sha256( masterKey.id=%s, siteSalt )\n",
|
trc( "siteKey: hmac-sha256( masterKey.id=%s, siteSalt )\n",
|
||||||
mpw_id_buf( masterKey, MPMasterKeySize ) );
|
mpw_id_buf( masterKey, MPMasterKeySize ) );
|
||||||
MPSiteKey siteKey = mpw_hash_hmac_sha256( masterKey, MPMasterKeySize, siteSalt, siteSaltSize );
|
MPSiteKey siteKey = mpw_hash_hmac_sha256( masterKey, MPMasterKeySize, siteSalt, siteSaltSize );
|
||||||
mpw_free( siteSalt, siteSaltSize );
|
mpw_free( &siteSalt, siteSaltSize );
|
||||||
if (!siteKey) {
|
if (!siteKey) {
|
||||||
err( "Could not derive site key: %s\n", strerror( errno ) );
|
err( "Could not derive site key: %s\n", strerror( errno ) );
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -163,19 +161,19 @@ static const char *mpw_sitePasswordFromCrypt_v0(
|
|||||||
size_t bufSize = (size_t)mpw_base64_decode( cipherBuf, cipherText );
|
size_t bufSize = (size_t)mpw_base64_decode( cipherBuf, cipherText );
|
||||||
if ((int)bufSize < 0) {
|
if ((int)bufSize < 0) {
|
||||||
err( "Base64 decoding error." );
|
err( "Base64 decoding error." );
|
||||||
mpw_free( cipherBuf, mpw_base64_decode_max( cipherText ) );
|
mpw_free( &cipherBuf, mpw_base64_decode_max( cipherText ) );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
trc( "b64 decoded: %zu bytes = %s\n", bufSize, mpw_hex( cipherBuf, bufSize ) );
|
trc( "b64 decoded: %zu bytes = %s\n", bufSize, mpw_hex( cipherBuf, bufSize ) );
|
||||||
|
|
||||||
// Decrypt
|
// Decrypt
|
||||||
const uint8_t *plainBytes = mpw_aes_decrypt( masterKey, MPMasterKeySize, cipherBuf, bufSize );
|
const uint8_t *plainBytes = mpw_aes_decrypt( masterKey, MPMasterKeySize, cipherBuf, bufSize );
|
||||||
|
mpw_free( &cipherBuf, bufSize );
|
||||||
const char *plainText = strndup( (char *)plainBytes, bufSize );
|
const char *plainText = strndup( (char *)plainBytes, bufSize );
|
||||||
mpw_free( plainBytes, bufSize );
|
mpw_free( &plainBytes, bufSize );
|
||||||
if (!plainText)
|
if (!plainText)
|
||||||
err( "AES decryption error: %s\n", strerror( errno ) );
|
err( "AES decryption error: %s\n", strerror( errno ) );
|
||||||
trc( "decrypted -> plainText: %s = %s\n", plainText, mpw_hex( plainText, sizeof( plainText ) ) );
|
trc( "decrypted -> plainText: %s = %s\n", plainText, mpw_hex( plainText, sizeof( plainText ) ) );
|
||||||
mpw_free( cipherBuf, bufSize );
|
|
||||||
|
|
||||||
return plainText;
|
return plainText;
|
||||||
}
|
}
|
||||||
@ -206,15 +204,16 @@ static const char *mpw_sitePasswordFromDerive_v0(
|
|||||||
|
|
||||||
// Base64-encode
|
// Base64-encode
|
||||||
size_t b64Max = mpw_base64_encode_max( keySize );
|
size_t b64Max = mpw_base64_encode_max( keySize );
|
||||||
char *sitePassword = calloc( 1, b64Max + 1 );
|
char *b64Key = calloc( 1, b64Max + 1 );
|
||||||
if (mpw_base64_encode( sitePassword, resultKey, keySize ) < 0) {
|
if (mpw_base64_encode( b64Key, resultKey, keySize ) < 0) {
|
||||||
err( "Base64 encoding error." );
|
err( "Base64 encoding error." );
|
||||||
mpw_free_string( sitePassword );
|
mpw_free_string( &b64Key );
|
||||||
sitePassword = NULL;
|
|
||||||
}
|
}
|
||||||
trc( "b64 encoded -> key.id: %s\n", mpw_id_buf( sitePassword, strlen( sitePassword ) ) );
|
else
|
||||||
|
trc( "b64 encoded -> key.id: %s\n", mpw_id_buf( b64Key, strlen( b64Key ) ) );
|
||||||
|
mpw_free( &resultKey, keySize );
|
||||||
|
|
||||||
return sitePassword;
|
return b64Key;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
err( "Unsupported derived password type: %d\n", resultType );
|
err( "Unsupported derived password type: %d\n", resultType );
|
||||||
@ -239,11 +238,11 @@ static const char *mpw_siteState_v0(
|
|||||||
char *cipherText = calloc( 1, b64Max + 1 );
|
char *cipherText = calloc( 1, b64Max + 1 );
|
||||||
if (mpw_base64_encode( cipherText, cipherBuf, bufSize ) < 0) {
|
if (mpw_base64_encode( cipherText, cipherBuf, bufSize ) < 0) {
|
||||||
err( "Base64 encoding error." );
|
err( "Base64 encoding error." );
|
||||||
mpw_free_string( cipherText );
|
mpw_free_string( &cipherText );
|
||||||
cipherText = NULL;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
trc( "b64 encoded -> cipherText: %s = %s\n", cipherText, mpw_hex( cipherText, sizeof( cipherText ) ) );
|
trc( "b64 encoded -> cipherText: %s = %s\n", cipherText, mpw_hex( cipherText, sizeof( cipherText ) ) );
|
||||||
mpw_free( cipherBuf, bufSize );
|
mpw_free( &cipherBuf, bufSize );
|
||||||
|
|
||||||
return cipherText;
|
return cipherText;
|
||||||
}
|
}
|
||||||
|
@ -69,9 +69,8 @@ static MPSiteKey mpw_siteKey_v2(
|
|||||||
mpw_push_int( &siteSalt, &siteSaltSize, htonl( strlen( keyContext ) ) );
|
mpw_push_int( &siteSalt, &siteSaltSize, htonl( strlen( keyContext ) ) );
|
||||||
mpw_push_string( &siteSalt, &siteSaltSize, keyContext );
|
mpw_push_string( &siteSalt, &siteSaltSize, keyContext );
|
||||||
}
|
}
|
||||||
if (!siteSalt || !siteSaltSize) {
|
if (!siteSalt) {
|
||||||
err( "Could not allocate site salt: %s\n", strerror( errno ) );
|
err( "Could not allocate site salt: %s\n", strerror( errno ) );
|
||||||
mpw_free( siteSalt, siteSaltSize );
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
trc( " => siteSalt.id: %s\n", mpw_id_buf( siteSalt, siteSaltSize ) );
|
trc( " => siteSalt.id: %s\n", mpw_id_buf( siteSalt, siteSaltSize ) );
|
||||||
@ -79,7 +78,7 @@ static MPSiteKey mpw_siteKey_v2(
|
|||||||
trc( "siteKey: hmac-sha256( masterKey.id=%s, siteSalt )\n",
|
trc( "siteKey: hmac-sha256( masterKey.id=%s, siteSalt )\n",
|
||||||
mpw_id_buf( masterKey, MPMasterKeySize ) );
|
mpw_id_buf( masterKey, MPMasterKeySize ) );
|
||||||
MPSiteKey siteKey = mpw_hash_hmac_sha256( masterKey, MPMasterKeySize, siteSalt, siteSaltSize );
|
MPSiteKey siteKey = mpw_hash_hmac_sha256( masterKey, MPMasterKeySize, siteSalt, siteSaltSize );
|
||||||
mpw_free( siteSalt, siteSaltSize );
|
mpw_free( &siteSalt, siteSaltSize );
|
||||||
if (!siteKey) {
|
if (!siteKey) {
|
||||||
err( "Could not allocate site key: %s\n", strerror( errno ) );
|
err( "Could not allocate site key: %s\n", strerror( errno ) );
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -64,7 +64,7 @@ static MPMasterKey mpw_masterKey_v3(
|
|||||||
// Calculate the master key.
|
// Calculate the master key.
|
||||||
trc( "masterKey: scrypt( masterPassword, masterKeySalt, N=%lu, r=%u, p=%u )\n", MP_N, MP_r, MP_p );
|
trc( "masterKey: scrypt( masterPassword, masterKeySalt, N=%lu, r=%u, p=%u )\n", MP_N, MP_r, MP_p );
|
||||||
MPMasterKey masterKey = mpw_kdf_scrypt( MPMasterKeySize, masterPassword, masterKeySalt, masterKeySaltSize, MP_N, MP_r, MP_p );
|
MPMasterKey masterKey = mpw_kdf_scrypt( MPMasterKeySize, masterPassword, masterKeySalt, masterKeySaltSize, MP_N, MP_r, MP_p );
|
||||||
mpw_free( masterKeySalt, masterKeySaltSize );
|
mpw_free( &masterKeySalt, masterKeySaltSize );
|
||||||
if (!masterKey) {
|
if (!masterKey) {
|
||||||
err( "Could not allocate master key: %s\n", strerror( errno ) );
|
err( "Could not allocate master key: %s\n", strerror( errno ) );
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -100,10 +100,9 @@ bool mpw_update_masterKey(MPMasterKey *masterKey, MPAlgorithmVersion *masterKeyA
|
|||||||
const char *fullName, const char *masterPassword) {
|
const char *fullName, const char *masterPassword) {
|
||||||
|
|
||||||
if (*masterKeyAlgorithm != targetKeyAlgorithm) {
|
if (*masterKeyAlgorithm != targetKeyAlgorithm) {
|
||||||
mpw_free( *masterKey, MPMasterKeySize );
|
mpw_free( masterKey, MPMasterKeySize );
|
||||||
*masterKeyAlgorithm = targetKeyAlgorithm;
|
*masterKeyAlgorithm = targetKeyAlgorithm;
|
||||||
*masterKey = mpw_masterKey(
|
*masterKey = mpw_masterKey( fullName, masterPassword, *masterKeyAlgorithm );
|
||||||
fullName, masterPassword, *masterKeyAlgorithm );
|
|
||||||
if (!*masterKey) {
|
if (!*masterKey) {
|
||||||
err( "Couldn't derive master key for user %s, algorithm %d.\n", fullName, *masterKeyAlgorithm );
|
err( "Couldn't derive master key for user %s, algorithm %d.\n", fullName, *masterKeyAlgorithm );
|
||||||
return false;
|
return false;
|
||||||
|
@ -94,42 +94,39 @@ MPMarshalledQuestion *mpw_marshal_question(
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool mpw_marshal_info_free(
|
bool mpw_marshal_info_free(
|
||||||
MPMarshallInfo *info) {
|
MPMarshallInfo **info) {
|
||||||
|
|
||||||
if (!info)
|
if (!info || !*info)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
bool success = true;
|
bool success = true;
|
||||||
success &= mpw_free_string( info->fullName );
|
success &= mpw_free_strings( &(*info)->fullName, &(*info)->keyID, NULL );
|
||||||
success &= mpw_free_string( info->keyID );
|
|
||||||
success &= mpw_free( info, sizeof( MPMarshallInfo ) );
|
success &= mpw_free( info, sizeof( MPMarshallInfo ) );
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mpw_marshal_free(
|
bool mpw_marshal_free(
|
||||||
MPMarshalledUser *user) {
|
MPMarshalledUser **user) {
|
||||||
|
|
||||||
if (!user)
|
if (!user)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
bool success = true;
|
bool success = true;
|
||||||
for (size_t s = 0; s < user->sites_count; ++s) {
|
success &= mpw_free_strings( &(*user)->fullName, &(*user)->masterPassword, NULL );
|
||||||
MPMarshalledSite *site = &user->sites[s];
|
|
||||||
success &= mpw_free_string( site->name );
|
for (size_t s = 0; s < (*user)->sites_count; ++s) {
|
||||||
success &= mpw_free_string( site->content );
|
MPMarshalledSite *site = &(*user)->sites[s];
|
||||||
success &= mpw_free_string( site->loginContent );
|
success &= mpw_free_strings( &site->name, &site->content, &site->loginContent, &site->url, NULL );
|
||||||
success &= mpw_free_string( site->url );
|
|
||||||
for (size_t q = 0; q < site->questions_count; ++q) {
|
for (size_t q = 0; q < site->questions_count; ++q) {
|
||||||
MPMarshalledQuestion *question = &site->questions[q];
|
MPMarshalledQuestion *question = &site->questions[q];
|
||||||
success &= mpw_free_string( question->keyword );
|
success &= mpw_free_strings( &question->keyword, &question->content, NULL );
|
||||||
success &= mpw_free_string( question->content );
|
|
||||||
}
|
}
|
||||||
success &= mpw_free( site->questions, sizeof( MPMarshalledQuestion ) * site->questions_count );
|
success &= mpw_free( &site->questions, sizeof( MPMarshalledQuestion ) * site->questions_count );
|
||||||
}
|
}
|
||||||
success &= mpw_free( user->sites, sizeof( MPMarshalledSite ) * user->sites_count );
|
|
||||||
success &= mpw_free_string( user->fullName );
|
success &= mpw_free( &(*user)->sites, sizeof( MPMarshalledSite ) * (*user)->sites_count );
|
||||||
success &= mpw_free_string( user->masterPassword );
|
|
||||||
success &= mpw_free( user, sizeof( MPMarshalledUser ) );
|
success &= mpw_free( user, sizeof( MPMarshalledUser ) );
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
@ -210,10 +207,9 @@ static bool mpw_marshall_write_flat(
|
|||||||
mpw_string_pushf( 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,
|
dateString, (long)site->uses, (long)site->type, (long)site->algorithm, (long)site->counter,
|
||||||
loginContent?: "", site->name, content?: "" );
|
loginContent?: "", site->name, content?: "" );
|
||||||
mpw_free_string( content );
|
mpw_free_strings( &content, &loginContent, NULL );
|
||||||
mpw_free_string( loginContent );
|
|
||||||
}
|
}
|
||||||
mpw_free( masterKey, MPMasterKeySize );
|
mpw_free( &masterKey, MPMasterKeySize );
|
||||||
|
|
||||||
*error = (MPMarshallError){ .type = MPMarshallSuccess };
|
*error = (MPMarshallError){ .type = MPMarshallSuccess };
|
||||||
return true;
|
return true;
|
||||||
@ -336,11 +332,11 @@ static bool mpw_marshall_write_json(
|
|||||||
if (site->url)
|
if (site->url)
|
||||||
json_object_object_add( json_site_mpw, "url", json_object_new_string( site->url ) );
|
json_object_object_add( json_site_mpw, "url", json_object_new_string( site->url ) );
|
||||||
|
|
||||||
mpw_free_string( content );
|
mpw_free_strings( &content, &loginContent );
|
||||||
}
|
}
|
||||||
|
|
||||||
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_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 );
|
mpw_free( &masterKey, MPMasterKeySize );
|
||||||
json_object_put( json_file );
|
json_object_put( json_file );
|
||||||
|
|
||||||
*error = (MPMarshallError){ .type = MPMarshallSuccess };
|
*error = (MPMarshallError){ .type = MPMarshallSuccess };
|
||||||
@ -405,8 +401,7 @@ static void mpw_marshall_read_flat_info(
|
|||||||
if (strcmp( headerName, "Date" ) == 0)
|
if (strcmp( headerName, "Date" ) == 0)
|
||||||
info->date = mpw_mktime( headerValue );
|
info->date = mpw_mktime( headerValue );
|
||||||
|
|
||||||
mpw_free_string( headerName );
|
mpw_free_strings( &headerName, &headerValue, NULL );
|
||||||
mpw_free_string( headerValue );
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -488,8 +483,7 @@ static MPMarshalledUser *mpw_marshall_read_flat(
|
|||||||
if (strcmp( headerName, "Passwords" ) == 0)
|
if (strcmp( headerName, "Passwords" ) == 0)
|
||||||
importRedacted = strcmp( headerValue, "VISIBLE" ) != 0;
|
importRedacted = strcmp( headerValue, "VISIBLE" ) != 0;
|
||||||
|
|
||||||
mpw_free_string( headerName );
|
mpw_free_strings( &headerName, &headerValue, NULL );
|
||||||
mpw_free_string( headerValue );
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!headerEnded)
|
if (!headerEnded)
|
||||||
@ -531,7 +525,7 @@ static MPMarshalledUser *mpw_marshall_read_flat(
|
|||||||
if (typeAndVersion) {
|
if (typeAndVersion) {
|
||||||
str_type = strdup( strtok( typeAndVersion, ":" ) );
|
str_type = strdup( strtok( typeAndVersion, ":" ) );
|
||||||
str_algorithm = strdup( strtok( NULL, "" ) );
|
str_algorithm = strdup( strtok( NULL, "" ) );
|
||||||
mpw_free_string( typeAndVersion );
|
mpw_free_string( &typeAndVersion );
|
||||||
}
|
}
|
||||||
str_counter = strdup( "1" );
|
str_counter = strdup( "1" );
|
||||||
siteLoginName = NULL;
|
siteLoginName = NULL;
|
||||||
@ -547,7 +541,7 @@ static MPMarshalledUser *mpw_marshall_read_flat(
|
|||||||
str_type = strdup( strtok( typeAndVersionAndCounter, ":" ) );
|
str_type = strdup( strtok( typeAndVersionAndCounter, ":" ) );
|
||||||
str_algorithm = strdup( strtok( NULL, ":" ) );
|
str_algorithm = strdup( strtok( NULL, ":" ) );
|
||||||
str_counter = strdup( strtok( NULL, "" ) );
|
str_counter = strdup( strtok( NULL, "" ) );
|
||||||
mpw_free_string( typeAndVersionAndCounter );
|
mpw_free_string( &typeAndVersionAndCounter );
|
||||||
}
|
}
|
||||||
siteLoginName = mpw_get_token( &positionInLine, endOfLine, "\t\n" );
|
siteLoginName = mpw_get_token( &positionInLine, endOfLine, "\t\n" );
|
||||||
siteName = mpw_get_token( &positionInLine, endOfLine, "\t\n" );
|
siteName = mpw_get_token( &positionInLine, endOfLine, "\t\n" );
|
||||||
@ -606,6 +600,7 @@ static MPMarshalledUser *mpw_marshall_read_flat(
|
|||||||
if (siteLoginName && strlen( siteLoginName ))
|
if (siteLoginName && strlen( siteLoginName ))
|
||||||
site->loginContent = mpw_siteState( masterKey, site->name, MPCounterValueInitial,
|
site->loginContent = mpw_siteState( masterKey, site->name, MPCounterValueInitial,
|
||||||
MPKeyPurposeIdentification, NULL, site->loginType, siteLoginName, site->algorithm );
|
MPKeyPurposeIdentification, NULL, site->loginType, siteLoginName, site->algorithm );
|
||||||
|
dbg( "site->content: %p\n", (void *)site->content );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Redacted
|
// Redacted
|
||||||
@ -613,6 +608,7 @@ static MPMarshalledUser *mpw_marshall_read_flat(
|
|||||||
site->content = strdup( siteContent );
|
site->content = strdup( siteContent );
|
||||||
if (siteLoginName && strlen( siteLoginName ))
|
if (siteLoginName && strlen( siteLoginName ))
|
||||||
site->loginContent = strdup( siteLoginName );
|
site->loginContent = strdup( siteLoginName );
|
||||||
|
dbg( "site->content: %p\n", (void *)site->content );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -623,18 +619,11 @@ static MPMarshalledUser *mpw_marshall_read_flat(
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
mpw_free_string( str_lastUsed );
|
mpw_free_strings( &str_lastUsed, &str_uses, &str_type, &str_algorithm, &str_counter, NULL );
|
||||||
mpw_free_string( str_uses );
|
mpw_free_strings( &siteLoginName, &siteName, &siteContent, NULL );
|
||||||
mpw_free_string( str_type );
|
|
||||||
mpw_free_string( str_algorithm );
|
|
||||||
mpw_free_string( str_counter );
|
|
||||||
mpw_free_string( siteLoginName );
|
|
||||||
mpw_free_string( siteName );
|
|
||||||
mpw_free_string( siteContent );
|
|
||||||
}
|
}
|
||||||
mpw_free_string( fullName );
|
mpw_free_strings( &fullName, &keyID, NULL );
|
||||||
mpw_free_string( keyID );
|
mpw_free( &masterKey, MPMasterKeySize );
|
||||||
mpw_free( masterKey, MPMasterKeySize );
|
|
||||||
|
|
||||||
*error = (MPMarshallError){ .type = MPMarshallSuccess };
|
*error = (MPMarshallError){ .type = MPMarshallSuccess };
|
||||||
return user;
|
return user;
|
||||||
@ -796,6 +785,7 @@ static MPMarshalledUser *mpw_marshall_read_json(
|
|||||||
if (siteLoginName && strlen( siteLoginName ))
|
if (siteLoginName && strlen( siteLoginName ))
|
||||||
site->loginContent = mpw_siteState( masterKey, site->name, MPCounterValueInitial,
|
site->loginContent = mpw_siteState( masterKey, site->name, MPCounterValueInitial,
|
||||||
MPKeyPurposeIdentification, NULL, site->loginType, siteLoginName, site->algorithm );
|
MPKeyPurposeIdentification, NULL, site->loginType, siteLoginName, site->algorithm );
|
||||||
|
dbg( "site->content: %p\n", (void *)site->content );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Redacted
|
// Redacted
|
||||||
@ -803,6 +793,7 @@ static MPMarshalledUser *mpw_marshall_read_json(
|
|||||||
site->content = strdup( siteContent );
|
site->content = strdup( siteContent );
|
||||||
if (siteLoginName && strlen( siteLoginName ))
|
if (siteLoginName && strlen( siteLoginName ))
|
||||||
site->loginContent = strdup( siteLoginName );
|
site->loginContent = strdup( siteLoginName );
|
||||||
|
dbg( "site->content: %p\n", (void *)site->content );
|
||||||
}
|
}
|
||||||
|
|
||||||
json_object_iter json_site_question;
|
json_object_iter json_site_question;
|
||||||
|
@ -130,9 +130,9 @@ MPMarshalledQuestion *mpw_marshal_question(
|
|||||||
MPMarshalledSite *site, const char *keyword);
|
MPMarshalledSite *site, const char *keyword);
|
||||||
/** Free the given user object and all associated data. */
|
/** Free the given user object and all associated data. */
|
||||||
bool mpw_marshal_info_free(
|
bool mpw_marshal_info_free(
|
||||||
MPMarshallInfo *info);
|
MPMarshallInfo **info);
|
||||||
bool mpw_marshal_free(
|
bool mpw_marshal_free(
|
||||||
MPMarshalledUser *user);
|
MPMarshalledUser **user);
|
||||||
|
|
||||||
//// Format.
|
//// Format.
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
int mpw_verbosity = inf_level;
|
int mpw_verbosity = inf_level;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool mpw_push_buf(uint8_t **const buffer, size_t *const bufferSize, const void *pushBuffer, const size_t pushSize) {
|
bool mpw_push_buf(uint8_t **buffer, size_t *bufferSize, const void *pushBuffer, const size_t pushSize) {
|
||||||
|
|
||||||
if (!buffer || !bufferSize || !pushBuffer || !pushSize)
|
if (!buffer || !bufferSize || !pushBuffer || !pushSize)
|
||||||
return false;
|
return false;
|
||||||
@ -49,9 +49,8 @@ bool mpw_push_buf(uint8_t **const buffer, size_t *const bufferSize, const void *
|
|||||||
|
|
||||||
if (!mpw_realloc( buffer, bufferSize, pushSize )) {
|
if (!mpw_realloc( buffer, bufferSize, pushSize )) {
|
||||||
// realloc failed, we can't push. Mark the buffer as broken.
|
// realloc failed, we can't push. Mark the buffer as broken.
|
||||||
mpw_free( *buffer, *bufferSize );
|
mpw_free( buffer, *bufferSize );
|
||||||
*bufferSize = (size_t)ERR;
|
*bufferSize = (size_t)ERR;
|
||||||
*buffer = NULL;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,12 +59,12 @@ bool mpw_push_buf(uint8_t **const buffer, size_t *const bufferSize, const void *
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mpw_push_string(uint8_t **const buffer, size_t *const bufferSize, const char *pushString) {
|
bool mpw_push_string(uint8_t **buffer, size_t *bufferSize, const char *pushString) {
|
||||||
|
|
||||||
return pushString && mpw_push_buf( buffer, bufferSize, pushString, strlen( pushString ) );
|
return pushString && mpw_push_buf( buffer, bufferSize, pushString, strlen( pushString ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mpw_string_push(char **const string, const char *pushString) {
|
bool mpw_string_push(char **string, const char *pushString) {
|
||||||
|
|
||||||
if (!*string)
|
if (!*string)
|
||||||
*string = calloc( 1, sizeof( char ) );
|
*string = calloc( 1, sizeof( char ) );
|
||||||
@ -74,29 +73,29 @@ bool mpw_string_push(char **const string, const char *pushString) {
|
|||||||
return pushString && mpw_push_buf( (uint8_t **const)string, &stringLength, pushString, strlen( pushString ) + 1 );
|
return pushString && mpw_push_buf( (uint8_t **const)string, &stringLength, pushString, strlen( pushString ) + 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mpw_string_pushf(char **const string, const char *pushFormat, ...) {
|
bool mpw_string_pushf(char **string, const char *pushFormat, ...) {
|
||||||
|
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start( args, pushFormat );
|
va_start( args, pushFormat );
|
||||||
char *pushString = NULL;
|
char *pushString = NULL;
|
||||||
bool success = vasprintf( &pushString, pushFormat, args ) >= 0 && mpw_string_push( string, pushString );
|
bool success = vasprintf( &pushString, pushFormat, args ) >= 0 && mpw_string_push( string, pushString );
|
||||||
va_end( args );
|
va_end( args );
|
||||||
mpw_free_string( pushString );
|
mpw_free_string( &pushString );
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mpw_push_int(uint8_t **const buffer, size_t *const bufferSize, const uint32_t pushInt) {
|
bool mpw_push_int(uint8_t **buffer, size_t *bufferSize, const uint32_t pushInt) {
|
||||||
|
|
||||||
return mpw_push_buf( buffer, bufferSize, &pushInt, sizeof( pushInt ) );
|
return mpw_push_buf( buffer, bufferSize, &pushInt, sizeof( pushInt ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool __mpw_realloc(void **buffer, size_t *bufferSize, const size_t deltaSize) {
|
bool __mpw_realloc(const void **buffer, size_t *bufferSize, const size_t deltaSize) {
|
||||||
|
|
||||||
if (!buffer)
|
if (!buffer)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
void *newBuffer = realloc( *buffer, (bufferSize? *bufferSize: 0) + deltaSize );
|
void *newBuffer = realloc( (void *)*buffer, (bufferSize? *bufferSize: 0) + deltaSize );
|
||||||
if (!newBuffer)
|
if (!newBuffer)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -107,24 +106,31 @@ bool __mpw_realloc(void **buffer, size_t *bufferSize, const size_t deltaSize) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mpw_free(const void *buffer, const size_t bufferSize) {
|
bool __mpw_free(const void **buffer, const size_t bufferSize) {
|
||||||
|
|
||||||
if (!buffer)
|
if (!buffer || !*buffer)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
memset( (void *)buffer, 0, bufferSize );
|
memset( (void *)*buffer, 0, bufferSize );
|
||||||
free( (void *)buffer );
|
free( (void *)*buffer );
|
||||||
|
*buffer = NULL;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mpw_free_string(const char *strings, ...) {
|
bool __mpw_free_string(const char **string) {
|
||||||
|
|
||||||
|
return *string && __mpw_free( (const void **)string, strlen( *string ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool __mpw_free_strings(const char **strings, ...) {
|
||||||
|
|
||||||
bool success = true;
|
bool success = true;
|
||||||
|
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start( args, strings );
|
va_start( args, strings );
|
||||||
const char *string = va_arg( args, const char * );
|
for (const char **string; (string = va_arg( args, const char ** ));)
|
||||||
success &= string && mpw_free( string, strlen( string ) );
|
success &= mpw_free_string( string );
|
||||||
va_end( args );
|
va_end( args );
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
@ -142,12 +148,12 @@ uint8_t const *mpw_kdf_scrypt(const size_t keySize, const char *secret, const ui
|
|||||||
|
|
||||||
#if HAS_CPERCIVA
|
#if HAS_CPERCIVA
|
||||||
if (crypto_scrypt( (const uint8_t *)secret, strlen( secret ), salt, saltSize, N, r, p, key, keySize ) < 0) {
|
if (crypto_scrypt( (const uint8_t *)secret, strlen( secret ), salt, saltSize, N, r, p, key, keySize ) < 0) {
|
||||||
mpw_free( key, keySize );
|
mpw_free( &key, keySize );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
#elif HAS_SODIUM
|
#elif HAS_SODIUM
|
||||||
if (crypto_pwhash_scryptsalsa208sha256_ll( (const uint8_t *)secret, strlen( secret ), salt, saltSize, N, r, p, key, keySize ) != 0) {
|
if (crypto_pwhash_scryptsalsa208sha256_ll( (const uint8_t *)secret, strlen( secret ), salt, saltSize, N, r, p, key, keySize ) != 0) {
|
||||||
mpw_free( key, keySize );
|
mpw_free( &key, keySize );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@ -192,7 +198,7 @@ uint8_t const *mpw_kdf_blake2b(const size_t subkeySize, const uint8_t *key, cons
|
|||||||
memcpy( personalBuf, personal, strlen( personal ) );
|
memcpy( personalBuf, personal, strlen( personal ) );
|
||||||
|
|
||||||
if (crypto_generichash_blake2b_salt_personal( subkey, subkeySize, context, contextSize, key, keySize, saltBuf, personalBuf ) != 0) {
|
if (crypto_generichash_blake2b_salt_personal( subkey, subkeySize, context, contextSize, key, keySize, saltBuf, personalBuf ) != 0) {
|
||||||
mpw_free( subkey, subkeySize );
|
mpw_free( &subkey, subkeySize );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@ -222,7 +228,7 @@ uint8_t const *mpw_hash_hmac_sha256(const uint8_t *key, const size_t keySize, co
|
|||||||
if (crypto_auth_hmacsha256_init( &state, key, keySize ) != 0 ||
|
if (crypto_auth_hmacsha256_init( &state, key, keySize ) != 0 ||
|
||||||
crypto_auth_hmacsha256_update( &state, message, messageSize ) != 0 ||
|
crypto_auth_hmacsha256_update( &state, message, messageSize ) != 0 ||
|
||||||
crypto_auth_hmacsha256_final( &state, mac ) != 0) {
|
crypto_auth_hmacsha256_final( &state, mac ) != 0) {
|
||||||
mpw_free( mac, crypto_auth_hmacsha256_BYTES );
|
mpw_free( &mac, crypto_auth_hmacsha256_BYTES );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@ -248,7 +254,7 @@ static uint8_t const *mpw_aes(bool encrypt, const uint8_t *key, const size_t key
|
|||||||
if (encrypt) {
|
if (encrypt) {
|
||||||
uint8_t *const cipherBuf = malloc( bufSize );
|
uint8_t *const cipherBuf = malloc( bufSize );
|
||||||
if (crypto_stream_aes128ctr_xor( cipherBuf, buf, bufSize, nonce, key ) != 0) {
|
if (crypto_stream_aes128ctr_xor( cipherBuf, buf, bufSize, nonce, key ) != 0) {
|
||||||
mpw_free( cipherBuf, bufSize );
|
mpw_free( &cipherBuf, bufSize );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return cipherBuf;
|
return cipherBuf;
|
||||||
@ -256,7 +262,7 @@ static uint8_t const *mpw_aes(bool encrypt, const uint8_t *key, const size_t key
|
|||||||
else {
|
else {
|
||||||
uint8_t *const plainBuf = malloc( bufSize );
|
uint8_t *const plainBuf = malloc( bufSize );
|
||||||
if (crypto_stream_aes128ctr( plainBuf, bufSize, nonce, key ) != 0) {
|
if (crypto_stream_aes128ctr( plainBuf, bufSize, nonce, key ) != 0) {
|
||||||
mpw_free( plainBuf, bufSize );
|
mpw_free( &plainBuf, bufSize );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
for (size_t c = 0; c < bufSize; ++c)
|
for (size_t c = 0; c < bufSize; ++c)
|
||||||
@ -415,7 +421,7 @@ const char *mpw_identicon(const char *fullName, const char *masterPassword) {
|
|||||||
accessory[identiconSeed[3] % (sizeof( accessory ) / sizeof( accessory[0] ))],
|
accessory[identiconSeed[3] % (sizeof( accessory ) / sizeof( accessory[0] ))],
|
||||||
resetString );
|
resetString );
|
||||||
|
|
||||||
mpw_free( identiconSeed, 32 );
|
mpw_free( &identiconSeed, 32 );
|
||||||
free( colorString );
|
free( colorString );
|
||||||
free( resetString );
|
free( resetString );
|
||||||
return identicon;
|
return identicon;
|
||||||
|
@ -106,18 +106,18 @@ extern int mpw_verbosity;
|
|||||||
|
|
||||||
/** Push a buffer onto a buffer. reallocs the given buffer and appends the given buffer. */
|
/** Push a buffer onto a buffer. reallocs the given buffer and appends the given buffer. */
|
||||||
bool mpw_push_buf(
|
bool mpw_push_buf(
|
||||||
uint8_t **const buffer, size_t *const bufferSize, const void *pushBuffer, const size_t pushSize);
|
uint8_t ** buffer, size_t *bufferSize, const void *pushBuffer, const size_t pushSize);
|
||||||
/** Push a string onto a buffer. reallocs the given buffer and appends the given string. */
|
/** Push a string onto a buffer. reallocs the given buffer and appends the given string. */
|
||||||
bool mpw_push_string(
|
bool mpw_push_string(
|
||||||
uint8_t **buffer, size_t *const bufferSize, const char *pushString);
|
uint8_t **buffer, size_t *bufferSize, const char *pushString);
|
||||||
/** Push a string onto another string. reallocs the target string and appends the source string. */
|
/** Push a string onto another string. reallocs the target string and appends the source string. */
|
||||||
bool mpw_string_push(
|
bool mpw_string_push(
|
||||||
char **const string, const char *pushString);
|
char **string, const char *pushString);
|
||||||
bool mpw_string_pushf(
|
bool mpw_string_pushf(
|
||||||
char **const string, const char *pushFormat, ...);
|
char **string, const char *pushFormat, ...);
|
||||||
/** Push an integer onto a buffer. reallocs the given buffer and appends the given integer. */
|
/** Push an integer onto a buffer. reallocs the given buffer and appends the given integer. */
|
||||||
bool mpw_push_int(
|
bool mpw_push_int(
|
||||||
uint8_t **const buffer, size_t *const bufferSize, const uint32_t pushInt);
|
uint8_t **buffer, size_t *bufferSize, const uint32_t pushInt);
|
||||||
/** Reallocate the given buffer from the given size by adding the delta size.
|
/** Reallocate the given buffer from the given size by adding the delta size.
|
||||||
* On success, the buffer size pointer will be updated to the buffer's new size
|
* On success, the buffer size pointer will be updated to the buffer's new size
|
||||||
* and the buffer pointer may be updated to a new memory address.
|
* and the buffer pointer may be updated to a new memory address.
|
||||||
@ -128,14 +128,23 @@ bool mpw_push_int(
|
|||||||
* @return true if successful, false if reallocation failed.
|
* @return true if successful, false if reallocation failed.
|
||||||
*/
|
*/
|
||||||
#define mpw_realloc(buffer, bufferSize, deltaSize) \
|
#define mpw_realloc(buffer, bufferSize, deltaSize) \
|
||||||
__mpw_realloc( (void **)buffer, bufferSize, deltaSize )
|
({ typeof(buffer) _b = buffer; const void *__b = *_b; __mpw_realloc( (const void **)_b, bufferSize, deltaSize ); })
|
||||||
bool __mpw_realloc(void **buffer, size_t *bufferSize, const size_t deltaSize);
|
bool __mpw_realloc(const void **buffer, size_t *bufferSize, const size_t deltaSize);
|
||||||
/** Free a buffer after zero'ing its contents. */
|
/** Free a buffer after zero'ing its contents, then set the reference to NULL. */
|
||||||
bool mpw_free(
|
#define mpw_free(buffer, bufferSize) \
|
||||||
const void *buffer, const size_t bufferSize);
|
({ typeof(buffer) _b = buffer; const void *__b = *_b; __mpw_free((const void **)_b, bufferSize); })
|
||||||
/** Free a string after zero'ing its contents. */
|
bool __mpw_free(
|
||||||
bool mpw_free_string(
|
const void **buffer, const size_t bufferSize);
|
||||||
const char *strings, ...);
|
/** Free a string after zero'ing its contents, then set the reference to NULL. */
|
||||||
|
#define mpw_free_string(string) \
|
||||||
|
({ typeof(string) _s = string; const char *__s = *_s; __mpw_free_string((const char **)_s); })
|
||||||
|
bool __mpw_free_string(
|
||||||
|
const char **string);
|
||||||
|
/** Free strings after zero'ing their contents, then set the references to NULL. Terminate the va_list with NULL. */
|
||||||
|
#define mpw_free_strings(strings, ...) \
|
||||||
|
({ typeof(strings) _s = strings; const char *__s = *_s; __mpw_free_strings((const char **)strings, __VA_ARGS__); })
|
||||||
|
bool __mpw_free_strings(
|
||||||
|
const char **strings, ...);
|
||||||
|
|
||||||
//// Cryptographic functions.
|
//// Cryptographic functions.
|
||||||
|
|
||||||
|
@ -580,7 +580,7 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
|||||||
importMasterPassword = askImportPassword( @(info->fullName) );
|
importMasterPassword = askImportPassword( @(info->fullName) );
|
||||||
if (!importMasterPassword) {
|
if (!importMasterPassword) {
|
||||||
inf( @"Import cancelled." );
|
inf( @"Import cancelled." );
|
||||||
mpw_marshal_info_free( info );
|
mpw_marshal_info_free( &info );
|
||||||
return MPError( ([NSError errorWithDomain:NSCocoaErrorDomain code:NSUserCancelledError userInfo:nil]), @"" );
|
return MPError( ([NSError errorWithDomain:NSCocoaErrorDomain code:NSUserCancelledError userInfo:nil]), @"" );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -591,7 +591,7 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
|||||||
// Parse import data.
|
// Parse import data.
|
||||||
MPMarshallError importError = { .type = MPMarshallSuccess };
|
MPMarshallError importError = { .type = MPMarshallSuccess };
|
||||||
MPMarshalledUser *importUser = mpw_marshall_read( importData.UTF8String, info->format, importMasterPassword.UTF8String, &importError );
|
MPMarshalledUser *importUser = mpw_marshall_read( importData.UTF8String, info->format, importMasterPassword.UTF8String, &importError );
|
||||||
mpw_marshal_info_free( info );
|
mpw_marshal_info_free( &info );
|
||||||
|
|
||||||
@try {
|
@try {
|
||||||
if (!importUser || importError.type != MPMarshallSuccess)
|
if (!importUser || importError.type != MPMarshallSuccess)
|
||||||
@ -677,7 +677,7 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
|||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
@finally {
|
@finally {
|
||||||
mpw_marshal_free( importUser );
|
mpw_marshal_free( &importUser );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,7 +248,7 @@
|
|||||||
[self importSites:importData];
|
[self importSites:importData];
|
||||||
[UIPasteboard generalPasteboard].string = @"";
|
[UIPasteboard generalPasteboard].string = @"";
|
||||||
} cancelTitle:@"No" otherTitles:@"Import Sites", nil];
|
} cancelTitle:@"No" otherTitles:@"Import Sites", nil];
|
||||||
mpw_marshal_info_free( importInfo );
|
mpw_marshal_info_free( &importInfo );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
[super applicationDidBecomeActive:application];
|
[super applicationDidBecomeActive:application];
|
||||||
|
@ -242,7 +242,7 @@ int main(int argc, char *const argv[]) {
|
|||||||
ftl( "Unexpected option: %c\n", opt );
|
ftl( "Unexpected option: %c\n", opt );
|
||||||
return EX_USAGE;
|
return EX_USAGE;
|
||||||
}
|
}
|
||||||
if (optind < argc)
|
if (optind < argc && argv[optind])
|
||||||
siteNameArg = strdup( argv[optind] );
|
siteNameArg = strdup( argv[optind] );
|
||||||
|
|
||||||
// Determine fullName, siteName & masterPassword.
|
// Determine fullName, siteName & masterPassword.
|
||||||
@ -250,7 +250,7 @@ int main(int argc, char *const argv[]) {
|
|||||||
if (!(fullNameArg && (fullName = strdup( fullNameArg ))) &&
|
if (!(fullNameArg && (fullName = strdup( fullNameArg ))) &&
|
||||||
!(fullName = mpw_getline( "Your full name:" ))) {
|
!(fullName = mpw_getline( "Your full name:" ))) {
|
||||||
ftl( "Missing full name.\n" );
|
ftl( "Missing full name.\n" );
|
||||||
mpw_free_string( fullName, masterPassword, siteName );
|
mpw_free_strings( &fullName, &masterPassword, &siteName, NULL );
|
||||||
return EX_DATAERR;
|
return EX_DATAERR;
|
||||||
}
|
}
|
||||||
if (!(masterPasswordArg && (masterPassword = strdup( masterPasswordArg ))))
|
if (!(masterPasswordArg && (masterPassword = strdup( masterPasswordArg ))))
|
||||||
@ -259,7 +259,7 @@ int main(int argc, char *const argv[]) {
|
|||||||
if (!(siteNameArg && (siteName = strdup( siteNameArg ))) &&
|
if (!(siteNameArg && (siteName = strdup( siteNameArg ))) &&
|
||||||
!(siteName = mpw_getline( "Site name:" ))) {
|
!(siteName = mpw_getline( "Site name:" ))) {
|
||||||
ftl( "Missing site name.\n" );
|
ftl( "Missing site name.\n" );
|
||||||
mpw_free_string( fullName, masterPassword, siteName );
|
mpw_free_strings( &fullName, &masterPassword, &siteName, NULL );
|
||||||
return EX_DATAERR;
|
return EX_DATAERR;
|
||||||
}
|
}
|
||||||
MPMarshallFormat sitesFormat = MPMarshallFormatDefault;
|
MPMarshallFormat sitesFormat = MPMarshallFormatDefault;
|
||||||
@ -267,7 +267,7 @@ int main(int argc, char *const argv[]) {
|
|||||||
sitesFormat = mpw_formatWithName( sitesFormatArg );
|
sitesFormat = mpw_formatWithName( sitesFormatArg );
|
||||||
if (ERR == (int)sitesFormat) {
|
if (ERR == (int)sitesFormat) {
|
||||||
ftl( "Invalid sites format: %s\n", sitesFormatArg );
|
ftl( "Invalid sites format: %s\n", sitesFormatArg );
|
||||||
mpw_free_string( fullName, masterPassword, siteName );
|
mpw_free_strings( &fullName, &masterPassword, &siteName, NULL );
|
||||||
return EX_USAGE;
|
return EX_USAGE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -280,7 +280,7 @@ int main(int argc, char *const argv[]) {
|
|||||||
|
|
||||||
// Try to fall back to the flat format.
|
// Try to fall back to the flat format.
|
||||||
if (!sitesFormatFixed) {
|
if (!sitesFormatFixed) {
|
||||||
mpw_free_string( sitesPath );
|
mpw_free_string( &sitesPath );
|
||||||
sitesPath = mpw_path( fullName, mpw_marshall_format_extension( MPMarshallFormatFlat ) );
|
sitesPath = mpw_path( fullName, mpw_marshall_format_extension( MPMarshallFormatFlat ) );
|
||||||
if (sitesPath && (sitesFile = fopen( sitesPath, "r" )))
|
if (sitesPath && (sitesFile = fopen( sitesPath, "r" )))
|
||||||
sitesFormat = MPMarshallFormatFlat;
|
sitesFormat = MPMarshallFormatFlat;
|
||||||
@ -293,10 +293,9 @@ int main(int argc, char *const argv[]) {
|
|||||||
MPMarshalledUser *user = NULL;
|
MPMarshalledUser *user = NULL;
|
||||||
MPMarshalledSite *site = NULL;
|
MPMarshalledSite *site = NULL;
|
||||||
MPMarshalledQuestion *question = NULL;
|
MPMarshalledQuestion *question = NULL;
|
||||||
if (!sitesFile) {
|
if (!sitesFile)
|
||||||
mpw_free_string( sitesPath );
|
mpw_free_string( &sitesPath );
|
||||||
sitesPath = NULL;
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
// Read file.
|
// Read file.
|
||||||
size_t blockSize = 4096, bufSize = 0, bufOffset = 0, readSize = 0;
|
size_t blockSize = 4096, bufSize = 0, bufOffset = 0, readSize = 0;
|
||||||
@ -312,15 +311,15 @@ int main(int argc, char *const argv[]) {
|
|||||||
MPMarshallInfo *sitesInputInfo = mpw_marshall_read_info( sitesInputData );
|
MPMarshallInfo *sitesInputInfo = mpw_marshall_read_info( sitesInputData );
|
||||||
MPMarshallFormat sitesInputFormat = sitesFormatArg? sitesFormat: sitesInputInfo->format;
|
MPMarshallFormat sitesInputFormat = sitesFormatArg? sitesFormat: sitesInputInfo->format;
|
||||||
MPMarshallError marshallError = { .type = MPMarshallSuccess };
|
MPMarshallError marshallError = { .type = MPMarshallSuccess };
|
||||||
mpw_marshal_info_free( sitesInputInfo );
|
mpw_marshal_info_free( &sitesInputInfo );
|
||||||
user = mpw_marshall_read( sitesInputData, sitesInputFormat, masterPassword, &marshallError );
|
user = mpw_marshall_read( sitesInputData, sitesInputFormat, masterPassword, &marshallError );
|
||||||
if (marshallError.type == MPMarshallErrorMasterPassword) {
|
if (marshallError.type == MPMarshallErrorMasterPassword) {
|
||||||
// Incorrect master password.
|
// Incorrect master password.
|
||||||
if (!allowPasswordUpdate) {
|
if (!allowPasswordUpdate) {
|
||||||
ftl( "Incorrect master password according to configuration:\n %s: %s\n", sitesPath, marshallError.description );
|
ftl( "Incorrect master password according to configuration:\n %s: %s\n", sitesPath, marshallError.description );
|
||||||
mpw_marshal_free( user );
|
mpw_marshal_free( &user );
|
||||||
mpw_free( sitesInputData, bufSize );
|
mpw_free( &sitesInputData, bufSize );
|
||||||
mpw_free_string( sitesPath, fullName, masterPassword, siteName );
|
mpw_free_strings( &sitesPath, &fullName, &masterPassword, &siteName, NULL );
|
||||||
return EX_DATAERR;
|
return EX_DATAERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,27 +332,25 @@ int main(int argc, char *const argv[]) {
|
|||||||
while (!importMasterPassword || !strlen( importMasterPassword ))
|
while (!importMasterPassword || !strlen( importMasterPassword ))
|
||||||
importMasterPassword = mpw_getpass( "Old master password: " );
|
importMasterPassword = mpw_getpass( "Old master password: " );
|
||||||
|
|
||||||
mpw_marshal_free( user );
|
mpw_marshal_free( &user );
|
||||||
user = mpw_marshall_read( sitesInputData, sitesInputFormat, importMasterPassword, &marshallError );
|
user = mpw_marshall_read( sitesInputData, sitesInputFormat, importMasterPassword, &marshallError );
|
||||||
mpw_free_string( importMasterPassword );
|
mpw_free_string( &importMasterPassword );
|
||||||
}
|
}
|
||||||
if (user) {
|
if (user) {
|
||||||
mpw_free_string( user->masterPassword );
|
mpw_free_string( &user->masterPassword );
|
||||||
user->masterPassword = strdup( masterPassword );
|
user->masterPassword = strdup( masterPassword );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mpw_free( sitesInputData, bufSize );
|
mpw_free( &sitesInputData, bufSize );
|
||||||
if (!user || marshallError.type != MPMarshallSuccess) {
|
if (!user || marshallError.type != MPMarshallSuccess) {
|
||||||
err( "Couldn't parse configuration file:\n %s: %s\n", sitesPath, marshallError.description );
|
err( "Couldn't parse configuration file:\n %s: %s\n", sitesPath, marshallError.description );
|
||||||
mpw_marshal_free( user );
|
mpw_marshal_free( &user );
|
||||||
user = NULL;
|
mpw_free_string( &sitesPath );
|
||||||
mpw_free_string( sitesPath );
|
|
||||||
sitesPath = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!user)
|
if (!user)
|
||||||
user = mpw_marshall_user( fullName, masterPassword, MPAlgorithmVersionCurrent );
|
user = mpw_marshall_user( fullName, masterPassword, MPAlgorithmVersionCurrent );
|
||||||
mpw_free_string( fullName, masterPassword );
|
mpw_free_strings( &fullName, &masterPassword, NULL );
|
||||||
|
|
||||||
// Load the site object.
|
// Load the site object.
|
||||||
for (size_t s = 0; s < user->sites_count; ++s) {
|
for (size_t s = 0; s < user->sites_count; ++s) {
|
||||||
@ -366,7 +363,7 @@ int main(int argc, char *const argv[]) {
|
|||||||
}
|
}
|
||||||
if (!site)
|
if (!site)
|
||||||
site = mpw_marshall_site( user, siteName, MPResultTypeDefault, MPCounterValueDefault, user->algorithm );
|
site = mpw_marshall_site( user, siteName, MPResultTypeDefault, MPCounterValueDefault, user->algorithm );
|
||||||
mpw_free_string( siteName );
|
mpw_free_string( &siteName );
|
||||||
|
|
||||||
// Load the purpose and context / question object.
|
// Load the purpose and context / question object.
|
||||||
MPKeyPurpose keyPurpose = MPKeyPurposeAuthentication;
|
MPKeyPurpose keyPurpose = MPKeyPurposeAuthentication;
|
||||||
@ -374,8 +371,8 @@ int main(int argc, char *const argv[]) {
|
|||||||
keyPurpose = mpw_purposeWithName( keyPurposeArg );
|
keyPurpose = mpw_purposeWithName( keyPurposeArg );
|
||||||
if (ERR == (int)keyPurpose) {
|
if (ERR == (int)keyPurpose) {
|
||||||
ftl( "Invalid purpose: %s\n", keyPurposeArg );
|
ftl( "Invalid purpose: %s\n", keyPurposeArg );
|
||||||
mpw_marshal_free( user );
|
mpw_marshal_free( &user );
|
||||||
mpw_free_string( sitesPath );
|
mpw_free_string( &sitesPath );
|
||||||
return EX_USAGE;
|
return EX_USAGE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -413,23 +410,23 @@ int main(int argc, char *const argv[]) {
|
|||||||
case MPKeyPurposeAuthentication: {
|
case MPKeyPurposeAuthentication: {
|
||||||
purposeResult = "password";
|
purposeResult = "password";
|
||||||
resultType = site->type;
|
resultType = site->type;
|
||||||
resultState = strdup( site->content );
|
resultState = site->content? strdup( site->content ): NULL;
|
||||||
siteCounter = site->counter;
|
siteCounter = site->counter;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MPKeyPurposeIdentification: {
|
case MPKeyPurposeIdentification: {
|
||||||
purposeResult = "login";
|
purposeResult = "login";
|
||||||
resultType = site->loginType;
|
resultType = site->loginType;
|
||||||
resultState = strdup( site->loginContent );
|
resultState = site->loginContent? strdup( site->loginContent ): NULL;
|
||||||
siteCounter = MPCounterValueInitial;
|
siteCounter = MPCounterValueInitial;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MPKeyPurposeRecovery: {
|
case MPKeyPurposeRecovery: {
|
||||||
mpw_free_string( keyContext );
|
mpw_free_string( &keyContext );
|
||||||
purposeResult = "answer";
|
purposeResult = "answer";
|
||||||
keyContext = strdup( question->keyword );
|
keyContext = question->keyword? strdup( question->keyword ): NULL;
|
||||||
resultType = question->type;
|
resultType = question->type;
|
||||||
resultState = strdup( question->content );
|
resultState = question->content? strdup( question->content ): NULL;
|
||||||
siteCounter = MPCounterValueInitial;
|
siteCounter = MPCounterValueInitial;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -440,8 +437,8 @@ int main(int argc, char *const argv[]) {
|
|||||||
resultType = mpw_typeWithName( resultTypeArg );
|
resultType = mpw_typeWithName( resultTypeArg );
|
||||||
if (ERR == (int)resultType) {
|
if (ERR == (int)resultType) {
|
||||||
ftl( "Invalid type: %s\n", resultTypeArg );
|
ftl( "Invalid type: %s\n", resultTypeArg );
|
||||||
mpw_marshal_free( user );
|
mpw_marshal_free( &user );
|
||||||
mpw_free_string( sitesPath, resultState, keyContext );
|
mpw_free_strings( &sitesPath, &resultState, &keyContext, NULL );
|
||||||
return EX_USAGE;
|
return EX_USAGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -463,8 +460,8 @@ int main(int argc, char *const argv[]) {
|
|||||||
long long int siteCounterInt = atoll( siteCounterArg );
|
long long int siteCounterInt = atoll( siteCounterArg );
|
||||||
if (siteCounterInt < MPCounterValueFirst || siteCounterInt > MPCounterValueLast) {
|
if (siteCounterInt < MPCounterValueFirst || siteCounterInt > MPCounterValueLast) {
|
||||||
ftl( "Invalid site counter: %s\n", siteCounterArg );
|
ftl( "Invalid site counter: %s\n", siteCounterArg );
|
||||||
mpw_marshal_free( user );
|
mpw_marshal_free( &user );
|
||||||
mpw_free_string( sitesPath, resultState, keyContext );
|
mpw_free_strings( &sitesPath, &resultState, &keyContext, NULL );
|
||||||
return EX_USAGE;
|
return EX_USAGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -485,8 +482,8 @@ int main(int argc, char *const argv[]) {
|
|||||||
int algorithmVersionInt = atoi( algorithmVersionArg );
|
int algorithmVersionInt = atoi( algorithmVersionArg );
|
||||||
if (algorithmVersionInt < MPAlgorithmVersionFirst || algorithmVersionInt > MPAlgorithmVersionLast) {
|
if (algorithmVersionInt < MPAlgorithmVersionFirst || algorithmVersionInt > MPAlgorithmVersionLast) {
|
||||||
ftl( "Invalid algorithm version: %s\n", algorithmVersionArg );
|
ftl( "Invalid algorithm version: %s\n", algorithmVersionArg );
|
||||||
mpw_marshal_free( user );
|
mpw_marshal_free( &user );
|
||||||
mpw_free_string( sitesPath, resultState, keyContext, resultParam );
|
mpw_free_strings( &sitesPath, &resultState, &keyContext, &resultParam, NULL );
|
||||||
return EX_USAGE;
|
return EX_USAGE;
|
||||||
}
|
}
|
||||||
site->algorithm = (MPAlgorithmVersion)algorithmVersionInt;
|
site->algorithm = (MPAlgorithmVersion)algorithmVersionInt;
|
||||||
@ -495,9 +492,9 @@ int main(int argc, char *const argv[]) {
|
|||||||
user->redacted = strcmp( sitesRedactedArg, "1" ) == 0;
|
user->redacted = strcmp( sitesRedactedArg, "1" ) == 0;
|
||||||
else if (!user->redacted)
|
else if (!user->redacted)
|
||||||
wrn( "Sites configuration is not redacted. Use -R 1 to change this.\n" );
|
wrn( "Sites configuration is not redacted. Use -R 1 to change this.\n" );
|
||||||
mpw_free_string( fullNameArg, masterPasswordArg, siteNameArg );
|
mpw_free_strings( &fullNameArg, &masterPasswordArg, &siteNameArg, NULL );
|
||||||
mpw_free_string( resultTypeArg, resultParamArg, siteCounterArg, algorithmVersionArg);
|
mpw_free_strings( &resultTypeArg, &resultParamArg, &siteCounterArg, &algorithmVersionArg, NULL );
|
||||||
mpw_free_string( keyPurposeArg, keyContextArg, sitesFormatArg, sitesRedactedArg );
|
mpw_free_strings( &keyPurposeArg, &keyContextArg, &sitesFormatArg, &sitesRedactedArg, NULL );
|
||||||
|
|
||||||
// Operation summary.
|
// Operation summary.
|
||||||
const char *identicon = mpw_identicon( user->fullName, user->masterPassword );
|
const char *identicon = mpw_identicon( user->fullName, user->masterPassword );
|
||||||
@ -518,75 +515,74 @@ int main(int argc, char *const argv[]) {
|
|||||||
dbg( "algorithmVersion : %u\n", site->algorithm );
|
dbg( "algorithmVersion : %u\n", site->algorithm );
|
||||||
dbg( "-----------------\n\n" );
|
dbg( "-----------------\n\n" );
|
||||||
inf( "%s's %s for %s:\n[ %s ]: ", user->fullName, purposeResult, site->name, identicon );
|
inf( "%s's %s for %s:\n[ %s ]: ", user->fullName, purposeResult, site->name, identicon );
|
||||||
mpw_free_string( identicon, sitesPath );
|
mpw_free_strings( &identicon, &sitesPath, NULL );
|
||||||
|
|
||||||
// Determine master key.
|
// Determine master key.
|
||||||
MPMasterKey masterKey = mpw_masterKey(
|
MPMasterKey masterKey = mpw_masterKey(
|
||||||
user->fullName, user->masterPassword, site->algorithm );
|
user->fullName, user->masterPassword, site->algorithm );
|
||||||
if (!masterKey) {
|
if (!masterKey) {
|
||||||
ftl( "Couldn't derive master key.\n" );
|
ftl( "Couldn't derive master key.\n" );
|
||||||
mpw_marshal_free( user );
|
mpw_marshal_free( &user );
|
||||||
mpw_free_string( resultState, keyContext, resultParam );
|
mpw_free_strings( &resultState, &keyContext, &resultParam, NULL );
|
||||||
return EX_SOFTWARE;
|
return EX_SOFTWARE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update state.
|
// Update state.
|
||||||
if (resultParam && resultType & MPResultTypeClassStateful) {
|
if (resultParam && resultType & MPResultTypeClassStateful) {
|
||||||
mpw_free_string( resultState );
|
mpw_free_string( &resultState );
|
||||||
if (!(resultState = mpw_siteState( masterKey, site->name, siteCounter,
|
if (!(resultState = mpw_siteState( masterKey, site->name, siteCounter,
|
||||||
keyPurpose, keyContext, resultType, resultParam, site->algorithm ))) {
|
keyPurpose, keyContext, resultType, resultParam, site->algorithm ))) {
|
||||||
ftl( "Couldn't encrypt site result.\n" );
|
ftl( "Couldn't encrypt site result.\n" );
|
||||||
mpw_free( masterKey, MPMasterKeySize );
|
mpw_free( &masterKey, MPMasterKeySize );
|
||||||
mpw_marshal_free( user );
|
mpw_marshal_free( &user );
|
||||||
mpw_free_string( resultState, keyContext, resultParam );
|
mpw_free_strings( &resultState, &keyContext, &resultParam, NULL );
|
||||||
return EX_SOFTWARE;
|
return EX_SOFTWARE;
|
||||||
}
|
}
|
||||||
inf( "(state) %s => ", resultState );
|
inf( "(state) %s => ", resultState );
|
||||||
|
|
||||||
switch (keyPurpose) {
|
switch (keyPurpose) {
|
||||||
case MPKeyPurposeAuthentication: {
|
case MPKeyPurposeAuthentication: {
|
||||||
mpw_free_string( site->content );
|
mpw_free_string( &site->content );
|
||||||
site->content = resultState;
|
site->content = strdup( resultState );
|
||||||
|
dbg( "site->content: %p", (void *)site->content );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MPKeyPurposeIdentification: {
|
case MPKeyPurposeIdentification: {
|
||||||
mpw_free_string( site->loginContent );
|
mpw_free_string( &site->loginContent );
|
||||||
site->loginContent = resultState;
|
site->loginContent = strdup( resultState );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case MPKeyPurposeRecovery: {
|
case MPKeyPurposeRecovery: {
|
||||||
mpw_free_string( question->content );
|
mpw_free_string( &question->content );
|
||||||
question->content = resultState;
|
question->content = strdup( resultState );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// resultParam is consumed.
|
// resultParam is consumed.
|
||||||
mpw_free_string( resultParam );
|
mpw_free_string( &resultParam );
|
||||||
resultParam = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Second phase resultParam defaults to state.
|
// Second phase resultParam defaults to state.
|
||||||
if (!resultParam && resultState)
|
if (!resultParam && resultState)
|
||||||
resultParam = strdup( resultState );
|
resultParam = strdup( resultState );
|
||||||
mpw_free_string( resultState );
|
mpw_free_string( &resultState );
|
||||||
|
|
||||||
// Generate result.
|
// Generate result.
|
||||||
const char *result = mpw_siteResult( masterKey, site->name, siteCounter,
|
const char *result = mpw_siteResult( masterKey, site->name, siteCounter,
|
||||||
keyPurpose, keyContext, resultType, resultParam, site->algorithm );
|
keyPurpose, keyContext, resultType, resultParam, site->algorithm );
|
||||||
|
mpw_free( &masterKey, MPMasterKeySize );
|
||||||
|
mpw_free_strings( &keyContext, &resultParam, NULL );
|
||||||
if (!result) {
|
if (!result) {
|
||||||
ftl( "Couldn't generate site result.\n" );
|
ftl( "Couldn't generate site result.\n" );
|
||||||
mpw_free( masterKey, MPMasterKeySize );
|
mpw_marshal_free( &user );
|
||||||
mpw_marshal_free( user );
|
|
||||||
mpw_free_string( resultState, keyContext, resultParam );
|
|
||||||
return EX_SOFTWARE;
|
return EX_SOFTWARE;
|
||||||
}
|
}
|
||||||
fprintf( stdout, "%s\n", result );
|
fprintf( stdout, "%s\n", result );
|
||||||
if (site->url)
|
if (site->url)
|
||||||
inf( "See: %s\n", site->url );
|
inf( "See: %s\n", site->url );
|
||||||
mpw_free( masterKey, MPMasterKeySize );
|
mpw_free_string( &result );
|
||||||
mpw_free_string( keyContext, resultParam, result );
|
|
||||||
|
|
||||||
// Update usage metadata.
|
// Update usage metadata.
|
||||||
site->lastUsed = user->lastUsed = time( NULL );
|
site->lastUsed = user->lastUsed = time( NULL );
|
||||||
@ -611,12 +607,12 @@ int main(int argc, char *const argv[]) {
|
|||||||
else if (fwrite( buf, sizeof( char ), strlen( buf ), sitesFile ) != strlen( buf ))
|
else if (fwrite( buf, sizeof( char ), strlen( buf ), sitesFile ) != strlen( buf ))
|
||||||
wrn( "Error while writing updated configuration file:\n %s: %d\n", sitesPath, ferror( sitesFile ) );
|
wrn( "Error while writing updated configuration file:\n %s: %d\n", sitesPath, ferror( sitesFile ) );
|
||||||
|
|
||||||
mpw_free_string( buf );
|
mpw_free_string( &buf );
|
||||||
fclose( sitesFile );
|
fclose( sitesFile );
|
||||||
}
|
}
|
||||||
mpw_free_string( sitesPath );
|
mpw_free_string( &sitesPath );
|
||||||
}
|
}
|
||||||
mpw_marshal_free( user );
|
mpw_marshal_free( &user );
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ int main(int argc, char *const argv[]) {
|
|||||||
// 2. calculate the site password.
|
// 2. calculate the site password.
|
||||||
const char *sitePassword = mpw_siteResult(
|
const char *sitePassword = mpw_siteResult(
|
||||||
masterKey, (char *)siteName, siteCounter, keyPurpose, (char *)keyContext, resultType, NULL, algorithm );
|
masterKey, (char *)siteName, siteCounter, keyPurpose, (char *)keyContext, resultType, NULL, algorithm );
|
||||||
mpw_free( masterKey, MPMasterKeySize );
|
mpw_free( &masterKey, MPMasterKeySize );
|
||||||
if (!sitePassword) {
|
if (!sitePassword) {
|
||||||
ftl( "Couldn't derive site password.\n" );
|
ftl( "Couldn't derive site password.\n" );
|
||||||
continue;
|
continue;
|
||||||
@ -72,7 +72,7 @@ int main(int argc, char *const argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Free test case.
|
// Free test case.
|
||||||
mpw_free_string( sitePassword );
|
mpw_free_string( &sitePassword );
|
||||||
xmlFree( id );
|
xmlFree( id );
|
||||||
xmlFree( fullName );
|
xmlFree( fullName );
|
||||||
xmlFree( masterPassword );
|
xmlFree( masterPassword );
|
||||||
|
Loading…
Reference in New Issue
Block a user