2
0

Some more refactoring.

This commit is contained in:
Maarten Billemont 2017-09-03 17:00:35 -04:00
parent ced7aef5d7
commit 4261160902

View File

@ -20,8 +20,8 @@ static void usage() {
inf( "" inf( ""
"\nUSAGE\n\n" "\nUSAGE\n\n"
" mpw [-u|-U full-name] [-m fd] [-t pw-type] [-P value] [-c counter]\n" " mpw [-u|-U full-name] [-m fd] [-t pw-type] [-P value] [-c counter]\n"
" [-a version] [-p purpose] [-C context] [-f|-F format] [-R 0|1]\n" " [-a version] [-p purpose] [-C context] [-f|F format] [-R 0|1]\n"
" [-v|-q] [-h] site-name\n\n" ); " [-v|-q] [-h] [site-name]\n\n" );
inf( "" inf( ""
" -u full-name Specify the full name of the user.\n" " -u full-name Specify the full name of the user.\n"
" -u checks the master password against the config,\n" " -u checks the master password against the config,\n"
@ -82,10 +82,14 @@ static void usage() {
MP_ENV_format, mpw_marshall_format_extension( MPMarshallFormatFlat ), mpw_marshall_format_extension( MPMarshallFormatJSON ) ); MP_ENV_format, mpw_marshall_format_extension( MPMarshallFormatFlat ), mpw_marshall_format_extension( MPMarshallFormatJSON ) );
inf( "" inf( ""
" -R redacted Whether to save the mpsites in redacted format or not.\n" " -R redacted Whether to save the mpsites in redacted format or not.\n"
" Redaction omits or encrypts any secrets, making the file safe\n"
" for saving on or transmitting via untrusted media.\n"
" Defaults to 1, redacted.\n\n" ); " Defaults to 1, redacted.\n\n" );
inf( "" inf( ""
" -v Increase output verbosity (can be repeated).\n" " -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( ""
" -h Show this help output instead of performing any operation.\n\n" );
inf( "" inf( ""
"\nENVIRONMENT\n\n" "\nENVIRONMENT\n\n"
" %-12s The full name of the user (see -u).\n" " %-12s The full name of the user (see -u).\n"
@ -118,6 +122,7 @@ typedef struct {
bool sitesFormatFixed; bool sitesFormatFixed;
const char *fullName; const char *fullName;
const char *masterPassword; const char *masterPassword;
const char *identicon;
const char *siteName; const char *siteName;
MPMarshallFormat sitesFormat; MPMarshallFormat sitesFormat;
MPKeyPurpose keyPurpose; MPKeyPurpose keyPurpose;
@ -200,35 +205,32 @@ int main(const int argc, char *const argv[]) {
cli_free( &args, NULL ); cli_free( &args, NULL );
// Operation summary. // Operation summary.
const char *identicon = mpw_identicon( operation.user->fullName, operation.user->masterPassword );
if (!identicon)
wrn( "Couldn't determine identicon.\n" );
dbg( "-----------------\n" ); dbg( "-----------------\n" );
dbg( "fullName : %s\n", operation.user->fullName ); if (operation.user) {
trc( "masterPassword : %s\n", operation.user->masterPassword ); dbg( "fullName : %s\n", operation.user->fullName );
dbg( "identicon : %s\n", identicon ); trc( "masterPassword : %s\n", operation.user->masterPassword );
dbg( "sitesFormat : %s%s\n", mpw_nameForFormat( operation.sitesFormat ), operation.sitesFormatFixed? " (fixed)": "" ); dbg( "identicon : %s\n", operation.identicon );
dbg( "sitesPath : %s\n", operation.sitesPath ); dbg( "sitesFormat : %s%s\n", mpw_nameForFormat( operation.sitesFormat ), operation.sitesFormatFixed? " (fixed)": "" );
dbg( "siteName : %s\n", operation.site->name ); dbg( "sitesPath : %s\n", operation.sitesPath );
dbg( "siteCounter : %u\n", operation.siteCounter ); }
dbg( "resultType : %s (%u)\n", mpw_nameForType( operation.resultType ), operation.resultType ); if (operation.site) {
dbg( "resultParam : %s\n", operation.resultParam ); dbg( "siteName : %s\n", operation.site->name );
dbg( "keyPurpose : %s (%u)\n", mpw_nameForPurpose( operation.keyPurpose ), operation.keyPurpose ); dbg( "siteCounter : %u\n", operation.siteCounter );
dbg( "keyContext : %s\n", operation.keyContext ); dbg( "resultType : %s (%u)\n", mpw_nameForType( operation.resultType ), operation.resultType );
dbg( "algorithmVersion : %u\n", operation.site->algorithm ); dbg( "resultParam : %s\n", operation.resultParam );
dbg( "keyPurpose : %s (%u)\n", mpw_nameForPurpose( operation.keyPurpose ), operation.keyPurpose );
dbg( "keyContext : %s\n", operation.keyContext );
dbg( "algorithmVersion : %u\n", operation.site->algorithm );
}
dbg( "-----------------\n\n" ); dbg( "-----------------\n\n" );
inf( "%s's %s for %s:\n[ %s ]: ", operation.user->fullName, operation.purposeResult, operation.site->name, identicon );
mpw_free_strings( &identicon, &operation.sitesPath, NULL );
// Finally ready to perform the actual operation. // Finally ready to perform the actual operation.
cli_mpw( &args, &operation ); cli_mpw( &args, &operation );
// Update metadata and save state. // Save changes and clean up.
operation.site->lastUsed = operation.user->lastUsed = time( NULL );
operation.site->uses++;
cli_save( &args, &operation ); cli_save( &args, &operation );
cli_free( &args, &operation ); cli_free( &args, &operation );
return EX_OK; return EX_OK;
} }
@ -242,7 +244,8 @@ void cli_free(Arguments *args, Operation *operation) {
if (operation) { if (operation) {
mpw_free_strings( &operation->fullName, &operation->masterPassword, &operation->siteName, NULL ); mpw_free_strings( &operation->fullName, &operation->masterPassword, &operation->siteName, NULL );
mpw_free_strings( &operation->keyContext, &operation->sitesPath, &operation->resultState, &operation->resultParam, NULL ); mpw_free_strings( &operation->keyContext, &operation->resultState, &operation->resultParam, NULL );
mpw_free_strings( &operation->identicon, &operation->sitesPath, NULL );
mpw_marshal_free( &operation->user ); mpw_marshal_free( &operation->user );
operation->site = NULL; operation->site = NULL;
operation->question = NULL; operation->question = NULL;
@ -325,6 +328,7 @@ void cli_args(Arguments *args, Operation *operation, const int argc, char *const
ftl( "Unexpected option: %c\n", opt ); ftl( "Unexpected option: %c\n", opt );
exit( EX_USAGE ); exit( EX_USAGE );
} }
if (optind < argc && argv[optind]) if (optind < argc && argv[optind])
args->siteName = strdup( argv[optind] ); args->siteName = strdup( argv[optind] );
} }
@ -333,10 +337,12 @@ void cli_fullName(Arguments *args, Operation *operation) {
if ((!operation->fullName || !strlen( operation->fullName )) && args->fullName) if ((!operation->fullName || !strlen( operation->fullName )) && args->fullName)
operation->fullName = strdup( args->fullName ); operation->fullName = strdup( args->fullName );
if (!operation->fullName || !strlen( operation->fullName )) if (!operation->fullName || !strlen( operation->fullName ))
do { do {
operation->fullName = mpw_getline( "Your full name:" ); operation->fullName = mpw_getline( "Your full name:" );
} while (operation->fullName && !strlen( operation->fullName )); } while (operation->fullName && !strlen( operation->fullName ));
if (!operation->fullName || !strlen( operation->fullName )) { if (!operation->fullName || !strlen( operation->fullName )) {
ftl( "Missing full name.\n" ); ftl( "Missing full name.\n" );
cli_free( args, operation ); cli_free( args, operation );
@ -351,12 +357,15 @@ void cli_masterPassword(Arguments *args, Operation *operation) {
if (!operation->masterPassword && errno) if (!operation->masterPassword && errno)
wrn( "Error reading master password from FD %s: %s\n", args->masterPasswordFD, strerror( errno ) ); wrn( "Error reading master password from FD %s: %s\n", args->masterPasswordFD, strerror( errno ) );
} }
if ((!operation->masterPassword || !strlen( operation->masterPassword )) && args->masterPassword) if ((!operation->masterPassword || !strlen( operation->masterPassword )) && args->masterPassword)
operation->masterPassword = strdup( args->masterPassword ); operation->masterPassword = strdup( args->masterPassword );
if (!operation->masterPassword || !strlen( operation->masterPassword )) if (!operation->masterPassword || !strlen( operation->masterPassword ))
do { do {
operation->masterPassword = mpw_getpass( "Your master password: " ); operation->masterPassword = mpw_getpass( "Your master password: " );
} while (operation->masterPassword && !strlen( operation->masterPassword )); } while (operation->masterPassword && !strlen( operation->masterPassword ));
if (!operation->masterPassword || !strlen( operation->masterPassword )) { if (!operation->masterPassword || !strlen( operation->masterPassword )) {
ftl( "Missing master password.\n" ); ftl( "Missing master password.\n" );
cli_free( args, operation ); cli_free( args, operation );
@ -382,32 +391,36 @@ void cli_siteName(Arguments *args, Operation *operation) {
void cli_sitesFormat(Arguments *args, Operation *operation) { void cli_sitesFormat(Arguments *args, Operation *operation) {
if (args->sitesFormat) { if (!args->sitesFormat)
operation->sitesFormat = mpw_formatWithName( args->sitesFormat ); return;
if (ERR == (int)operation->sitesFormat) {
ftl( "Invalid sites format: %s\n", args->sitesFormat ); operation->sitesFormat = mpw_formatWithName( args->sitesFormat );
cli_free( args, operation ); if (ERR == (int)operation->sitesFormat) {
exit( EX_DATAERR ); ftl( "Invalid sites format: %s\n", args->sitesFormat );
} cli_free( args, operation );
exit( EX_DATAERR );
} }
} }
void cli_keyPurpose(Arguments *args, Operation *operation) { void cli_keyPurpose(Arguments *args, Operation *operation) {
if (args->keyPurpose) { if (!args->keyPurpose)
operation->keyPurpose = mpw_purposeWithName( args->keyPurpose ); return;
if (ERR == (int)operation->keyPurpose) {
ftl( "Invalid purpose: %s\n", args->keyPurpose ); operation->keyPurpose = mpw_purposeWithName( args->keyPurpose );
cli_free( args, operation ); if (ERR == (int)operation->keyPurpose) {
exit( EX_DATAERR ); ftl( "Invalid purpose: %s\n", args->keyPurpose );
} cli_free( args, operation );
exit( EX_DATAERR );
} }
} }
void cli_keyContext(Arguments *args, Operation *operation) { void cli_keyContext(Arguments *args, Operation *operation) {
if (args->keyContext) if (!args->keyContext)
operation->keyContext = strdup( args->keyContext ); return;
operation->keyContext = strdup( args->keyContext );
} }
void cli_user(Arguments *args, Operation *operation) { void cli_user(Arguments *args, Operation *operation) {
@ -491,6 +504,9 @@ void cli_user(Arguments *args, Operation *operation) {
void cli_site(Arguments __unused *args, Operation *operation) { void cli_site(Arguments __unused *args, Operation *operation) {
if (!operation->siteName)
abort();
// Load the site object from mpsites. // Load the site object from mpsites.
for (size_t s = 0; !operation->site && s < operation->user->sites_count; ++s) for (size_t s = 0; !operation->site && s < operation->user->sites_count; ++s)
if (strcmp( operation->siteName, (&operation->user->sites[s])->name ) == 0) if (strcmp( operation->siteName, (&operation->user->sites[s])->name ) == 0)
@ -504,6 +520,9 @@ void cli_site(Arguments __unused *args, Operation *operation) {
void cli_question(Arguments __unused *args, Operation *operation) { void cli_question(Arguments __unused *args, Operation *operation) {
if (!operation->site)
abort();
// Load the question object from mpsites. // Load the question object from mpsites.
switch (operation->keyPurpose) { switch (operation->keyPurpose) {
case MPKeyPurposeAuthentication: case MPKeyPurposeAuthentication:
@ -524,6 +543,11 @@ void cli_question(Arguments __unused *args, Operation *operation) {
void cli_operation(Arguments __unused *args, Operation *operation) { void cli_operation(Arguments __unused *args, Operation *operation) {
operation->identicon = mpw_identicon( operation->user->fullName, operation->user->masterPassword );
if (!operation->site)
abort();
switch (operation->keyPurpose) { switch (operation->keyPurpose) {
case MPKeyPurposeAuthentication: { case MPKeyPurposeAuthentication: {
operation->purposeResult = "password"; operation->purposeResult = "password";
@ -553,80 +577,98 @@ void cli_operation(Arguments __unused *args, Operation *operation) {
void cli_resultType(Arguments *args, Operation *operation) { void cli_resultType(Arguments *args, Operation *operation) {
if (args->resultType) { if (!args->resultType)
operation->resultType = mpw_typeWithName( args->resultType ); return;
if (ERR == (int)operation->resultType) { if (!operation->site)
ftl( "Invalid type: %s\n", args->resultType ); abort();
cli_free( args, operation );
exit( EX_USAGE );
}
if (!(operation->resultType & MPSiteFeatureAlternative)) { operation->resultType = mpw_typeWithName( args->resultType );
switch (operation->keyPurpose) { if (ERR == (int)operation->resultType) {
case MPKeyPurposeAuthentication: ftl( "Invalid type: %s\n", args->resultType );
operation->site->type = operation->resultType; cli_free( args, operation );
break; exit( EX_USAGE );
case MPKeyPurposeIdentification: }
operation->site->loginType = operation->resultType;
break; if (!(operation->resultType & MPSiteFeatureAlternative)) {
case MPKeyPurposeRecovery: switch (operation->keyPurpose) {
operation->question->type = operation->resultType; case MPKeyPurposeAuthentication:
break; operation->site->type = operation->resultType;
} break;
case MPKeyPurposeIdentification:
operation->site->loginType = operation->resultType;
break;
case MPKeyPurposeRecovery:
operation->question->type = operation->resultType;
break;
} }
} }
} }
void cli_siteCounter(Arguments *args, Operation *operation) { void cli_siteCounter(Arguments *args, Operation *operation) {
if (args->siteCounter) { if (!args->siteCounter)
long long int siteCounterInt = atoll( args->siteCounter ); return;
if (siteCounterInt < MPCounterValueFirst || siteCounterInt > MPCounterValueLast) { if (!operation->site)
ftl( "Invalid site counter: %s\n", args->siteCounter ); abort();
cli_free( args, operation );
exit( EX_USAGE );
}
switch (operation->keyPurpose) { long long int siteCounterInt = atoll( args->siteCounter );
case MPKeyPurposeAuthentication: if (siteCounterInt < MPCounterValueFirst || siteCounterInt > MPCounterValueLast) {
operation->siteCounter = operation->site->counter = (MPCounterValue)siteCounterInt; ftl( "Invalid site counter: %s\n", args->siteCounter );
break; cli_free( args, operation );
case MPKeyPurposeIdentification: exit( EX_USAGE );
case MPKeyPurposeRecovery: }
// NOTE: counter for login & question is not persisted.
break; switch (operation->keyPurpose) {
} case MPKeyPurposeAuthentication:
operation->siteCounter = operation->site->counter = (MPCounterValue)siteCounterInt;
break;
case MPKeyPurposeIdentification:
case MPKeyPurposeRecovery:
// NOTE: counter for login & question is not persisted.
break;
} }
} }
void cli_resultParam(Arguments *args, Operation *operation) { void cli_resultParam(Arguments *args, Operation *operation) {
if (args->resultParam) if (!args->resultParam)
operation->resultParam = strdup( args->resultParam ); return;
operation->resultParam = strdup( args->resultParam );
} }
void cli_algorithmVersion(Arguments *args, Operation *operation) { void cli_algorithmVersion(Arguments *args, Operation *operation) {
if (args->algorithmVersion) { if (!args->algorithmVersion)
int algorithmVersionInt = atoi( args->algorithmVersion ); return;
if (algorithmVersionInt < MPAlgorithmVersionFirst || algorithmVersionInt > MPAlgorithmVersionLast) { if (!operation->site)
ftl( "Invalid algorithm version: %s\n", args->algorithmVersion ); abort();
cli_free( args, operation );
exit( EX_USAGE ); int algorithmVersionInt = atoi( args->algorithmVersion );
} if (algorithmVersionInt < MPAlgorithmVersionFirst || algorithmVersionInt > MPAlgorithmVersionLast) {
operation->site->algorithm = (MPAlgorithmVersion)algorithmVersionInt; ftl( "Invalid algorithm version: %s\n", args->algorithmVersion );
cli_free( args, operation );
exit( EX_USAGE );
} }
operation->site->algorithm = (MPAlgorithmVersion)algorithmVersionInt;
} }
void cli_sitesRedacted(Arguments *args, Operation *operation) { void cli_sitesRedacted(Arguments *args, Operation *operation) {
if (args->sitesRedacted) if (args->sitesRedacted)
operation->user->redacted = strcmp( args->sitesRedacted, "1" ) == 0; operation->user->redacted = strcmp( args->sitesRedacted, "1" ) == 0;
else if (!operation->user->redacted) else if (!operation->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" );
} }
void cli_mpw(Arguments *args, Operation *operation) { void cli_mpw(Arguments *args, Operation *operation) {
if (!operation->site)
abort();
inf( "%s's %s for %s:\n[ %s ]: ", operation->user->fullName, operation->purposeResult, operation->site->name, operation->identicon );
// Determine master key. // Determine master key.
MPMasterKey masterKey = mpw_masterKey( MPMasterKey masterKey = mpw_masterKey(
operation->user->fullName, operation->user->masterPassword, operation->site->algorithm ); operation->user->fullName, operation->user->masterPassword, operation->site->algorithm );
@ -640,7 +682,8 @@ void cli_mpw(Arguments *args, Operation *operation) {
if (operation->resultParam && operation->resultType & MPResultTypeClassStateful) { if (operation->resultParam && operation->resultType & MPResultTypeClassStateful) {
mpw_free_string( &operation->resultState ); mpw_free_string( &operation->resultState );
if (!(operation->resultState = mpw_siteState( masterKey, operation->site->name, operation->siteCounter, if (!(operation->resultState = mpw_siteState( masterKey, operation->site->name, operation->siteCounter,
operation->keyPurpose, operation->keyContext, operation->resultType, operation->resultParam, operation->site->algorithm ))) { operation->keyPurpose, operation->keyContext, operation->resultType, operation->resultParam,
operation->site->algorithm ))) {
ftl( "Couldn't encrypt site result.\n" ); ftl( "Couldn't encrypt site result.\n" );
mpw_free( &masterKey, MPMasterKeySize ); mpw_free( &masterKey, MPMasterKeySize );
cli_free( args, operation ); cli_free( args, operation );
@ -688,6 +731,10 @@ void cli_mpw(Arguments *args, Operation *operation) {
if (operation->site->url) if (operation->site->url)
inf( "See: %s\n", operation->site->url ); inf( "See: %s\n", operation->site->url );
mpw_free_string( &result ); mpw_free_string( &result );
// Update usage metadata.
operation->site->lastUsed = operation->user->lastUsed = time( NULL );
operation->site->uses++;
} }
void cli_save(Arguments __unused *args, Operation *operation) { void cli_save(Arguments __unused *args, Operation *operation) {