Refactor CLI code to make the flow more clear and the free'ing more reliable.
This commit is contained in:
parent
060ce61030
commit
6811773e54
@ -93,70 +93,210 @@ static void usage() {
|
|||||||
" %-12s The default mpsites format (see -f).\n"
|
" %-12s The default mpsites format (see -f).\n"
|
||||||
" %-12s The askpass program to use for prompting the user.\n\n",
|
" %-12s The askpass program to use for prompting the user.\n\n",
|
||||||
MP_ENV_fullName, MP_ENV_algorithm, MP_ENV_format, MP_ENV_askpass );
|
MP_ENV_fullName, MP_ENV_algorithm, MP_ENV_format, MP_ENV_askpass );
|
||||||
exit( 0 );
|
exit( EX_OK );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Internal state.
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char *fullName;
|
||||||
|
const char *masterPasswordFD;
|
||||||
|
const char *masterPassword;
|
||||||
|
const char *siteName;
|
||||||
|
const char *resultType;
|
||||||
|
const char *resultParam;
|
||||||
|
const char *siteCounter;
|
||||||
|
const char *algorithmVersion;
|
||||||
|
const char *keyPurpose;
|
||||||
|
const char *keyContext;
|
||||||
|
const char *sitesFormat;
|
||||||
|
const char *sitesRedacted;
|
||||||
|
} Arguments;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool allowPasswordUpdate;
|
||||||
|
bool sitesFormatFixed;
|
||||||
|
const char *fullName;
|
||||||
|
const char *masterPassword;
|
||||||
|
const char *siteName;
|
||||||
|
MPMarshallFormat sitesFormat;
|
||||||
|
MPKeyPurpose keyPurpose;
|
||||||
|
const char *keyContext;
|
||||||
|
const char *sitesPath;
|
||||||
|
MPResultType resultType;
|
||||||
|
MPCounterValue siteCounter;
|
||||||
|
const char *purposeResult;
|
||||||
|
const char *resultState;
|
||||||
|
const char *resultParam;
|
||||||
|
MPMarshalledUser *user;
|
||||||
|
MPMarshalledSite *site;
|
||||||
|
MPMarshalledQuestion *question;
|
||||||
|
} Operation;
|
||||||
|
|
||||||
|
// Processing steps.
|
||||||
|
|
||||||
|
void cli_free(Arguments *args, Operation *operation);
|
||||||
|
void cli_args(Arguments *args, Operation *operation, const int argc, char *const argv[]);
|
||||||
|
void cli_fullName(Arguments *args, Operation *operation);
|
||||||
|
void cli_masterPassword(Arguments *args, Operation *operation);
|
||||||
|
void cli_siteName(Arguments *args, Operation *operation);
|
||||||
|
void cli_sitesFormat(Arguments *args, Operation *operation);
|
||||||
|
void cli_keyPurpose(Arguments *args, Operation *operation);
|
||||||
|
void cli_keyContext(Arguments *args, Operation *operation);
|
||||||
|
void cli_user(Arguments *args, Operation *operation);
|
||||||
|
void cli_site(Arguments *args, Operation *operation);
|
||||||
|
void cli_question(Arguments *args, Operation *operation);
|
||||||
|
void cli_operation(Arguments *args, Operation *operation);
|
||||||
|
void cli_resultType(Arguments *args, Operation *operation);
|
||||||
|
void cli_siteCounter(Arguments *args, Operation *operation);
|
||||||
|
void cli_resultParam(Arguments *args, Operation *operation);
|
||||||
|
void cli_algorithmVersion(Arguments *args, Operation *operation);
|
||||||
|
void cli_sitesRedacted(Arguments *args, Operation *operation);
|
||||||
|
void cli_mpw(Arguments *args, Operation *operation);
|
||||||
|
void cli_save(Arguments *args, Operation *operation);
|
||||||
|
|
||||||
/** ========================================================================
|
/** ========================================================================
|
||||||
* MAIN */
|
* MAIN */
|
||||||
int main(const int argc, char *const argv[]) {
|
int main(const int argc, char *const argv[]) {
|
||||||
|
|
||||||
// CLI defaults.
|
// Application defaults.
|
||||||
bool allowPasswordUpdate = false, sitesFormatFixed = false;
|
Arguments args = {
|
||||||
|
.fullName = mpw_getenv( MP_ENV_fullName ),
|
||||||
// Read the environment.
|
.algorithmVersion = mpw_getenv( MP_ENV_algorithm ),
|
||||||
const char *fullNameArg = NULL, *masterPasswordFDArg = NULL, *masterPasswordArg = NULL, *siteNameArg = NULL;
|
.sitesFormat = mpw_getenv( MP_ENV_format ),
|
||||||
const char *resultTypeArg = NULL, *resultParamArg = NULL, *siteCounterArg = NULL, *algorithmVersionArg = NULL;
|
};
|
||||||
const char *keyPurposeArg = NULL, *keyContextArg = NULL, *sitesFormatArg = NULL, *sitesRedactedArg = NULL;
|
Operation operation = {
|
||||||
fullNameArg = mpw_getenv( MP_ENV_fullName );
|
.allowPasswordUpdate = false,
|
||||||
algorithmVersionArg = mpw_getenv( MP_ENV_algorithm );
|
.sitesFormatFixed = false,
|
||||||
sitesFormatArg = mpw_getenv( MP_ENV_format );
|
.sitesFormat = MPMarshallFormatDefault,
|
||||||
|
.keyPurpose = MPKeyPurposeAuthentication,
|
||||||
|
.resultType = MPResultTypeDefault,
|
||||||
|
.siteCounter = MPCounterValueDefault,
|
||||||
|
};
|
||||||
|
|
||||||
// Read the command-line options.
|
// Read the command-line options.
|
||||||
for (int opt; (opt = getopt( argc, argv, "u:U:m:M:t:P:c:a:p:C:f:F:R:vqh" )) != EOF;)
|
cli_args( &args, &operation, argc, argv );
|
||||||
|
|
||||||
|
// Determine the operation parameters not sourced from mpsites.
|
||||||
|
cli_fullName( &args, &operation );
|
||||||
|
cli_masterPassword( &args, &operation );
|
||||||
|
cli_siteName( &args, &operation );
|
||||||
|
cli_sitesFormat( &args, &operation );
|
||||||
|
cli_keyPurpose( &args, &operation );
|
||||||
|
cli_keyContext( &args, &operation );
|
||||||
|
|
||||||
|
// Load the operation parameters from mpsites.
|
||||||
|
cli_user( &args, &operation );
|
||||||
|
cli_site( &args, &operation );
|
||||||
|
cli_question( &args, &operation );
|
||||||
|
cli_operation( &args, &operation );
|
||||||
|
|
||||||
|
// Override the operation parameters from command-line arguments.
|
||||||
|
cli_resultType( &args, &operation );
|
||||||
|
cli_siteCounter( &args, &operation );
|
||||||
|
cli_resultParam( &args, &operation );
|
||||||
|
cli_algorithmVersion( &args, &operation );
|
||||||
|
cli_sitesRedacted( &args, &operation );
|
||||||
|
cli_free( &args, NULL );
|
||||||
|
|
||||||
|
// Operation summary.
|
||||||
|
const char *identicon = mpw_identicon( operation.user->fullName, operation.user->masterPassword );
|
||||||
|
if (!identicon)
|
||||||
|
wrn( "Couldn't determine identicon.\n" );
|
||||||
|
dbg( "-----------------\n" );
|
||||||
|
dbg( "fullName : %s\n", operation.user->fullName );
|
||||||
|
trc( "masterPassword : %s\n", operation.user->masterPassword );
|
||||||
|
dbg( "identicon : %s\n", identicon );
|
||||||
|
dbg( "sitesFormat : %s%s\n", mpw_nameForFormat( operation.sitesFormat ), operation.sitesFormatFixed? " (fixed)": "" );
|
||||||
|
dbg( "sitesPath : %s\n", operation.sitesPath );
|
||||||
|
dbg( "siteName : %s\n", operation.site->name );
|
||||||
|
dbg( "siteCounter : %u\n", operation.siteCounter );
|
||||||
|
dbg( "resultType : %s (%u)\n", mpw_nameForType( operation.resultType ), operation.resultType );
|
||||||
|
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" );
|
||||||
|
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.
|
||||||
|
cli_mpw( &args, &operation );
|
||||||
|
|
||||||
|
// Update metadata and save state.
|
||||||
|
operation.site->lastUsed = operation.user->lastUsed = time( NULL );
|
||||||
|
operation.site->uses++;
|
||||||
|
cli_save( &args, &operation );
|
||||||
|
|
||||||
|
cli_free( &args, &operation );
|
||||||
|
return EX_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cli_free(Arguments *args, Operation *operation) {
|
||||||
|
|
||||||
|
if (args) {
|
||||||
|
mpw_free_strings( &args->fullName, &args->masterPasswordFD, &args->masterPassword, &args->siteName, NULL );
|
||||||
|
mpw_free_strings( &args->resultType, &args->resultParam, &args->siteCounter, &args->algorithmVersion, NULL );
|
||||||
|
mpw_free_strings( &args->keyPurpose, &args->keyContext, &args->sitesFormat, &args->sitesRedacted, NULL );
|
||||||
|
}
|
||||||
|
|
||||||
|
if (operation) {
|
||||||
|
mpw_free_strings( &operation->fullName, &operation->masterPassword, &operation->siteName, NULL );
|
||||||
|
mpw_free_strings( &operation->keyContext, &operation->sitesPath, &operation->purposeResult, NULL );
|
||||||
|
mpw_free_strings( &operation->resultState, &operation->resultParam, NULL );
|
||||||
|
mpw_marshal_free( &operation->user );
|
||||||
|
operation->site = NULL;
|
||||||
|
operation->question = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cli_args(Arguments *args, Operation *operation, const int argc, char *const argv[]) {
|
||||||
|
|
||||||
|
for (int opt; (opt = getopt( argc, argv, "u:U:m:M:t:P:c:a:p:C:f:F:R:vqh" )) != EOF; optarg? bzero( optarg, strlen( optarg ) ): NULL)
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'u':
|
case 'u':
|
||||||
fullNameArg = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
args->fullName = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
||||||
allowPasswordUpdate = false;
|
operation->allowPasswordUpdate = false;
|
||||||
break;
|
break;
|
||||||
case 'U':
|
case 'U':
|
||||||
fullNameArg = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
args->fullName = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
||||||
allowPasswordUpdate = true;
|
operation->allowPasswordUpdate = true;
|
||||||
break;
|
break;
|
||||||
case 'm':
|
case 'm':
|
||||||
masterPasswordFDArg = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
args->masterPasswordFD = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
||||||
break;
|
break;
|
||||||
case 'M':
|
case 'M':
|
||||||
// Passing your master password via the command-line is insecure. Testing purposes only.
|
// Passing your master password via the command-line is insecure. Testing purposes only.
|
||||||
masterPasswordArg = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
args->masterPassword = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
||||||
break;
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
resultTypeArg = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
args->resultType = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
||||||
break;
|
break;
|
||||||
case 'P':
|
case 'P':
|
||||||
resultParamArg = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
args->resultParam = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
siteCounterArg = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
args->siteCounter = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
||||||
break;
|
break;
|
||||||
case 'a':
|
case 'a':
|
||||||
algorithmVersionArg = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
args->algorithmVersion = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
keyPurposeArg = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
args->keyPurpose = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
||||||
break;
|
break;
|
||||||
case 'C':
|
case 'C':
|
||||||
keyContextArg = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
args->keyContext = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
||||||
break;
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
sitesFormatArg = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
args->sitesFormat = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
||||||
sitesFormatFixed = false;
|
operation->sitesFormatFixed = false;
|
||||||
break;
|
break;
|
||||||
case 'F':
|
case 'F':
|
||||||
sitesFormatArg = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
args->sitesFormat = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
||||||
sitesFormatFixed = true;
|
operation->sitesFormatFixed = true;
|
||||||
break;
|
break;
|
||||||
case 'R':
|
case 'R':
|
||||||
sitesRedactedArg = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
args->sitesRedacted = optarg && strlen( optarg )? strdup( optarg ): NULL;
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
++mpw_verbosity;
|
++mpw_verbosity;
|
||||||
@ -171,132 +311,145 @@ int main(const int argc, char *const argv[]) {
|
|||||||
switch (optopt) {
|
switch (optopt) {
|
||||||
case 'u':
|
case 'u':
|
||||||
ftl( "Missing full name to option: -%c\n", optopt );
|
ftl( "Missing full name to option: -%c\n", optopt );
|
||||||
return EX_USAGE;
|
exit( EX_USAGE );
|
||||||
case 't':
|
case 't':
|
||||||
ftl( "Missing type name to option: -%c\n", optopt );
|
ftl( "Missing type name to option: -%c\n", optopt );
|
||||||
return EX_USAGE;
|
exit( EX_USAGE );
|
||||||
case 'c':
|
case 'c':
|
||||||
ftl( "Missing counter value to option: -%c\n", optopt );
|
ftl( "Missing counter value to option: -%c\n", optopt );
|
||||||
return EX_USAGE;
|
exit( EX_USAGE );
|
||||||
default:
|
default:
|
||||||
ftl( "Unknown option: -%c\n", optopt );
|
ftl( "Unknown option: -%c\n", optopt );
|
||||||
return EX_USAGE;
|
exit( EX_USAGE );
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
ftl( "Unexpected option: %c\n", opt );
|
ftl( "Unexpected option: %c\n", opt );
|
||||||
return EX_USAGE;
|
exit( EX_USAGE );
|
||||||
}
|
}
|
||||||
if (optind < argc && argv[optind])
|
if (optind < argc && argv[optind])
|
||||||
siteNameArg = strdup( argv[optind] );
|
args->siteName = strdup( argv[optind] );
|
||||||
|
}
|
||||||
|
|
||||||
// Determine fullName, siteName & masterPassword.
|
void cli_fullName(Arguments *args, Operation *operation) {
|
||||||
const char *fullName = NULL, *masterPassword = NULL, *siteName = NULL;
|
|
||||||
if ((!fullName || !strlen( fullName )) && fullNameArg)
|
if ((!operation->fullName || !strlen( operation->fullName )) && args->fullName)
|
||||||
fullName = strdup( fullNameArg );
|
operation->fullName = strdup( args->fullName );
|
||||||
if (!fullName || !strlen( fullName ))
|
if (!operation->fullName || !strlen( operation->fullName ))
|
||||||
do {
|
do {
|
||||||
fullName = mpw_getline( "Your full name:" );
|
operation->fullName = mpw_getline( "Your full name:" );
|
||||||
} while (fullName && !strlen( fullName ));
|
} while (operation->fullName && !strlen( operation->fullName ));
|
||||||
if (!fullName || !strlen( fullName )) {
|
if (!operation->fullName || !strlen( operation->fullName )) {
|
||||||
ftl( "Missing full name.\n" );
|
ftl( "Missing full name.\n" );
|
||||||
mpw_free_strings( &fullName, &masterPassword, &siteName, NULL );
|
cli_free( args, operation );
|
||||||
return EX_DATAERR;
|
exit( EX_DATAERR );
|
||||||
}
|
}
|
||||||
if ((!masterPassword || !strlen( masterPassword )) && masterPasswordFDArg) {
|
}
|
||||||
masterPassword = mpw_read_fd( atoi( masterPasswordFDArg ) );
|
|
||||||
if (!masterPassword && errno)
|
|
||||||
wrn( "Error reading master password from FD %s: %s\n", masterPasswordFDArg, strerror( errno ) );
|
|
||||||
}
|
|
||||||
if ((!masterPassword || !strlen( masterPassword )) && masterPasswordArg)
|
|
||||||
masterPassword = strdup( masterPasswordArg );
|
|
||||||
if (!masterPassword || !strlen( masterPassword ))
|
|
||||||
do {
|
|
||||||
masterPassword = mpw_getpass( "Your master password: " );
|
|
||||||
} while (masterPassword && !strlen( masterPassword ));
|
|
||||||
if (!masterPassword || !strlen( masterPassword )) {
|
|
||||||
ftl( "Missing master password.\n" );
|
|
||||||
mpw_free_strings( &fullName, &masterPassword, &siteName, NULL );
|
|
||||||
return EX_DATAERR;
|
|
||||||
}
|
|
||||||
if ((!siteName || !strlen( siteName )) && siteNameArg)
|
|
||||||
siteName = strdup( siteNameArg );
|
|
||||||
if (!siteName || !strlen( siteName ))
|
|
||||||
do {
|
|
||||||
siteName = mpw_getline( "Site name:" );
|
|
||||||
} while (siteName && !strlen( siteName ));
|
|
||||||
if (!siteName || !strlen( siteName )) {
|
|
||||||
ftl( "Missing site name.\n" );
|
|
||||||
mpw_free_strings( &fullName, &masterPassword, &siteName, NULL );
|
|
||||||
return EX_DATAERR;
|
|
||||||
}
|
|
||||||
MPMarshallFormat sitesFormat = MPMarshallFormatDefault;
|
|
||||||
if (sitesFormatArg) {
|
|
||||||
sitesFormat = mpw_formatWithName( sitesFormatArg );
|
|
||||||
if (ERR == (int)sitesFormat) {
|
|
||||||
ftl( "Invalid sites format: %s\n", sitesFormatArg );
|
|
||||||
mpw_free_strings( &fullName, &masterPassword, &siteName, NULL );
|
|
||||||
return EX_USAGE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MPKeyPurpose keyPurpose = MPKeyPurposeAuthentication;
|
|
||||||
if (keyPurposeArg) {
|
|
||||||
keyPurpose = mpw_purposeWithName( keyPurposeArg );
|
|
||||||
if (ERR == (int)keyPurpose) {
|
|
||||||
ftl( "Invalid purpose: %s\n", keyPurposeArg );
|
|
||||||
return EX_USAGE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const char *keyContext = NULL;
|
|
||||||
if (keyContextArg)
|
|
||||||
keyContext = strdup( keyContextArg );
|
|
||||||
|
|
||||||
// Find the user's sites file.
|
void cli_masterPassword(Arguments *args, Operation *operation) {
|
||||||
|
|
||||||
|
if ((!operation->masterPassword || !strlen( operation->masterPassword )) && args->masterPasswordFD) {
|
||||||
|
operation->masterPassword = mpw_read_fd( atoi( args->masterPasswordFD ) );
|
||||||
|
if (!operation->masterPassword && errno)
|
||||||
|
wrn( "Error reading master password from FD %s: %s\n", args->masterPasswordFD, strerror( errno ) );
|
||||||
|
}
|
||||||
|
if ((!operation->masterPassword || !strlen( operation->masterPassword )) && args->masterPassword)
|
||||||
|
operation->masterPassword = strdup( args->masterPassword );
|
||||||
|
if (!operation->masterPassword || !strlen( operation->masterPassword ))
|
||||||
|
do {
|
||||||
|
operation->masterPassword = mpw_getpass( "Your master password: " );
|
||||||
|
} while (operation->masterPassword && !strlen( operation->masterPassword ));
|
||||||
|
if (!operation->masterPassword || !strlen( operation->masterPassword )) {
|
||||||
|
ftl( "Missing master password.\n" );
|
||||||
|
cli_free( args, operation );
|
||||||
|
exit( EX_DATAERR );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cli_siteName(Arguments *args, Operation *operation) {
|
||||||
|
|
||||||
|
if ((!operation->siteName || !strlen( operation->siteName )) && args->siteName)
|
||||||
|
operation->siteName = strdup( args->siteName );
|
||||||
|
if (!operation->siteName || !strlen( operation->siteName ))
|
||||||
|
do {
|
||||||
|
operation->siteName = mpw_getline( "Site name:" );
|
||||||
|
} while (operation->siteName && !strlen( operation->siteName ));
|
||||||
|
|
||||||
|
if (!operation->siteName || !strlen( operation->siteName )) {
|
||||||
|
ftl( "Missing site name.\n" );
|
||||||
|
cli_free( args, operation );
|
||||||
|
exit( EX_DATAERR );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cli_sitesFormat(Arguments *args, Operation *operation) {
|
||||||
|
|
||||||
|
if (args->sitesFormat) {
|
||||||
|
operation->sitesFormat = mpw_formatWithName( args->sitesFormat );
|
||||||
|
if (ERR == (int)operation->sitesFormat) {
|
||||||
|
ftl( "Invalid sites format: %s\n", args->sitesFormat );
|
||||||
|
cli_free( args, operation );
|
||||||
|
exit( EX_DATAERR );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cli_keyPurpose(Arguments *args, Operation *operation) {
|
||||||
|
|
||||||
|
if (args->keyPurpose) {
|
||||||
|
operation->keyPurpose = mpw_purposeWithName( args->keyPurpose );
|
||||||
|
if (ERR == (int)operation->keyPurpose) {
|
||||||
|
ftl( "Invalid purpose: %s\n", args->keyPurpose );
|
||||||
|
cli_free( args, operation );
|
||||||
|
exit( EX_DATAERR );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cli_keyContext(Arguments *args, Operation *operation) {
|
||||||
|
|
||||||
|
if (args->keyContext)
|
||||||
|
operation->keyContext = strdup( args->keyContext );
|
||||||
|
}
|
||||||
|
|
||||||
|
void cli_user(Arguments *args, Operation *operation) {
|
||||||
|
|
||||||
|
// Find mpsites file from parameters.
|
||||||
FILE *sitesFile = NULL;
|
FILE *sitesFile = NULL;
|
||||||
const char *sitesPath = mpw_path( fullName, mpw_marshall_format_extension( sitesFormat ) );
|
mpw_free_string( &operation->sitesPath );
|
||||||
if (!sitesPath || !(sitesFile = fopen( sitesPath, "r" ))) {
|
operation->sitesPath = mpw_path( operation->fullName, mpw_marshall_format_extension( operation->sitesFormat ) );
|
||||||
dbg( "Couldn't open configuration file:\n %s: %s\n", sitesPath, strerror( errno ) );
|
if (!operation->sitesPath || !(sitesFile = fopen( operation->sitesPath, "r" ))) {
|
||||||
|
dbg( "Couldn't open configuration file:\n %s: %s\n", operation->sitesPath, strerror( errno ) );
|
||||||
|
|
||||||
// Try to fall back to the flat format.
|
// Try to fall back to the flat format.
|
||||||
if (!sitesFormatFixed) {
|
if (!operation->sitesFormatFixed) {
|
||||||
mpw_free_string( &sitesPath );
|
mpw_free_string( &operation->sitesPath );
|
||||||
sitesPath = mpw_path( fullName, mpw_marshall_format_extension( MPMarshallFormatFlat ) );
|
operation->sitesPath = mpw_path( operation->fullName, mpw_marshall_format_extension( MPMarshallFormatFlat ) );
|
||||||
if (sitesPath && (sitesFile = fopen( sitesPath, "r" )))
|
if (operation->sitesPath && (sitesFile = fopen( operation->sitesPath, "r" )))
|
||||||
sitesFormat = MPMarshallFormatFlat;
|
operation->sitesFormat = MPMarshallFormatFlat;
|
||||||
else
|
else
|
||||||
dbg( "Couldn't open configuration file:\n %s: %s\n", sitesPath, strerror( errno ) );
|
dbg( "Couldn't open configuration file:\n %s: %s\n", operation->sitesPath, strerror( errno ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the user object from file.
|
// Load the user object from mpsites.
|
||||||
MPMarshalledUser *user = NULL;
|
|
||||||
MPMarshalledSite *site = NULL;
|
|
||||||
MPMarshalledQuestion *question = NULL;
|
|
||||||
if (!sitesFile)
|
if (!sitesFile)
|
||||||
mpw_free_string( &sitesPath );
|
mpw_free_string( &operation->sitesPath );
|
||||||
|
|
||||||
else {
|
else {
|
||||||
// Read file.
|
// Read file.
|
||||||
char *sitesInputData = mpw_read_file( sitesFile );
|
char *sitesInputData = mpw_read_file( sitesFile );
|
||||||
if (ferror( sitesFile ))
|
if (ferror( sitesFile ))
|
||||||
wrn( "Error while reading configuration file:\n %s: %d\n", sitesPath, ferror( sitesFile ) );
|
wrn( "Error while reading configuration file:\n %s: %d\n", operation->sitesPath, ferror( sitesFile ) );
|
||||||
fclose( sitesFile );
|
fclose( sitesFile );
|
||||||
|
|
||||||
// Parse file.
|
// Parse file.
|
||||||
MPMarshallInfo *sitesInputInfo = mpw_marshall_read_info( sitesInputData );
|
MPMarshallInfo *sitesInputInfo = mpw_marshall_read_info( sitesInputData );
|
||||||
MPMarshallFormat sitesInputFormat = sitesFormatArg? sitesFormat: sitesInputInfo->format;
|
MPMarshallFormat sitesInputFormat = args->sitesFormat? operation->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 );
|
operation->user = mpw_marshall_read( sitesInputData, sitesInputFormat, operation->masterPassword, &marshallError );
|
||||||
if (marshallError.type == MPMarshallErrorMasterPassword) {
|
if (marshallError.type == MPMarshallErrorMasterPassword && operation->allowPasswordUpdate) {
|
||||||
// Incorrect master password.
|
// Update master password in mpsites.
|
||||||
if (!allowPasswordUpdate) {
|
|
||||||
ftl( "Incorrect master password according to configuration:\n %s: %s\n", sitesPath, marshallError.description );
|
|
||||||
mpw_marshal_free( &user );
|
|
||||||
mpw_free_strings( &sitesInputData, &sitesPath, &fullName, &masterPassword, &siteName, NULL );
|
|
||||||
return EX_DATAERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update user's master password.
|
|
||||||
while (marshallError.type == MPMarshallErrorMasterPassword) {
|
while (marshallError.type == MPMarshallErrorMasterPassword) {
|
||||||
inf( "Given master password does not match configuration.\n" );
|
inf( "Given master password does not match configuration.\n" );
|
||||||
inf( "To update the configuration with this new master password, first confirm the old master password.\n" );
|
inf( "To update the configuration with this new master password, first confirm the old master password.\n" );
|
||||||
@ -305,124 +458,139 @@ int main(const 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( &operation->user );
|
||||||
user = mpw_marshall_read( sitesInputData, sitesInputFormat, importMasterPassword, &marshallError );
|
operation->user = mpw_marshall_read( sitesInputData, sitesInputFormat, importMasterPassword, &marshallError );
|
||||||
mpw_free_string( &importMasterPassword );
|
mpw_free_string( &importMasterPassword );
|
||||||
}
|
}
|
||||||
if (user) {
|
if (operation->user) {
|
||||||
mpw_free_string( &user->masterPassword );
|
mpw_free_string( &operation->user->masterPassword );
|
||||||
user->masterPassword = strdup( masterPassword );
|
operation->user->masterPassword = strdup( operation->masterPassword );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mpw_free_string( &sitesInputData );
|
mpw_free_string( &sitesInputData );
|
||||||
|
|
||||||
if (!user || marshallError.type != MPMarshallSuccess) {
|
// Incorrect master password.
|
||||||
err( "Couldn't parse configuration file:\n %s: %s\n", sitesPath, marshallError.description );
|
if (marshallError.type == MPMarshallErrorMasterPassword) {
|
||||||
mpw_marshal_free( &user );
|
ftl( "Incorrect master password according to configuration:\n %s: %s\n", operation->sitesPath, marshallError.description );
|
||||||
mpw_free_string( &sitesPath );
|
cli_free( args, operation );
|
||||||
|
exit( EX_DATAERR );
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (!user)
|
|
||||||
user = mpw_marshall_user( fullName, masterPassword, MPAlgorithmVersionCurrent );
|
|
||||||
mpw_free_strings( &fullName, &masterPassword, NULL );
|
|
||||||
|
|
||||||
// Load the site object.
|
// Any other parse error.
|
||||||
for (size_t s = 0; s < user->sites_count; ++s) {
|
if (!operation->user || marshallError.type != MPMarshallSuccess) {
|
||||||
site = &user->sites[s];
|
err( "Couldn't parse configuration file:\n %s: %s\n", operation->sitesPath, marshallError.description );
|
||||||
if (strcmp( siteName, site->name ) == 0)
|
cli_free( args, operation );
|
||||||
// Found.
|
exit( EX_DATAERR );
|
||||||
break;
|
}
|
||||||
site = NULL;
|
|
||||||
}
|
}
|
||||||
if (!site)
|
|
||||||
site = mpw_marshall_site( user, siteName, MPResultTypeDefault, MPCounterValueDefault, user->algorithm );
|
|
||||||
mpw_free_string( &siteName );
|
|
||||||
|
|
||||||
// Load the question object.
|
// If no user from mpsites, create a new one.
|
||||||
switch (keyPurpose) {
|
if (!operation->user)
|
||||||
|
operation->user = mpw_marshall_user(
|
||||||
|
operation->fullName, operation->masterPassword, MPAlgorithmVersionCurrent );
|
||||||
|
}
|
||||||
|
|
||||||
|
void cli_site(Arguments __unused *args, Operation *operation) {
|
||||||
|
|
||||||
|
// Load the site object from mpsites.
|
||||||
|
for (size_t s = 0; !operation->site && s < operation->user->sites_count; ++s)
|
||||||
|
if (strcmp( operation->siteName, (&operation->user->sites[s])->name ) == 0)
|
||||||
|
operation->site = &operation->user->sites[s];
|
||||||
|
|
||||||
|
// If no site from mpsites, create a new one.
|
||||||
|
if (!operation->site)
|
||||||
|
operation->site = mpw_marshall_site(
|
||||||
|
operation->user, operation->siteName, MPResultTypeDefault, MPCounterValueDefault, operation->user->algorithm );
|
||||||
|
}
|
||||||
|
|
||||||
|
void cli_question(Arguments __unused *args, Operation *operation) {
|
||||||
|
|
||||||
|
// Load the question object from mpsites.
|
||||||
|
switch (operation->keyPurpose) {
|
||||||
case MPKeyPurposeAuthentication:
|
case MPKeyPurposeAuthentication:
|
||||||
case MPKeyPurposeIdentification:
|
case MPKeyPurposeIdentification:
|
||||||
break;
|
break;
|
||||||
case MPKeyPurposeRecovery:
|
case MPKeyPurposeRecovery:
|
||||||
for (size_t q = 0; q < site->questions_count; ++q) {
|
for (size_t q = 0; !operation->question && q < operation->site->questions_count; ++q)
|
||||||
question = &site->questions[q];
|
if ((!operation->keyContext && !strlen( (&operation->site->questions[q])->keyword )) ||
|
||||||
if ((!keyContext && !strlen( question->keyword )) ||
|
(operation->keyContext && strcmp( (&operation->site->questions[q])->keyword, operation->keyContext ) != 0))
|
||||||
(keyContext && strcmp( keyContext, question->keyword ) != 0))
|
operation->question = &operation->site->questions[q];
|
||||||
// Found.
|
|
||||||
break;
|
|
||||||
question = NULL;
|
|
||||||
}
|
|
||||||
if (!question)
|
|
||||||
question = mpw_marshal_question( site, keyContext );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize purpose-specific operation parameters.
|
// If no question from mpsites, create a new one.
|
||||||
MPResultType resultType = MPResultTypeDefault;
|
if (!operation->question)
|
||||||
MPCounterValue siteCounter = MPCounterValueDefault;
|
operation->question = mpw_marshal_question( operation->site, operation->keyContext );
|
||||||
const char *purposeResult = NULL, *resultState = NULL;
|
break;
|
||||||
switch (keyPurpose) {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cli_operation(Arguments __unused *args, Operation *operation) {
|
||||||
|
|
||||||
|
switch (operation->keyPurpose) {
|
||||||
case MPKeyPurposeAuthentication: {
|
case MPKeyPurposeAuthentication: {
|
||||||
purposeResult = "password";
|
operation->purposeResult = "password";
|
||||||
resultType = site->type;
|
operation->resultType = operation->site->type;
|
||||||
resultState = site->content? strdup( site->content ): NULL;
|
operation->resultState = operation->site->content? strdup( operation->site->content ): NULL;
|
||||||
siteCounter = site->counter;
|
operation->siteCounter = operation->site->counter;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MPKeyPurposeIdentification: {
|
case MPKeyPurposeIdentification: {
|
||||||
purposeResult = "login";
|
operation->purposeResult = "login";
|
||||||
resultType = site->loginType;
|
operation->resultType = operation->site->loginType;
|
||||||
resultState = site->loginContent? strdup( site->loginContent ): NULL;
|
operation->resultState = operation->site->loginContent? strdup( operation->site->loginContent ): NULL;
|
||||||
siteCounter = MPCounterValueInitial;
|
operation->siteCounter = MPCounterValueInitial;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MPKeyPurposeRecovery: {
|
case MPKeyPurposeRecovery: {
|
||||||
mpw_free_string( &keyContext );
|
mpw_free_string( &operation->keyContext );
|
||||||
purposeResult = "answer";
|
operation->purposeResult = "answer";
|
||||||
keyContext = question->keyword? strdup( question->keyword ): NULL;
|
operation->keyContext = operation->question->keyword? strdup( operation->question->keyword ): NULL;
|
||||||
resultType = question->type;
|
operation->resultType = operation->question->type;
|
||||||
resultState = question->content? strdup( question->content ): NULL;
|
operation->resultState = operation->question->content? strdup( operation->question->content ): NULL;
|
||||||
siteCounter = MPCounterValueInitial;
|
operation->siteCounter = MPCounterValueInitial;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Override operation parameters from command-line arguments.
|
void cli_resultType(Arguments *args, Operation *operation) {
|
||||||
if (resultTypeArg) {
|
|
||||||
resultType = mpw_typeWithName( resultTypeArg );
|
if (args->resultType) {
|
||||||
if (ERR == (int)resultType) {
|
operation->resultType = mpw_typeWithName( args->resultType );
|
||||||
ftl( "Invalid type: %s\n", resultTypeArg );
|
if (ERR == (int)operation->resultType) {
|
||||||
mpw_marshal_free( &user );
|
ftl( "Invalid type: %s\n", args->resultType );
|
||||||
mpw_free_strings( &sitesPath, &resultState, &keyContext, NULL );
|
cli_free( args, operation );
|
||||||
return EX_USAGE;
|
exit( EX_USAGE );
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(resultType & MPSiteFeatureAlternative)) {
|
if (!(operation->resultType & MPSiteFeatureAlternative)) {
|
||||||
switch (keyPurpose) {
|
switch (operation->keyPurpose) {
|
||||||
case MPKeyPurposeAuthentication:
|
case MPKeyPurposeAuthentication:
|
||||||
site->type = resultType;
|
operation->site->type = operation->resultType;
|
||||||
break;
|
break;
|
||||||
case MPKeyPurposeIdentification:
|
case MPKeyPurposeIdentification:
|
||||||
site->loginType = resultType;
|
operation->site->loginType = operation->resultType;
|
||||||
break;
|
break;
|
||||||
case MPKeyPurposeRecovery:
|
case MPKeyPurposeRecovery:
|
||||||
question->type = resultType;
|
operation->question->type = operation->resultType;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (siteCounterArg) {
|
}
|
||||||
long long int siteCounterInt = atoll( siteCounterArg );
|
|
||||||
|
void cli_siteCounter(Arguments *args, Operation *operation) {
|
||||||
|
|
||||||
|
if (args->siteCounter) {
|
||||||
|
long long int siteCounterInt = atoll( args->siteCounter );
|
||||||
if (siteCounterInt < MPCounterValueFirst || siteCounterInt > MPCounterValueLast) {
|
if (siteCounterInt < MPCounterValueFirst || siteCounterInt > MPCounterValueLast) {
|
||||||
ftl( "Invalid site counter: %s\n", siteCounterArg );
|
ftl( "Invalid site counter: %s\n", args->siteCounter );
|
||||||
mpw_marshal_free( &user );
|
cli_free( args, operation );
|
||||||
mpw_free_strings( &sitesPath, &resultState, &keyContext, NULL );
|
exit( EX_USAGE );
|
||||||
return EX_USAGE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (keyPurpose) {
|
switch (operation->keyPurpose) {
|
||||||
case MPKeyPurposeAuthentication:
|
case MPKeyPurposeAuthentication:
|
||||||
siteCounter = site->counter = (MPCounterValue)siteCounterInt;
|
operation->siteCounter = operation->site->counter = (MPCounterValue)siteCounterInt;
|
||||||
break;
|
break;
|
||||||
case MPKeyPurposeIdentification:
|
case MPKeyPurposeIdentification:
|
||||||
case MPKeyPurposeRecovery:
|
case MPKeyPurposeRecovery:
|
||||||
@ -430,143 +598,123 @@ int main(const int argc, char *const argv[]) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const char *resultParam = NULL;
|
}
|
||||||
if (resultParamArg)
|
|
||||||
resultParam = strdup( resultParamArg );
|
void cli_resultParam(Arguments *args, Operation *operation) {
|
||||||
if (algorithmVersionArg) {
|
|
||||||
int algorithmVersionInt = atoi( algorithmVersionArg );
|
if (args->resultParam)
|
||||||
|
operation->resultParam = strdup( args->resultParam );
|
||||||
|
}
|
||||||
|
|
||||||
|
void cli_algorithmVersion(Arguments *args, Operation *operation) {
|
||||||
|
|
||||||
|
if (args->algorithmVersion) {
|
||||||
|
int algorithmVersionInt = atoi( args->algorithmVersion );
|
||||||
if (algorithmVersionInt < MPAlgorithmVersionFirst || algorithmVersionInt > MPAlgorithmVersionLast) {
|
if (algorithmVersionInt < MPAlgorithmVersionFirst || algorithmVersionInt > MPAlgorithmVersionLast) {
|
||||||
ftl( "Invalid algorithm version: %s\n", algorithmVersionArg );
|
ftl( "Invalid algorithm version: %s\n", args->algorithmVersion );
|
||||||
mpw_marshal_free( &user );
|
cli_free( args, operation );
|
||||||
mpw_free_strings( &sitesPath, &resultState, &keyContext, &resultParam, NULL );
|
exit( EX_USAGE );
|
||||||
return EX_USAGE;
|
|
||||||
}
|
}
|
||||||
site->algorithm = (MPAlgorithmVersion)algorithmVersionInt;
|
operation->site->algorithm = (MPAlgorithmVersion)algorithmVersionInt;
|
||||||
}
|
}
|
||||||
if (sitesRedactedArg)
|
}
|
||||||
user->redacted = strcmp( sitesRedactedArg, "1" ) == 0;
|
|
||||||
else if (!user->redacted)
|
void cli_sitesRedacted(Arguments *args, Operation *operation) {
|
||||||
|
|
||||||
|
if (args->sitesRedacted)
|
||||||
|
operation->user->redacted = strcmp( args->sitesRedacted, "1" ) == 0;
|
||||||
|
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" );
|
||||||
mpw_free_strings( &fullNameArg, &masterPasswordArg, &siteNameArg, NULL );
|
}
|
||||||
mpw_free_strings( &resultTypeArg, &resultParamArg, &siteCounterArg, &algorithmVersionArg, NULL );
|
|
||||||
mpw_free_strings( &keyPurposeArg, &keyContextArg, &sitesFormatArg, &sitesRedactedArg, NULL );
|
|
||||||
|
|
||||||
// Operation summary.
|
|
||||||
const char *identicon = mpw_identicon( user->fullName, user->masterPassword );
|
|
||||||
if (!identicon)
|
|
||||||
wrn( "Couldn't determine identicon.\n" );
|
|
||||||
dbg( "-----------------\n" );
|
|
||||||
dbg( "fullName : %s\n", user->fullName );
|
|
||||||
trc( "masterPassword : %s\n", user->masterPassword );
|
|
||||||
dbg( "identicon : %s\n", identicon );
|
|
||||||
dbg( "sitesFormat : %s%s\n", mpw_nameForFormat( sitesFormat ), sitesFormatFixed? " (fixed)": "" );
|
|
||||||
dbg( "sitesPath : %s\n", sitesPath );
|
|
||||||
dbg( "siteName : %s\n", site->name );
|
|
||||||
dbg( "siteCounter : %u\n", siteCounter );
|
|
||||||
dbg( "resultType : %s (%u)\n", mpw_nameForType( resultType ), resultType );
|
|
||||||
dbg( "resultParam : %s\n", resultParam );
|
|
||||||
dbg( "keyPurpose : %s (%u)\n", mpw_nameForPurpose( keyPurpose ), keyPurpose );
|
|
||||||
dbg( "keyContext : %s\n", keyContext );
|
|
||||||
dbg( "algorithmVersion : %u\n", site->algorithm );
|
|
||||||
dbg( "-----------------\n\n" );
|
|
||||||
inf( "%s's %s for %s:\n[ %s ]: ", user->fullName, purposeResult, site->name, identicon );
|
|
||||||
mpw_free_strings( &identicon, &sitesPath, NULL );
|
|
||||||
|
|
||||||
|
void cli_mpw(Arguments *args, Operation *operation) {
|
||||||
// Determine master key.
|
// Determine master key.
|
||||||
MPMasterKey masterKey = mpw_masterKey(
|
MPMasterKey masterKey = mpw_masterKey(
|
||||||
user->fullName, user->masterPassword, site->algorithm );
|
operation->user->fullName, operation->user->masterPassword, operation->site->algorithm );
|
||||||
if (!masterKey) {
|
if (!masterKey) {
|
||||||
ftl( "Couldn't derive master key.\n" );
|
ftl( "Couldn't derive master key.\n" );
|
||||||
mpw_marshal_free( &user );
|
cli_free( args, operation );
|
||||||
mpw_free_strings( &resultState, &keyContext, &resultParam, NULL );
|
exit( EX_SOFTWARE );
|
||||||
return EX_SOFTWARE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update state.
|
// Update state from resultParam if stateful.
|
||||||
if (resultParam && resultType & MPResultTypeClassStateful) {
|
if (operation->resultParam && operation->resultType & MPResultTypeClassStateful) {
|
||||||
mpw_free_string( &resultState );
|
mpw_free_string( &operation->resultState );
|
||||||
if (!(resultState = mpw_siteState( masterKey, site->name, siteCounter,
|
if (!(operation->resultState = mpw_siteState( masterKey, operation->site->name, operation->siteCounter,
|
||||||
keyPurpose, keyContext, resultType, resultParam, 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 );
|
||||||
mpw_marshal_free( &user );
|
cli_free( args, operation );
|
||||||
mpw_free_strings( &resultState, &keyContext, &resultParam, NULL );
|
exit( EX_SOFTWARE );
|
||||||
return EX_SOFTWARE;
|
|
||||||
}
|
}
|
||||||
inf( "(state) %s => ", resultState );
|
inf( "(state) %s => ", operation->resultState );
|
||||||
|
|
||||||
switch (keyPurpose) {
|
switch (operation->keyPurpose) {
|
||||||
case MPKeyPurposeAuthentication: {
|
case MPKeyPurposeAuthentication: {
|
||||||
mpw_free_string( &site->content );
|
mpw_free_string( &operation->site->content );
|
||||||
site->content = strdup( resultState );
|
operation->site->content = strdup( operation->resultState );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MPKeyPurposeIdentification: {
|
case MPKeyPurposeIdentification: {
|
||||||
mpw_free_string( &site->loginContent );
|
mpw_free_string( &operation->site->loginContent );
|
||||||
site->loginContent = strdup( resultState );
|
operation->site->loginContent = strdup( operation->resultState );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case MPKeyPurposeRecovery: {
|
case MPKeyPurposeRecovery: {
|
||||||
mpw_free_string( &question->content );
|
mpw_free_string( &operation->question->content );
|
||||||
question->content = strdup( resultState );
|
operation->question->content = strdup( operation->resultState );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// resultParam is consumed.
|
// resultParam is consumed.
|
||||||
mpw_free_string( &resultParam );
|
mpw_free_string( &operation->resultParam );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Second phase resultParam defaults to state.
|
// resultParam defaults to state.
|
||||||
if (!resultParam && resultState)
|
if (!operation->resultParam && operation->resultState)
|
||||||
resultParam = strdup( resultState );
|
operation->resultParam = strdup( operation->resultState );
|
||||||
mpw_free_string( &resultState );
|
|
||||||
|
|
||||||
// Generate result.
|
// Generate result.
|
||||||
const char *result = mpw_siteResult( masterKey, site->name, siteCounter,
|
const char *result = mpw_siteResult( masterKey, operation->site->name, operation->siteCounter,
|
||||||
keyPurpose, keyContext, resultType, resultParam, site->algorithm );
|
operation->keyPurpose, operation->keyContext, operation->resultType, operation->resultParam, operation->site->algorithm );
|
||||||
mpw_free( &masterKey, MPMasterKeySize );
|
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_marshal_free( &user );
|
cli_free( args, operation );
|
||||||
return EX_SOFTWARE;
|
exit( EX_SOFTWARE );
|
||||||
}
|
}
|
||||||
fprintf( stdout, "%s\n", result );
|
fprintf( stdout, "%s\n", result );
|
||||||
if (site->url)
|
if (operation->site->url)
|
||||||
inf( "See: %s\n", site->url );
|
inf( "See: %s\n", operation->site->url );
|
||||||
mpw_free_string( &result );
|
mpw_free_string( &result );
|
||||||
|
}
|
||||||
|
|
||||||
// Update usage metadata.
|
void cli_save(Arguments __unused *args, Operation *operation) {
|
||||||
site->lastUsed = user->lastUsed = time( NULL );
|
|
||||||
site->uses++;
|
|
||||||
|
|
||||||
// Update the mpsites file.
|
if (operation->sitesFormat == MPMarshallFormatNone)
|
||||||
if (sitesFormat != MPMarshallFormatNone) {
|
return;
|
||||||
if (!sitesFormatFixed)
|
|
||||||
sitesFormat = MPMarshallFormatDefault;
|
|
||||||
sitesPath = mpw_path( user->fullName, mpw_marshall_format_extension( sitesFormat ) );
|
|
||||||
|
|
||||||
dbg( "Updating: %s (%s)\n", sitesPath, mpw_nameForFormat( sitesFormat ) );
|
if (!operation->sitesFormatFixed)
|
||||||
if (!sitesPath || !mpw_mkdirs( sitesPath ) || !(sitesFile = fopen( sitesPath, "w" )))
|
operation->sitesFormat = MPMarshallFormatDefault;
|
||||||
wrn( "Couldn't create updated configuration file:\n %s: %s\n", sitesPath, strerror( errno ) );
|
operation->sitesPath = mpw_path( operation->user->fullName, mpw_marshall_format_extension( operation->sitesFormat ) );
|
||||||
|
dbg( "Updating: %s (%s)\n", operation->sitesPath, mpw_nameForFormat( operation->sitesFormat ) );
|
||||||
|
|
||||||
|
FILE *sitesFile = NULL;
|
||||||
|
if (!operation->sitesPath || !mpw_mkdirs( operation->sitesPath ) || !(sitesFile = fopen( operation->sitesPath, "w" ))) {
|
||||||
|
wrn( "Couldn't create updated configuration file:\n %s: %s\n", operation->sitesPath, strerror( errno ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
else {
|
|
||||||
char *buf = NULL;
|
char *buf = NULL;
|
||||||
MPMarshallError marshallError = { .type = MPMarshallSuccess };
|
MPMarshallError marshallError = { .type = MPMarshallSuccess };
|
||||||
if (!mpw_marshall_write( &buf, sitesFormat, user, &marshallError ) || marshallError.type != MPMarshallSuccess)
|
if (!mpw_marshall_write( &buf, operation->sitesFormat, operation->user, &marshallError ) || marshallError.type != MPMarshallSuccess)
|
||||||
wrn( "Couldn't encode updated configuration file:\n %s: %s\n", sitesPath, marshallError.description );
|
wrn( "Couldn't encode updated configuration file:\n %s: %s\n", operation->sitesPath, marshallError.description );
|
||||||
|
|
||||||
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", operation->sitesPath, ferror( sitesFile ) );
|
||||||
|
|
||||||
mpw_free_string( &buf );
|
mpw_free_string( &buf );
|
||||||
fclose( sitesFile );
|
fclose( sitesFile );
|
||||||
}
|
|
||||||
mpw_free_string( &sitesPath );
|
|
||||||
}
|
|
||||||
mpw_marshal_free( &user );
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user