Update the mpsites file after the operation and memory cleanup.
This commit is contained in:
parent
23491faccc
commit
e15d01882f
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
#include "mpw-marshall.h"
|
#include "mpw-marshall.h"
|
||||||
#include "mpw-util.h"
|
#include "mpw-util.h"
|
||||||
@ -32,7 +33,7 @@ MPMarshalledUser *mpw_marshall_user(
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
*user = (MPMarshalledUser){
|
*user = (MPMarshalledUser){
|
||||||
.name = strdup( fullName ),
|
.fullName = strdup( fullName ),
|
||||||
.masterPassword = strdup( masterPassword ),
|
.masterPassword = strdup( masterPassword ),
|
||||||
.algorithm = algorithmVersion,
|
.algorithm = algorithmVersion,
|
||||||
.redacted = true,
|
.redacted = true,
|
||||||
@ -93,16 +94,16 @@ bool mpw_marshal_free(
|
|||||||
|
|
||||||
bool success = true;
|
bool success = true;
|
||||||
for (size_t s = 0; s < marshalledUser->sites_count; ++s) {
|
for (size_t s = 0; s < marshalledUser->sites_count; ++s) {
|
||||||
MPMarshalledSite site = marshalledUser->sites[s];
|
MPMarshalledSite *site = &marshalledUser->sites[s];
|
||||||
success &= mpw_free_string( site.name );
|
success &= mpw_free_string( site->name );
|
||||||
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_string( question->keyword );
|
||||||
}
|
}
|
||||||
success &= mpw_free( site.questions, sizeof( MPMarshalledQuestion ) * site.questions_count );
|
success &= mpw_free( site->questions, sizeof( MPMarshalledQuestion ) * site->questions_count );
|
||||||
}
|
}
|
||||||
success &= mpw_free( marshalledUser->sites, sizeof( MPMarshalledSite ) * marshalledUser->sites_count );
|
success &= mpw_free( marshalledUser->sites, sizeof( MPMarshalledSite ) * marshalledUser->sites_count );
|
||||||
success &= mpw_free_string( marshalledUser->name );
|
success &= mpw_free_string( marshalledUser->fullName );
|
||||||
success &= mpw_free_string( marshalledUser->masterPassword );
|
success &= mpw_free_string( marshalledUser->masterPassword );
|
||||||
success &= mpw_free( marshalledUser, sizeof( MPMarshalledUser ) );
|
success &= mpw_free( marshalledUser, sizeof( MPMarshalledUser ) );
|
||||||
|
|
||||||
@ -113,7 +114,7 @@ static bool mpw_marshall_write_flat(
|
|||||||
char **out, const MPMarshalledUser *user, MPMarshallError *error) {
|
char **out, const MPMarshalledUser *user, MPMarshallError *error) {
|
||||||
|
|
||||||
*error = (MPMarshallError){ MPMarshallErrorInternal, "Unexpected internal error." };
|
*error = (MPMarshallError){ MPMarshallErrorInternal, "Unexpected internal error." };
|
||||||
if (!user->name || !strlen( user->name )) {
|
if (!user->fullName || !strlen( user->fullName )) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorMissing, "Missing full name." };
|
*error = (MPMarshallError){ MPMarshallErrorMissing, "Missing full name." };
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -123,7 +124,7 @@ static bool mpw_marshall_write_flat(
|
|||||||
}
|
}
|
||||||
MPMasterKey masterKey = NULL;
|
MPMasterKey masterKey = NULL;
|
||||||
MPAlgorithmVersion masterKeyAlgorithm = user->algorithm - 1;
|
MPAlgorithmVersion masterKeyAlgorithm = user->algorithm - 1;
|
||||||
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, user->algorithm, user->name, user->masterPassword )) {
|
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, user->algorithm, user->fullName, user->masterPassword )) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." };
|
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." };
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -141,8 +142,8 @@ static bool mpw_marshall_write_flat(
|
|||||||
time_t now = time( NULL );
|
time_t now = time( NULL );
|
||||||
if (strftime( dateString, sizeof( dateString ), "%FT%TZ", gmtime( &now ) ))
|
if (strftime( dateString, sizeof( dateString ), "%FT%TZ", gmtime( &now ) ))
|
||||||
mpw_string_pushf( out, "# Date: %s\n", dateString );
|
mpw_string_pushf( out, "# Date: %s\n", dateString );
|
||||||
mpw_string_pushf( out, "# User Name: %s\n", user->name );
|
mpw_string_pushf( out, "# User Name: %s\n", user->fullName );
|
||||||
mpw_string_pushf( out, "# Full Name: %s\n", user->name );
|
mpw_string_pushf( out, "# Full Name: %s\n", user->fullName );
|
||||||
mpw_string_pushf( out, "# Avatar: %u\n", user->avatar );
|
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, "# Key ID: %s\n", mpw_id_buf( masterKey, MPMasterKeySize ) );
|
||||||
mpw_string_pushf( out, "# Algorithm: %d\n", user->algorithm );
|
mpw_string_pushf( out, "# Algorithm: %d\n", user->algorithm );
|
||||||
@ -155,34 +156,34 @@ static bool mpw_marshall_write_flat(
|
|||||||
|
|
||||||
// Sites.
|
// Sites.
|
||||||
for (size_t s = 0; s < user->sites_count; ++s) {
|
for (size_t s = 0; s < user->sites_count; ++s) {
|
||||||
MPMarshalledSite site = user->sites[s];
|
MPMarshalledSite *site = &user->sites[s];
|
||||||
if (!site.name || !strlen( site.name ))
|
if (!site->name || !strlen( site->name ))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const char *content = NULL;
|
const char *content = NULL;
|
||||||
if (!user->redacted) {
|
if (!user->redacted) {
|
||||||
// Clear Text
|
// Clear Text
|
||||||
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, site.algorithm, user->name, user->masterPassword )) {
|
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, site->algorithm, user->fullName, user->masterPassword )) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." };
|
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." };
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (site.type & MPPasswordTypeClassGenerated) {
|
if (site->type & MPPasswordTypeClassGenerated) {
|
||||||
MPSiteKey siteKey = mpw_siteKey( masterKey, site.name, site.counter, MPKeyPurposeAuthentication, NULL, site.algorithm );
|
MPSiteKey siteKey = mpw_siteKey( masterKey, site->name, site->counter, MPKeyPurposeAuthentication, NULL, site->algorithm );
|
||||||
content = mpw_sitePassword( siteKey, site.type, site.algorithm );
|
content = mpw_sitePassword( siteKey, site->type, site->algorithm );
|
||||||
mpw_free( siteKey, MPSiteKeySize );
|
mpw_free( siteKey, MPSiteKeySize );
|
||||||
}
|
}
|
||||||
else if (site.type & MPSiteFeatureExportContent && site.content && strlen( site.content ))
|
else if (site->type & MPSiteFeatureExportContent && site->content && strlen( site->content ))
|
||||||
content = mpw_decrypt( masterKey, site.content, site.algorithm );
|
content = mpw_decrypt( masterKey, site->content, site->algorithm );
|
||||||
}
|
}
|
||||||
else if (site.type & MPSiteFeatureExportContent && site.content && strlen( site.content ))
|
else if (site->type & MPSiteFeatureExportContent && site->content && strlen( site->content ))
|
||||||
// Redacted
|
// Redacted
|
||||||
content = strdup( site.content );
|
content = strdup( site->content );
|
||||||
|
|
||||||
if (strftime( dateString, sizeof( dateString ), "%FT%TZ", gmtime( &site.lastUsed ) ))
|
if (strftime( dateString, sizeof( dateString ), "%FT%TZ", gmtime( &site->lastUsed ) ))
|
||||||
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,
|
||||||
site.loginName?: "", site.name, content?: "" );
|
site->loginName?: "", site->name, content?: "" );
|
||||||
mpw_free_string( content );
|
mpw_free_string( content );
|
||||||
}
|
}
|
||||||
mpw_free( masterKey, MPMasterKeySize );
|
mpw_free( masterKey, MPMasterKeySize );
|
||||||
@ -195,7 +196,7 @@ static bool mpw_marshall_write_json(
|
|||||||
char **out, const MPMarshalledUser *user, MPMarshallError *error) {
|
char **out, const MPMarshalledUser *user, MPMarshallError *error) {
|
||||||
|
|
||||||
*error = (MPMarshallError){ MPMarshallErrorInternal, "Unexpected internal error." };
|
*error = (MPMarshallError){ MPMarshallErrorInternal, "Unexpected internal error." };
|
||||||
if (!user->name || !strlen( user->name )) {
|
if (!user->fullName || !strlen( user->fullName )) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorMissing, "Missing full name." };
|
*error = (MPMarshallError){ MPMarshallErrorMissing, "Missing full name." };
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -205,7 +206,7 @@ static bool mpw_marshall_write_json(
|
|||||||
}
|
}
|
||||||
MPMasterKey masterKey = NULL;
|
MPMasterKey masterKey = NULL;
|
||||||
MPAlgorithmVersion masterKeyAlgorithm = user->algorithm - 1;
|
MPAlgorithmVersion masterKeyAlgorithm = user->algorithm - 1;
|
||||||
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, user->algorithm, user->name, user->masterPassword )) {
|
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, user->algorithm, user->fullName, user->masterPassword )) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." };
|
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." };
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -226,7 +227,7 @@ static bool mpw_marshall_write_json(
|
|||||||
json_object *json_user = json_object_new_object();
|
json_object *json_user = json_object_new_object();
|
||||||
json_object_object_add( json_file, "user", json_user );
|
json_object_object_add( json_file, "user", json_user );
|
||||||
json_object_object_add( json_user, "avatar", json_object_new_int( (int)user->avatar ) );
|
json_object_object_add( json_user, "avatar", json_object_new_int( (int)user->avatar ) );
|
||||||
json_object_object_add( json_user, "full_name", json_object_new_string( user->name ) );
|
json_object_object_add( json_user, "full_name", json_object_new_string( user->fullName ) );
|
||||||
|
|
||||||
if (strftime( dateString, sizeof( dateString ), "%FT%TZ", gmtime( &user->lastUsed ) ))
|
if (strftime( dateString, sizeof( dateString ), "%FT%TZ", gmtime( &user->lastUsed ) ))
|
||||||
json_object_object_add( json_user, "last_used", json_object_new_string( dateString ) );
|
json_object_object_add( json_user, "last_used", json_object_new_string( dateString ) );
|
||||||
@ -239,59 +240,59 @@ static bool mpw_marshall_write_json(
|
|||||||
json_object *json_sites = json_object_new_object();
|
json_object *json_sites = json_object_new_object();
|
||||||
json_object_object_add( json_file, "sites", json_sites );
|
json_object_object_add( json_file, "sites", json_sites );
|
||||||
for (size_t s = 0; s < user->sites_count; ++s) {
|
for (size_t s = 0; s < user->sites_count; ++s) {
|
||||||
MPMarshalledSite site = user->sites[s];
|
MPMarshalledSite *site = &user->sites[s];
|
||||||
if (!site.name || !strlen( site.name ))
|
if (!site->name || !strlen( site->name ))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const char *content = NULL;
|
const char *content = NULL;
|
||||||
if (!user->redacted) {
|
if (!user->redacted) {
|
||||||
// Clear Text
|
// Clear Text
|
||||||
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, site.algorithm, user->name, user->masterPassword )) {
|
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, site->algorithm, user->fullName, user->masterPassword )) {
|
||||||
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." };
|
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." };
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (site.type & MPPasswordTypeClassGenerated) {
|
if (site->type & MPPasswordTypeClassGenerated) {
|
||||||
MPSiteKey siteKey = mpw_siteKey( masterKey, site.name, site.counter, MPKeyPurposeAuthentication, NULL, site.algorithm );
|
MPSiteKey siteKey = mpw_siteKey( masterKey, site->name, site->counter, MPKeyPurposeAuthentication, NULL, site->algorithm );
|
||||||
content = mpw_sitePassword( siteKey, site.type, site.algorithm );
|
content = mpw_sitePassword( siteKey, site->type, site->algorithm );
|
||||||
mpw_free( siteKey, MPSiteKeySize );
|
mpw_free( siteKey, MPSiteKeySize );
|
||||||
}
|
}
|
||||||
else if (site.type & MPSiteFeatureExportContent && site.content && strlen( site.content ))
|
else if (site->type & MPSiteFeatureExportContent && site->content && strlen( site->content ))
|
||||||
content = mpw_decrypt( masterKey, site.content, site.algorithm );
|
content = mpw_decrypt( masterKey, site->content, site->algorithm );
|
||||||
}
|
}
|
||||||
else if (site.type & MPSiteFeatureExportContent && site.content && strlen( site.content ))
|
else if (site->type & MPSiteFeatureExportContent && site->content && strlen( site->content ))
|
||||||
// Redacted
|
// Redacted
|
||||||
content = strdup( site.content );
|
content = strdup( site->content );
|
||||||
|
|
||||||
json_object *json_site = json_object_new_object();
|
json_object *json_site = json_object_new_object();
|
||||||
json_object_object_add( json_sites, site.name, json_site );
|
json_object_object_add( json_sites, site->name, json_site );
|
||||||
json_object_object_add( json_site, "type", json_object_new_int( (int)site.type ) );
|
json_object_object_add( json_site, "type", json_object_new_int( (int)site->type ) );
|
||||||
json_object_object_add( json_site, "counter", json_object_new_int( (int)site.counter ) );
|
json_object_object_add( json_site, "counter", json_object_new_int( (int)site->counter ) );
|
||||||
json_object_object_add( json_site, "algorithm", json_object_new_int( (int)site.algorithm ) );
|
json_object_object_add( json_site, "algorithm", json_object_new_int( (int)site->algorithm ) );
|
||||||
if (content)
|
if (content)
|
||||||
json_object_object_add( json_site, "password", json_object_new_string( content ) );
|
json_object_object_add( json_site, "password", json_object_new_string( content ) );
|
||||||
if (site.loginName)
|
if (site->loginName)
|
||||||
json_object_object_add( json_site, "login_name", json_object_new_string( site.loginName ) );
|
json_object_object_add( json_site, "login_name", json_object_new_string( site->loginName ) );
|
||||||
json_object_object_add( json_site, "login_generated", json_object_new_boolean( site.loginGenerated ) );
|
json_object_object_add( json_site, "login_generated", json_object_new_boolean( site->loginGenerated ) );
|
||||||
|
|
||||||
json_object_object_add( json_site, "uses", json_object_new_int( (int)site.uses ) );
|
json_object_object_add( json_site, "uses", json_object_new_int( (int)site->uses ) );
|
||||||
if (strftime( dateString, sizeof( dateString ), "%FT%TZ", gmtime( &site.lastUsed ) ))
|
if (strftime( dateString, sizeof( dateString ), "%FT%TZ", gmtime( &site->lastUsed ) ))
|
||||||
json_object_object_add( json_site, "last_used", json_object_new_string( dateString ) );
|
json_object_object_add( json_site, "last_used", json_object_new_string( dateString ) );
|
||||||
|
|
||||||
json_object *json_site_questions = json_object_new_object();
|
json_object *json_site_questions = json_object_new_object();
|
||||||
json_object_object_add( json_site, "questions", json_site_questions );
|
json_object_object_add( json_site, "questions", json_site_questions );
|
||||||
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];
|
||||||
if (!question.keyword)
|
if (!question->keyword)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
json_object *json_site_question = json_object_new_object();
|
json_object *json_site_question = json_object_new_object();
|
||||||
json_object_object_add( json_site_questions, question.keyword, json_site_question );
|
json_object_object_add( json_site_questions, question->keyword, json_site_question );
|
||||||
|
|
||||||
if (!user->redacted) {
|
if (!user->redacted) {
|
||||||
// Clear Text
|
// Clear Text
|
||||||
MPSiteKey siteKey = mpw_siteKey( masterKey, site.name, 1, MPKeyPurposeRecovery, question.keyword, site.algorithm );
|
MPSiteKey siteKey = mpw_siteKey( masterKey, site->name, 1, MPKeyPurposeRecovery, question->keyword, site->algorithm );
|
||||||
const char *answer = mpw_sitePassword( siteKey, MPPasswordTypeGeneratedPhrase, site.algorithm );
|
const char *answer = mpw_sitePassword( siteKey, MPPasswordTypeGeneratedPhrase, site->algorithm );
|
||||||
mpw_free( siteKey, MPSiteKeySize );
|
mpw_free( siteKey, MPSiteKeySize );
|
||||||
if (answer)
|
if (answer)
|
||||||
json_object_object_add( json_site_question, "answer", json_object_new_string( answer ) );
|
json_object_object_add( json_site_question, "answer", json_object_new_string( answer ) );
|
||||||
@ -300,8 +301,8 @@ static bool mpw_marshall_write_json(
|
|||||||
|
|
||||||
json_object *json_site_mpw = json_object_new_object();
|
json_object *json_site_mpw = json_object_new_object();
|
||||||
json_object_object_add( json_site, "_ext_mpw", json_site_mpw );
|
json_object_object_add( json_site, "_ext_mpw", json_site_mpw );
|
||||||
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_string( content );
|
||||||
}
|
}
|
||||||
@ -699,3 +700,52 @@ MPMarshalledUser *mpw_marshall_read(
|
|||||||
*error = (MPMarshallError){ MPMarshallErrorFormat, mpw_str( "Unsupported input format: %u", inFormat ) };
|
*error = (MPMarshallError){ MPMarshallErrorFormat, mpw_str( "Unsupported input format: %u", inFormat ) };
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MPMarshallFormat mpw_formatWithName(
|
||||||
|
const char *formatName) {
|
||||||
|
|
||||||
|
// Lower-case to standardize it.
|
||||||
|
size_t stdFormatNameSize = strlen( formatName );
|
||||||
|
char stdFormatName[stdFormatNameSize + 1];
|
||||||
|
for (size_t c = 0; c < stdFormatNameSize; ++c)
|
||||||
|
stdFormatName[c] = (char)tolower( formatName[c] );
|
||||||
|
stdFormatName[stdFormatNameSize] = '\0';
|
||||||
|
|
||||||
|
if (strncmp( mpw_nameForFormat( MPMarshallFormatFlat ), stdFormatName, strlen( stdFormatName ) ) == 0)
|
||||||
|
return MPMarshallFormatFlat;
|
||||||
|
if (strncmp( mpw_nameForFormat( MPMarshallFormatJSON ), stdFormatName, strlen( stdFormatName ) ) == 0)
|
||||||
|
return MPMarshallFormatJSON;
|
||||||
|
|
||||||
|
dbg( "Not a format name: %s\n", stdFormatName );
|
||||||
|
return (MPMarshallFormat)ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *mpw_nameForFormat(
|
||||||
|
const MPMarshallFormat format) {
|
||||||
|
|
||||||
|
switch (format) {
|
||||||
|
case MPMarshallFormatFlat:
|
||||||
|
return "flat";
|
||||||
|
case MPMarshallFormatJSON:
|
||||||
|
return "json";
|
||||||
|
default: {
|
||||||
|
dbg( "Unknown format: %d\n", format );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *mpw_marshall_format_extension(
|
||||||
|
const MPMarshallFormat format) {
|
||||||
|
|
||||||
|
switch (format) {
|
||||||
|
case MPMarshallFormatFlat:
|
||||||
|
return "mpsites";
|
||||||
|
case MPMarshallFormatJSON:
|
||||||
|
return "mpsites.json";
|
||||||
|
default: {
|
||||||
|
dbg( "Unknown format: %d\n", format );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -30,6 +30,8 @@ typedef enum( unsigned int, MPMarshallFormat ) {
|
|||||||
MPMarshallFormatFlat,
|
MPMarshallFormatFlat,
|
||||||
/** Generate a name for identification. */
|
/** Generate a name for identification. */
|
||||||
MPMarshallFormatJSON,
|
MPMarshallFormatJSON,
|
||||||
|
|
||||||
|
MPMarshallFormatDefault = MPMarshallFormatJSON,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum( unsigned int, MPMarshallErrorType ) {
|
typedef enum( unsigned int, MPMarshallErrorType ) {
|
||||||
@ -76,7 +78,7 @@ typedef struct MPMarshalledSite {
|
|||||||
} MPMarshalledSite;
|
} MPMarshalledSite;
|
||||||
|
|
||||||
typedef struct MPMarshalledUser {
|
typedef struct MPMarshalledUser {
|
||||||
const char *name;
|
const char *fullName;
|
||||||
const char *masterPassword;
|
const char *masterPassword;
|
||||||
MPAlgorithmVersion algorithm;
|
MPAlgorithmVersion algorithm;
|
||||||
bool redacted;
|
bool redacted;
|
||||||
@ -93,9 +95,6 @@ typedef struct MPMarshalledUser {
|
|||||||
|
|
||||||
bool mpw_marshall_write(
|
bool mpw_marshall_write(
|
||||||
char **out, const MPMarshallFormat outFormat, const MPMarshalledUser *marshalledUser, MPMarshallError *error);
|
char **out, const MPMarshallFormat outFormat, const MPMarshalledUser *marshalledUser, MPMarshallError *error);
|
||||||
|
|
||||||
//// Unmarshalling.
|
|
||||||
|
|
||||||
MPMarshalledUser *mpw_marshall_read(
|
MPMarshalledUser *mpw_marshall_read(
|
||||||
char *in, const MPMarshallFormat inFormat, const char *masterPassword, MPMarshallError *error);
|
char *in, const MPMarshallFormat inFormat, const char *masterPassword, MPMarshallError *error);
|
||||||
|
|
||||||
@ -111,4 +110,19 @@ MPMarshalledQuestion *mpw_marshal_question(
|
|||||||
bool mpw_marshal_free(
|
bool mpw_marshal_free(
|
||||||
MPMarshalledUser *marshalledUser);
|
MPMarshalledUser *marshalledUser);
|
||||||
|
|
||||||
|
//// Format.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The purpose represented by the given name.
|
||||||
|
*/
|
||||||
|
const MPMarshallFormat mpw_formatWithName(
|
||||||
|
const char *formatName);
|
||||||
|
/**
|
||||||
|
* @return The standard name for the given purpose.
|
||||||
|
*/
|
||||||
|
const char *mpw_nameForFormat(
|
||||||
|
const MPMarshallFormat format);
|
||||||
|
const char *mpw_marshall_format_extension(
|
||||||
|
const MPMarshallFormat format);
|
||||||
|
|
||||||
#endif // _MPW_MARSHALL_H
|
#endif // _MPW_MARSHALL_H
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
static void usage() {
|
static void usage() {
|
||||||
|
|
||||||
inf( ""
|
inf( ""
|
||||||
"Usage: mpw [-u name] [-t type] [-c counter] [-a algorithm] [-p purpose] [-C context] [-v|-q] [-h] site\n\n" );
|
"Usage: mpw [-u name] [-t type] [-c counter] [-a algorithm] [-p purpose] [-C context] [-f|-F format] [-v|-q] [-h] site\n\n" );
|
||||||
inf( ""
|
inf( ""
|
||||||
" -u name Specify the full name of the user.\n"
|
" -u name Specify the full name of the user.\n"
|
||||||
" Defaults to %s in env or prompts.\n\n", MP_env_fullName );
|
" Defaults to %s in env or prompts.\n\n", MP_env_fullName );
|
||||||
@ -56,8 +56,14 @@ static void usage() {
|
|||||||
" -p i, ident | -\n"
|
" -p i, ident | -\n"
|
||||||
" -p r, rec | Most significant word in security question.\n\n" );
|
" -p r, rec | Most significant word in security question.\n\n" );
|
||||||
inf( ""
|
inf( ""
|
||||||
" -v Increase output verbosity (can be repeated).\n\n" );
|
" -f|F format The mpsites format to use for reading/writing site parameters.\n"
|
||||||
|
" -F forces the use of the given format, -f allows fallback/migration.\n"
|
||||||
|
" Defaults to json, falls back to plain.\n"
|
||||||
|
" f, flat | ~/.mpw.d/Full Name.%s\n"
|
||||||
|
" j, json | ~/.mpw.d/Full Name.%s\n\n",
|
||||||
|
mpw_marshall_format_extension( MPMarshallFormatFlat ), mpw_marshall_format_extension( MPMarshallFormatJSON ) );
|
||||||
inf( ""
|
inf( ""
|
||||||
|
" -v Increase output verbosity (can be repeated).\n"
|
||||||
" -q Decrease output verbosity (can be repeated).\n\n" );
|
" -q Decrease output verbosity (can be repeated).\n\n" );
|
||||||
inf( ""
|
inf( ""
|
||||||
" ENVIRONMENT\n\n"
|
" ENVIRONMENT\n\n"
|
||||||
@ -108,18 +114,20 @@ int main(int argc, char *const argv[]) {
|
|||||||
|
|
||||||
// Master Password defaults.
|
// Master Password defaults.
|
||||||
const char *fullName = NULL, *masterPassword = NULL, *siteName = NULL, *keyContext = NULL;
|
const char *fullName = NULL, *masterPassword = NULL, *siteName = NULL, *keyContext = NULL;
|
||||||
|
uint32_t siteCounter = 1;
|
||||||
MPPasswordType passwordType = MPPasswordTypeDefault;
|
MPPasswordType passwordType = MPPasswordTypeDefault;
|
||||||
MPKeyPurpose keyPurpose = MPKeyPurposeAuthentication;
|
MPKeyPurpose keyPurpose = MPKeyPurposeAuthentication;
|
||||||
MPAlgorithmVersion algorithmVersion = MPAlgorithmVersionCurrent;
|
MPAlgorithmVersion algorithmVersion = MPAlgorithmVersionCurrent;
|
||||||
uint32_t siteCounter = 1;
|
MPMarshallFormat sitesFormat = MPMarshallFormatDefault;
|
||||||
|
bool sitesFormatFixed = false;
|
||||||
|
|
||||||
// Read the environment.
|
// Read the environment.
|
||||||
const char *fullNameArg = getenv( MP_env_fullName ), *masterPasswordArg = NULL, *siteNameArg = NULL;
|
const char *fullNameArg = getenv( MP_env_fullName ), *masterPasswordArg = NULL;
|
||||||
const char *passwordTypeArg = NULL, *keyPurposeArg = NULL, *keyContextArg = NULL, *siteCounterArg = NULL;
|
const char *passwordTypeArg = NULL, *siteCounterArg = NULL, *algorithmVersionArg = getenv( MP_env_algorithm );
|
||||||
const char *algorithmVersionArg = getenv( MP_env_algorithm );
|
const char *keyPurposeArg = NULL, *keyContextArg = NULL, *sitesFormatArg = NULL, *siteNameArg = NULL;
|
||||||
|
|
||||||
// Read the command-line options.
|
// Read the command-line options.
|
||||||
for (int opt; (opt = getopt( argc, argv, "u:P:t:c:V:a:C:vqh" )) != EOF;)
|
for (int opt; (opt = getopt( argc, argv, "u:P:t:c:a:p:C:f:F:vqh" )) != EOF;)
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'u':
|
case 'u':
|
||||||
fullNameArg = optarg;
|
fullNameArg = optarg;
|
||||||
@ -134,15 +142,23 @@ int main(int argc, char *const argv[]) {
|
|||||||
case 'c':
|
case 'c':
|
||||||
siteCounterArg = optarg;
|
siteCounterArg = optarg;
|
||||||
break;
|
break;
|
||||||
case 'p':
|
|
||||||
keyPurposeArg = optarg;
|
|
||||||
break;
|
|
||||||
case 'a':
|
case 'a':
|
||||||
algorithmVersionArg = optarg;
|
algorithmVersionArg = optarg;
|
||||||
break;
|
break;
|
||||||
|
case 'p':
|
||||||
|
keyPurposeArg = optarg;
|
||||||
|
break;
|
||||||
case 'C':
|
case 'C':
|
||||||
keyContextArg = optarg;
|
keyContextArg = optarg;
|
||||||
break;
|
break;
|
||||||
|
case 'f':
|
||||||
|
sitesFormatArg = optarg;
|
||||||
|
sitesFormatFixed = false;
|
||||||
|
break;
|
||||||
|
case 'F':
|
||||||
|
sitesFormatArg = optarg;
|
||||||
|
sitesFormatFixed = true;
|
||||||
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
++mpw_verbosity;
|
++mpw_verbosity;
|
||||||
break;
|
break;
|
||||||
@ -177,12 +193,13 @@ int main(int argc, char *const argv[]) {
|
|||||||
// Empty strings unset the argument.
|
// Empty strings unset the argument.
|
||||||
fullNameArg = fullNameArg && strlen( fullNameArg )? fullNameArg: NULL;
|
fullNameArg = fullNameArg && strlen( fullNameArg )? fullNameArg: NULL;
|
||||||
masterPasswordArg = masterPasswordArg && strlen( masterPasswordArg )? masterPasswordArg: NULL;
|
masterPasswordArg = masterPasswordArg && strlen( masterPasswordArg )? masterPasswordArg: NULL;
|
||||||
siteNameArg = siteNameArg && strlen( siteNameArg )? siteNameArg: NULL;
|
|
||||||
passwordTypeArg = passwordTypeArg && strlen( passwordTypeArg )? passwordTypeArg: NULL;
|
passwordTypeArg = passwordTypeArg && strlen( passwordTypeArg )? passwordTypeArg: NULL;
|
||||||
keyPurposeArg = keyPurposeArg && strlen( keyPurposeArg )? keyPurposeArg: NULL;
|
|
||||||
keyContextArg = keyContextArg && strlen( keyContextArg )? keyContextArg: NULL;
|
|
||||||
siteCounterArg = siteCounterArg && strlen( siteCounterArg )? siteCounterArg: NULL;
|
siteCounterArg = siteCounterArg && strlen( siteCounterArg )? siteCounterArg: NULL;
|
||||||
algorithmVersionArg = algorithmVersionArg && strlen( algorithmVersionArg )? algorithmVersionArg: NULL;
|
algorithmVersionArg = algorithmVersionArg && strlen( algorithmVersionArg )? algorithmVersionArg: NULL;
|
||||||
|
keyPurposeArg = keyPurposeArg && strlen( keyPurposeArg )? keyPurposeArg: NULL;
|
||||||
|
keyContextArg = keyContextArg && strlen( keyContextArg )? keyContextArg: NULL;
|
||||||
|
sitesFormatArg = sitesFormatArg && strlen( sitesFormatArg )? sitesFormatArg: NULL;
|
||||||
|
siteNameArg = siteNameArg && strlen( siteNameArg )? siteNameArg: NULL;
|
||||||
|
|
||||||
// Determine fullName, siteName & masterPassword.
|
// Determine fullName, siteName & masterPassword.
|
||||||
if (!(fullNameArg && (fullName = strdup( fullNameArg ))) &&
|
if (!(fullNameArg && (fullName = strdup( fullNameArg ))) &&
|
||||||
@ -198,96 +215,90 @@ int main(int argc, char *const argv[]) {
|
|||||||
if (!(masterPasswordArg && (masterPassword = strdup( masterPasswordArg ))))
|
if (!(masterPasswordArg && (masterPassword = strdup( masterPasswordArg ))))
|
||||||
while (!masterPassword || !strlen( masterPassword ))
|
while (!masterPassword || !strlen( masterPassword ))
|
||||||
masterPassword = getpass( "Your master password: " );
|
masterPassword = getpass( "Your master password: " );
|
||||||
|
if (sitesFormatArg) {
|
||||||
|
sitesFormat = mpw_formatWithName( sitesFormatArg );
|
||||||
|
if (ERR == sitesFormat) {
|
||||||
|
ftl( "Invalid sites format: %s\n", sitesFormatArg );
|
||||||
|
return EX_USAGE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Find the user's sites file.
|
// Find the user's sites file.
|
||||||
FILE *mpwSites = NULL;
|
FILE *sitesFile = NULL;
|
||||||
MPMarshallFormat mpwSitesFormat = MPMarshallFormatJSON;
|
char *sitesPath = mpw_path( fullName, mpw_marshall_format_extension( sitesFormat ) );
|
||||||
char *mpwSitesPath = mpw_path( fullName, "mpsites.json" );
|
if (!sitesPath || !(sitesFile = fopen( sitesPath, "r" ))) {
|
||||||
if (!mpwSitesPath || !(mpwSites = fopen( mpwSitesPath, "r" ))) {
|
dbg( "Couldn't open configuration file:\n %s: %s\n", sitesPath, strerror( errno ) );
|
||||||
dbg( "Couldn't open configuration file:\n %s: %s\n", mpwSitesPath, strerror( errno ) );
|
free( sitesPath );
|
||||||
free( mpwSitesPath );
|
|
||||||
mpwSitesFormat = MPMarshallFormatFlat;
|
// Try to fall back to the flat format.
|
||||||
mpwSitesPath = mpw_path( fullName, "mpsites" );
|
if (!sitesFormatFixed) {
|
||||||
if (!mpwSitesPath || !(mpwSites = fopen( mpwSitesPath, "r" )))
|
sitesFormat = MPMarshallFormatFlat;
|
||||||
dbg( "Couldn't open configuration file:\n %s: %s\n", mpwSitesPath, strerror( errno ) );
|
sitesPath = mpw_path( fullName, mpw_marshall_format_extension( sitesFormat ) );
|
||||||
|
if (!sitesPath || !(sitesFile = fopen( sitesPath, "r" )))
|
||||||
|
dbg( "Couldn't open configuration file:\n %s: %s\n", sitesPath, strerror( errno ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the user's sites file.
|
// Read the user's sites file.
|
||||||
if (mpwSites) {
|
MPMarshalledUser *user = NULL;
|
||||||
|
MPMarshalledSite *site = NULL;
|
||||||
|
if (!sitesFile) {
|
||||||
|
free( sitesPath );
|
||||||
|
sitesPath = NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
// Read file.
|
// Read file.
|
||||||
size_t readAmount = 4096, bufSize = 0, bufOffset = 0, readSize = 0;
|
size_t readAmount = 4096, bufSize = 0, bufOffset = 0, readSize = 0;
|
||||||
char *buf = NULL;
|
char *buf = NULL;
|
||||||
while ((mpw_realloc( &buf, &bufSize, readAmount )) &&
|
while ((mpw_realloc( &buf, &bufSize, readAmount )) &&
|
||||||
(bufOffset += (readSize = fread( buf + bufOffset, 1, readAmount, mpwSites ))) &&
|
(bufOffset += (readSize = fread( buf + bufOffset, 1, readAmount, sitesFile ))) &&
|
||||||
(readSize == readAmount));
|
(readSize == readAmount));
|
||||||
if (ferror( mpwSites ))
|
if (ferror( sitesFile ))
|
||||||
wrn( "Error while reading configuration file:\n %s: %d\n", mpwSitesPath, ferror( mpwSites ) );
|
wrn( "Error while reading configuration file:\n %s: %d\n", sitesPath, ferror( sitesFile ) );
|
||||||
fclose( mpwSites );
|
fclose( sitesFile );
|
||||||
|
|
||||||
// Parse file.
|
// Parse file.
|
||||||
MPMarshallError marshallError = { MPMarshallSuccess };
|
MPMarshallError marshallError = { MPMarshallSuccess };
|
||||||
MPMarshalledUser *user = mpw_marshall_read( buf, mpwSitesFormat, masterPassword, &marshallError );
|
user = mpw_marshall_read( buf, sitesFormat, masterPassword, &marshallError );
|
||||||
mpw_free( buf, bufSize );
|
mpw_free( buf, bufSize );
|
||||||
if (!user || marshallError.type != MPMarshallSuccess) {
|
if (!user || marshallError.type != MPMarshallSuccess) {
|
||||||
if (marshallError.type == MPMarshallErrorMasterPassword) {
|
if (marshallError.type == MPMarshallErrorMasterPassword) {
|
||||||
ftl( "Incorrect master password according to configuration:\n %s: %s\n", mpwSitesPath, marshallError.description );
|
ftl( "Incorrect master password according to configuration:\n %s: %s\n", sitesPath, marshallError.description );
|
||||||
return EX_DATAERR;
|
return EX_DATAERR;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
err( "Couldn't parse configuration file:\n %s: %s\n", mpwSitesPath, marshallError.description );
|
err( "Couldn't parse configuration file:\n %s: %s\n", sitesPath, marshallError.description );
|
||||||
|
mpw_marshal_free( user );
|
||||||
|
user = NULL;
|
||||||
|
free( sitesPath );
|
||||||
|
sitesPath = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
// Load defaults.
|
// Load defaults.
|
||||||
mpw_free_string( fullName );
|
mpw_free_string( fullName );
|
||||||
mpw_free_string( masterPassword );
|
mpw_free_string( masterPassword );
|
||||||
fullName = strdup( user->name );
|
fullName = strdup( user->fullName );
|
||||||
masterPassword = strdup( user->masterPassword );
|
masterPassword = strdup( user->masterPassword );
|
||||||
algorithmVersion = user->algorithm;
|
algorithmVersion = user->algorithm;
|
||||||
passwordType = user->defaultType;
|
passwordType = user->defaultType;
|
||||||
for (size_t s = 0; s < user->sites_count; ++s) {
|
for (size_t s = 0; s < user->sites_count; ++s) {
|
||||||
MPMarshalledSite site = user->sites[s];
|
site = &user->sites[s];
|
||||||
if (strcmp( siteName, site.name ) == 0) {
|
if (strcmp( siteName, site->name ) != 0) {
|
||||||
passwordType = site.type;
|
site = NULL;
|
||||||
siteCounter = site.counter;
|
continue;
|
||||||
algorithmVersion = site.algorithm;
|
}
|
||||||
|
|
||||||
|
passwordType = site->type;
|
||||||
|
siteCounter = site->counter;
|
||||||
|
algorithmVersion = site->algorithm;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Current format is not current, write out a new current format config file.
|
|
||||||
if (mpwSitesFormat != MPMarshallFormatJSON) {
|
|
||||||
mpwSitesPath = mpw_path( fullName, "mpsites.json" );
|
|
||||||
if (!mpwSitesPath || !(mpwSites = fopen( mpwSitesPath, "w" )))
|
|
||||||
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.type != MPMarshallSuccess)
|
|
||||||
wrn( "Couldn't encode updated configuration file:\n %s: %s\n", 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 ) );
|
|
||||||
|
|
||||||
mpw_free_string( buf );
|
|
||||||
fclose( mpwSites );
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
mpw_marshal_free( user );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free( mpwSitesPath );
|
|
||||||
|
|
||||||
// Parse default/config-overriding command-line parameters.
|
// Parse default/config-overriding command-line parameters.
|
||||||
if (algorithmVersionArg && strlen( algorithmVersionArg )) {
|
if (siteCounterArg) {
|
||||||
int algorithmVersionInt = atoi( algorithmVersionArg );
|
|
||||||
if (algorithmVersionInt < MPAlgorithmVersionFirst || algorithmVersionInt > MPAlgorithmVersionLast) {
|
|
||||||
ftl( "Invalid algorithm version: %s\n", algorithmVersionArg );
|
|
||||||
return EX_USAGE;
|
|
||||||
}
|
|
||||||
algorithmVersion = (MPAlgorithmVersion)algorithmVersionInt;
|
|
||||||
}
|
|
||||||
if (siteCounterArg && strlen( siteCounterArg )) {
|
|
||||||
long long int siteCounterInt = atoll( siteCounterArg );
|
long long int siteCounterInt = atoll( siteCounterArg );
|
||||||
if (siteCounterInt < 0 || siteCounterInt > UINT32_MAX) {
|
if (siteCounterInt < 0 || siteCounterInt > UINT32_MAX) {
|
||||||
ftl( "Invalid site counter: %s\n", siteCounterArg );
|
ftl( "Invalid site counter: %s\n", siteCounterArg );
|
||||||
@ -295,28 +306,47 @@ int main(int argc, char *const argv[]) {
|
|||||||
}
|
}
|
||||||
siteCounter = (uint32_t)siteCounterInt;
|
siteCounter = (uint32_t)siteCounterInt;
|
||||||
}
|
}
|
||||||
if (keyPurposeArg && strlen( keyPurposeArg )) {
|
if (algorithmVersionArg) {
|
||||||
|
int algorithmVersionInt = atoi( algorithmVersionArg );
|
||||||
|
if (algorithmVersionInt < MPAlgorithmVersionFirst || algorithmVersionInt > MPAlgorithmVersionLast) {
|
||||||
|
ftl( "Invalid algorithm version: %s\n", algorithmVersionArg );
|
||||||
|
return EX_USAGE;
|
||||||
|
}
|
||||||
|
algorithmVersion = (MPAlgorithmVersion)algorithmVersionInt;
|
||||||
|
}
|
||||||
|
if (keyPurposeArg) {
|
||||||
keyPurpose = mpw_purposeWithName( keyPurposeArg );
|
keyPurpose = mpw_purposeWithName( keyPurposeArg );
|
||||||
if (ERR == keyPurpose) {
|
if (ERR == keyPurpose) {
|
||||||
ftl( "Invalid purpose: %s\n", keyPurposeArg );
|
ftl( "Invalid purpose: %s\n", keyPurposeArg );
|
||||||
return EX_USAGE;
|
return EX_USAGE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (keyPurpose == MPKeyPurposeIdentification)
|
char *purposeResult = "password";
|
||||||
|
switch (keyPurpose) {
|
||||||
|
case MPKeyPurposeAuthentication:
|
||||||
|
break;
|
||||||
|
case MPKeyPurposeIdentification: {
|
||||||
passwordType = MPPasswordTypeGeneratedName;
|
passwordType = MPPasswordTypeGeneratedName;
|
||||||
if (keyPurpose == MPKeyPurposeRecovery)
|
purposeResult = "login";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MPKeyPurposeRecovery: {
|
||||||
passwordType = MPPasswordTypeGeneratedPhrase;
|
passwordType = MPPasswordTypeGeneratedPhrase;
|
||||||
if (passwordTypeArg && strlen( passwordTypeArg )) {
|
purposeResult = "answer";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (passwordTypeArg) {
|
||||||
passwordType = mpw_typeWithName( passwordTypeArg );
|
passwordType = mpw_typeWithName( passwordTypeArg );
|
||||||
if (ERR == passwordType) {
|
if (ERR == passwordType) {
|
||||||
ftl( "Invalid type: %s\n", passwordTypeArg );
|
ftl( "Invalid type: %s\n", passwordTypeArg );
|
||||||
return EX_USAGE;
|
return EX_USAGE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (keyContextArg && strlen( keyContextArg ))
|
if (keyContextArg)
|
||||||
keyContext = strdup( keyContextArg );
|
keyContext = strdup( keyContextArg );
|
||||||
|
|
||||||
// Summarize operation.
|
// Operation summary.
|
||||||
const char *identicon = mpw_identicon( fullName, masterPassword );
|
const char *identicon = mpw_identicon( fullName, masterPassword );
|
||||||
if (!identicon)
|
if (!identicon)
|
||||||
wrn( "Couldn't determine identicon.\n" );
|
wrn( "Couldn't determine identicon.\n" );
|
||||||
@ -324,6 +354,8 @@ int main(int argc, char *const argv[]) {
|
|||||||
dbg( "fullName : %s\n", fullName );
|
dbg( "fullName : %s\n", fullName );
|
||||||
trc( "masterPassword : %s\n", masterPassword );
|
trc( "masterPassword : %s\n", masterPassword );
|
||||||
dbg( "identicon : %s\n", identicon );
|
dbg( "identicon : %s\n", identicon );
|
||||||
|
dbg( "sitesFormat : %s%s\n", mpw_nameForFormat( sitesFormat ), sitesFormatFixed? " (fixed)": "" );
|
||||||
|
dbg( "sitesPath : %s\n", sitesPath );
|
||||||
dbg( "siteName : %s\n", siteName );
|
dbg( "siteName : %s\n", siteName );
|
||||||
dbg( "siteCounter : %u\n", siteCounter );
|
dbg( "siteCounter : %u\n", siteCounter );
|
||||||
dbg( "keyPurpose : %s (%u)\n", mpw_nameForPurpose( keyPurpose ), keyPurpose );
|
dbg( "keyPurpose : %s (%u)\n", mpw_nameForPurpose( keyPurpose ), keyPurpose );
|
||||||
@ -331,10 +363,12 @@ int main(int argc, char *const argv[]) {
|
|||||||
dbg( "passwordType : %s (%u)\n", mpw_nameForType( passwordType ), passwordType );
|
dbg( "passwordType : %s (%u)\n", mpw_nameForType( passwordType ), passwordType );
|
||||||
dbg( "algorithmVersion : %u\n", algorithmVersion );
|
dbg( "algorithmVersion : %u\n", algorithmVersion );
|
||||||
dbg( "-----------------\n\n" );
|
dbg( "-----------------\n\n" );
|
||||||
inf( "%s's password for %s:\n[ %s ]: ", fullName, siteName, identicon );
|
inf( "%s's %s for %s:\n[ %s ]: ", fullName, purposeResult, siteName, identicon );
|
||||||
mpw_free_string( identicon );
|
mpw_free_string( identicon );
|
||||||
|
if (sitesPath)
|
||||||
|
free( sitesPath );
|
||||||
|
|
||||||
// Output the password.
|
// Determine master key.
|
||||||
MPMasterKey masterKey = mpw_masterKey(
|
MPMasterKey masterKey = mpw_masterKey(
|
||||||
fullName, masterPassword, algorithmVersion );
|
fullName, masterPassword, algorithmVersion );
|
||||||
mpw_free_string( masterPassword );
|
mpw_free_string( masterPassword );
|
||||||
@ -344,19 +378,68 @@ int main(int argc, char *const argv[]) {
|
|||||||
return EX_SOFTWARE;
|
return EX_SOFTWARE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Output the result.
|
||||||
|
if (passwordType & MPPasswordTypeClassGenerated) {
|
||||||
MPSiteKey siteKey = mpw_siteKey( masterKey, siteName, siteCounter, keyPurpose, keyContext, algorithmVersion );
|
MPSiteKey siteKey = mpw_siteKey( masterKey, siteName, siteCounter, keyPurpose, keyContext, algorithmVersion );
|
||||||
const char *sitePassword = mpw_sitePassword( siteKey, passwordType, algorithmVersion );
|
const char *sitePassword = mpw_sitePassword( siteKey, passwordType, algorithmVersion );
|
||||||
mpw_free( masterKey, MPMasterKeySize );
|
|
||||||
mpw_free( siteKey, MPSiteKeySize );
|
mpw_free( siteKey, MPSiteKeySize );
|
||||||
mpw_free_string( siteName );
|
|
||||||
mpw_free_string( keyContext );
|
|
||||||
if (!sitePassword) {
|
if (!sitePassword) {
|
||||||
ftl( "Couldn't derive site password.\n" );
|
ftl( "Couldn't derive site password.\n" );
|
||||||
|
mpw_free( masterKey, MPMasterKeySize );
|
||||||
return EX_SOFTWARE;
|
return EX_SOFTWARE;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf( stdout, "%s\n", sitePassword );
|
fprintf( stdout, "%s\n", sitePassword );
|
||||||
mpw_free_string( sitePassword );
|
mpw_free_string( sitePassword );
|
||||||
|
}
|
||||||
|
else if (site && site->content) {
|
||||||
|
const char *sitePassword = mpw_decrypt( masterKey, site->content, algorithmVersion );
|
||||||
|
if (!sitePassword) {
|
||||||
|
ftl( "Couldn't decrypt site password.\n" );
|
||||||
|
mpw_free( masterKey, MPMasterKeySize );
|
||||||
|
return EX_SOFTWARE;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf( stdout, "%s\n", sitePassword );
|
||||||
|
mpw_free_string( sitePassword );
|
||||||
|
}
|
||||||
|
mpw_free( masterKey, MPMasterKeySize );
|
||||||
|
mpw_free_string( siteName );
|
||||||
|
mpw_free_string( keyContext );
|
||||||
|
|
||||||
|
// Update the mpsites file.
|
||||||
|
if (user) {
|
||||||
|
if (site) {
|
||||||
|
site->type = passwordType;
|
||||||
|
site->counter = siteCounter;
|
||||||
|
site->algorithm = algorithmVersion;
|
||||||
|
site->lastUsed = user->lastUsed = time( NULL );
|
||||||
|
site->uses++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sitesFormatFixed)
|
||||||
|
sitesFormat = MPMarshallFormatDefault;
|
||||||
|
|
||||||
|
sitesPath = mpw_path( user->fullName, mpw_marshall_format_extension( sitesFormat ) );
|
||||||
|
dbg( "Updating: %s (%s)\n", sitesPath, mpw_nameForFormat( sitesFormat ) );
|
||||||
|
if (!sitesPath || !(sitesFile = fopen( sitesPath, "w" )))
|
||||||
|
wrn( "Couldn't create updated configuration file:\n %s: %s\n", sitesPath, strerror( errno ) );
|
||||||
|
|
||||||
|
else {
|
||||||
|
char *buf = NULL;
|
||||||
|
MPMarshallError marshallError = { MPMarshallSuccess };
|
||||||
|
if (!mpw_marshall_write( &buf, sitesFormat, user, &marshallError ) || marshallError.type != MPMarshallSuccess)
|
||||||
|
wrn( "Couldn't encode updated configuration file:\n %s: %s\n", sitesPath, marshallError.description );
|
||||||
|
|
||||||
|
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 ) );
|
||||||
|
|
||||||
|
mpw_free_string( buf );
|
||||||
|
fclose( sitesFile );
|
||||||
|
}
|
||||||
|
free( sitesPath );
|
||||||
|
mpw_marshal_free( user );
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user