Use the user, not a site algorithm, for generating and testing the keyID.
- Order of fall-back formats from most to least preferred. - The keyID should be based on the user algorithm, not the site algorithm. - Standardize mpw_format* function names.
This commit is contained in:
		@@ -48,13 +48,13 @@ static void usage() {
 | 
			
		||||
         "               -u checks the master password against the config,\n"
 | 
			
		||||
         "               -U allows updating to a new master password.\n"
 | 
			
		||||
         "               Defaults to %s in env or prompts.\n", MP_ENV_fullName );
 | 
			
		||||
    dbg( ""
 | 
			
		||||
         "  -M master-pw Specify the master password of the user.\n"
 | 
			
		||||
         "               Passing secrets as arguments is unsafe, for use in testing only." );
 | 
			
		||||
    inf( ""
 | 
			
		||||
         "  -m fd        Read the master password of the user from a file descriptor.\n"
 | 
			
		||||
         "               Tip: don't send extra characters like newlines such as by using\n"
 | 
			
		||||
         "               echo in a pipe.  Consider printf instead.\n" );
 | 
			
		||||
    dbg( ""
 | 
			
		||||
         "  -M master-pw Specify the master password of the user.\n"
 | 
			
		||||
         "               Passing secrets as arguments is unsafe, for use in testing only." );
 | 
			
		||||
    inf( ""
 | 
			
		||||
         "  -t pw-type   Specify the password's template.\n"
 | 
			
		||||
         "               Defaults to 'long' (-p a), 'name' (-p i) or 'phrase' (-p r).\n"
 | 
			
		||||
@@ -93,14 +93,15 @@ static void usage() {
 | 
			
		||||
         "                   -p i        | -\n"
 | 
			
		||||
         "                   -p r        | Most significant word in security question.\n" );
 | 
			
		||||
    inf( ""
 | 
			
		||||
         "  -f|F format  The mpsites format to use for reading/writing site parameters.\n"
 | 
			
		||||
         "               -F forces the use of the given format,\n"
 | 
			
		||||
         "               -f allows fallback/migration.\n"
 | 
			
		||||
         "               Defaults to env var %s or json, falls back to plain.\n"
 | 
			
		||||
         "  -f|F format  The file format to use for reading/writing user state.\n"
 | 
			
		||||
         "               -f reads the given format, allows fall-back & writes the default format (%s).\n"
 | 
			
		||||
         "               -F reads & writes only the given format,\n"
 | 
			
		||||
         "               Defaults to env var %s or the default format (%s).\n"
 | 
			
		||||
         "                   n, none     | No file\n"
 | 
			
		||||
         "                   f, flat     | ~/.mpw.d/Full Name.%s\n"
 | 
			
		||||
         "                   j, json     | ~/.mpw.d/Full Name.%s\n",
 | 
			
		||||
            MP_ENV_format, mpw_marshal_format_extension( MPMarshalFormatFlat ), mpw_marshal_format_extension( MPMarshalFormatJSON ) );
 | 
			
		||||
            mpw_format_name( MPMarshalFormatDefault ), MP_ENV_format, mpw_format_name( MPMarshalFormatDefault ),
 | 
			
		||||
            mpw_format_extension( MPMarshalFormatFlat ), mpw_format_extension( MPMarshalFormatJSON ) );
 | 
			
		||||
    inf( ""
 | 
			
		||||
         "  -R redacted  Whether to save the mpsites in redacted format or not.\n"
 | 
			
		||||
         "               Redaction omits or encrypts any secrets, making the file safe\n"
 | 
			
		||||
@@ -455,12 +456,10 @@ void cli_keyContext(Arguments *args, Operation *operation) {
 | 
			
		||||
    operation->keyContext = mpw_strdup( args->keyContext );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cli_user(Arguments *args, Operation *operation) {
 | 
			
		||||
 | 
			
		||||
    // Find mpsites file from parameters.
 | 
			
		||||
static FILE *cli_user_open(const MPMarshalFormat format, Operation *operation) {
 | 
			
		||||
    FILE *sitesFile = NULL;
 | 
			
		||||
    size_t count = 0;
 | 
			
		||||
    const char **extensions = mpw_marshal_format_extensions( operation->sitesFormat, &count );
 | 
			
		||||
    const char **extensions = mpw_format_extensions( format, &count );
 | 
			
		||||
    for (int e = 0; !sitesFile && e < count; ++e) {
 | 
			
		||||
        mpw_free_string( &operation->sitesPath );
 | 
			
		||||
        operation->sitesPath = mpw_path( operation->fullName, extensions[e] );
 | 
			
		||||
@@ -468,22 +467,19 @@ void cli_user(Arguments *args, Operation *operation) {
 | 
			
		||||
        if (!operation->sitesPath || !(sitesFile = fopen( operation->sitesPath, "r" )))
 | 
			
		||||
            dbg( "Couldn't open configuration file:\n  %s: %s", operation->sitesPath, strerror( errno ) );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!sitesFile && !operation->sitesFormatFixed)
 | 
			
		||||
        for (MPMarshalFormat format = MPMarshalFormatFirst; !sitesFile && format <= MPMarshalFormatLast; ++format) {
 | 
			
		||||
            mpw_free( &extensions, count * sizeof( *extensions ) );
 | 
			
		||||
            extensions = mpw_marshal_format_extensions( operation->sitesFormat, &count );
 | 
			
		||||
 | 
			
		||||
            for (int e = 0; !sitesFile && e < count; ++e) {
 | 
			
		||||
                mpw_free_string( &operation->sitesPath );
 | 
			
		||||
                operation->sitesPath = mpw_path( operation->fullName, extensions[e] );
 | 
			
		||||
 | 
			
		||||
                if (!operation->sitesPath || !(sitesFile = fopen( operation->sitesPath, "r" )))
 | 
			
		||||
                    dbg( "Couldn't open configuration file:\n  %s: %s", operation->sitesPath, strerror( errno ) );
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    mpw_free( &extensions, count * sizeof( *extensions ) );
 | 
			
		||||
 | 
			
		||||
    return sitesFile;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cli_user(Arguments *args, Operation *operation) {
 | 
			
		||||
 | 
			
		||||
    // Find mpsites file from parameters.
 | 
			
		||||
    FILE *sitesFile = cli_user_open( operation->sitesFormat, operation );
 | 
			
		||||
    if (!sitesFile && !operation->sitesFormatFixed)
 | 
			
		||||
        for (MPMarshalFormat format = MPMarshalFormatLast; !sitesFile && format >= MPMarshalFormatFirst; --format)
 | 
			
		||||
            sitesFile = cli_user_open( format, operation );
 | 
			
		||||
 | 
			
		||||
    if (!sitesFile) {
 | 
			
		||||
        // If no user from mpsites, create a new one.
 | 
			
		||||
        mpw_free_string( &operation->sitesPath );
 | 
			
		||||
@@ -721,10 +717,10 @@ void cli_mpw(Arguments *args, Operation *operation) {
 | 
			
		||||
        fprintf( stderr, "%s's %s for %s:\n[ %s ]: ",
 | 
			
		||||
                operation->user->fullName, operation->purposeResult, operation->site->siteName, operation->identicon );
 | 
			
		||||
 | 
			
		||||
    // Determine master key.
 | 
			
		||||
    // Check user keyID.
 | 
			
		||||
    MPMasterKey masterKey = NULL;
 | 
			
		||||
    if (operation->user->masterKeyProvider)
 | 
			
		||||
        masterKey = operation->user->masterKeyProvider( operation->site->algorithm, operation->user->fullName );
 | 
			
		||||
        masterKey = operation->user->masterKeyProvider( operation->user->algorithm, operation->user->fullName );
 | 
			
		||||
    if (!masterKey) {
 | 
			
		||||
        ftl( "Couldn't derive master key." );
 | 
			
		||||
        cli_free( args, operation );
 | 
			
		||||
@@ -735,6 +731,17 @@ void cli_mpw(Arguments *args, Operation *operation) {
 | 
			
		||||
        operation->user->keyID = mpw_strdup( keyID );
 | 
			
		||||
    else if (!mpw_id_buf_equals( keyID, operation->user->keyID )) {
 | 
			
		||||
        ftl( "Master key mismatch." );
 | 
			
		||||
        mpw_free( &masterKey, MPMasterKeySize );
 | 
			
		||||
        cli_free( args, operation );
 | 
			
		||||
        exit( EX_SOFTWARE );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Resolve master key for site.
 | 
			
		||||
    mpw_free( &masterKey, MPMasterKeySize );
 | 
			
		||||
    if (operation->user->masterKeyProvider)
 | 
			
		||||
        masterKey = operation->user->masterKeyProvider( operation->site->algorithm, operation->user->fullName );
 | 
			
		||||
    if (!masterKey) {
 | 
			
		||||
        ftl( "Couldn't derive master key." );
 | 
			
		||||
        cli_free( args, operation );
 | 
			
		||||
        exit( EX_SOFTWARE );
 | 
			
		||||
    }
 | 
			
		||||
@@ -808,7 +815,7 @@ void cli_save(Arguments *args, Operation *operation) {
 | 
			
		||||
        operation->sitesFormat = MPMarshalFormatDefault;
 | 
			
		||||
 | 
			
		||||
    size_t count = 0;
 | 
			
		||||
    const char **extensions = mpw_marshal_format_extensions( operation->sitesFormat, &count );
 | 
			
		||||
    const char **extensions = mpw_format_extensions( operation->sitesFormat, &count );
 | 
			
		||||
    if (!extensions || !count)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1319,7 +1319,7 @@ const char *mpw_format_name(
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *mpw_marshal_format_extension(
 | 
			
		||||
const char *mpw_format_extension(
 | 
			
		||||
        const MPMarshalFormat format) {
 | 
			
		||||
 | 
			
		||||
    switch (format) {
 | 
			
		||||
@@ -1336,7 +1336,7 @@ const char *mpw_marshal_format_extension(
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char **mpw_marshal_format_extensions(
 | 
			
		||||
const char **mpw_format_extensions(
 | 
			
		||||
        const MPMarshalFormat format, size_t *count) {
 | 
			
		||||
 | 
			
		||||
    *count = 0;
 | 
			
		||||
@@ -1345,10 +1345,10 @@ const char **mpw_marshal_format_extensions(
 | 
			
		||||
            return NULL;
 | 
			
		||||
        case MPMarshalFormatFlat:
 | 
			
		||||
            return mpw_strings( count,
 | 
			
		||||
                    mpw_marshal_format_extension( format ), "mpsites.txt", "txt", NULL );
 | 
			
		||||
                    mpw_format_extension( format ), "mpsites.txt", "txt", NULL );
 | 
			
		||||
        case MPMarshalFormatJSON:
 | 
			
		||||
            return mpw_strings( count,
 | 
			
		||||
                    mpw_marshal_format_extension( format ), "mpsites.json", "json", NULL );
 | 
			
		||||
                    mpw_format_extension( format ), "mpsites.json", "json", NULL );
 | 
			
		||||
        default: {
 | 
			
		||||
            dbg( "Unknown format: %d", format );
 | 
			
		||||
            return NULL;
 | 
			
		||||
 
 | 
			
		||||
@@ -62,14 +62,27 @@ typedef mpw_enum( unsigned int, MPMarshalErrorType ) {
 | 
			
		||||
            MPMarshalErrorInternal,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef MPMasterKey (*MPMasterKeyProvider)(MPAlgorithmVersion algorithm, const char *fullName);
 | 
			
		||||
typedef bool (*MPMasterKeyProviderProxy)(MPMasterKey *, MPAlgorithmVersion *, MPAlgorithmVersion algorithm, const char *fullName);
 | 
			
		||||
/** A function that can resolve a master key of the given algorithm for the user with the given name.
 | 
			
		||||
 * @return A master key (allocated), or NULL if the key could not be resolved. */
 | 
			
		||||
typedef MPMasterKey (*MPMasterKeyProvider)(
 | 
			
		||||
        MPAlgorithmVersion algorithm, const char *fullName);
 | 
			
		||||
/** A function that updates the currentKey with the masterKey of the given algorithm for the user with the given name.
 | 
			
		||||
 * @param currentKey A pointer to where the current masterKey (allocated) can be found and a new one can be placed.  Must be freed if updated.
 | 
			
		||||
 * @param currentAlgorithm A pointer to where the algorithm of the current masterKey is found and can be updated.
 | 
			
		||||
 * @param algorithm The algorithm of the masterKey that should be placed in currentKey.
 | 
			
		||||
 * @param fullName The name of the user whose masterKey should be placed in currentKey.
 | 
			
		||||
 * @return false if not able to resolve the requested masterKey. */
 | 
			
		||||
typedef bool (*MPMasterKeyProviderProxy)(
 | 
			
		||||
        MPMasterKey *currentKey, MPAlgorithmVersion *currentAlgorithm, MPAlgorithmVersion algorithm, const char *fullName);
 | 
			
		||||
 | 
			
		||||
/** Create a key provider which handles key generation by proxying the given function.
 | 
			
		||||
 * The proxy function receives the currently cached key and its algorithm.  If those are NULL, the proxy function should clean up its state. */
 | 
			
		||||
MPMasterKeyProvider mpw_masterKeyProvider_proxy(const MPMasterKeyProviderProxy proxy);
 | 
			
		||||
MPMasterKeyProvider mpw_masterKeyProvider_proxy(
 | 
			
		||||
        const MPMasterKeyProviderProxy proxy);
 | 
			
		||||
/** Create a key provider that computes a master key for the given master password. */
 | 
			
		||||
MPMasterKeyProvider mpw_masterKeyProvider_str(const char *masterPassword);
 | 
			
		||||
MPMasterKeyProvider mpw_masterKeyProvider_str(
 | 
			
		||||
        const char *masterPassword);
 | 
			
		||||
 | 
			
		||||
/** Free the cached keys and proxy state. */
 | 
			
		||||
void mpw_masterKeyProvider_free(void);
 | 
			
		||||
 | 
			
		||||
@@ -329,14 +342,14 @@ const char *mpw_format_name(
 | 
			
		||||
 * @return The file extension (static) that's recommended and currently used for output files,
 | 
			
		||||
 *         or NULL if the format was not recognized or does not support marshalling.
 | 
			
		||||
 */
 | 
			
		||||
const char *mpw_marshal_format_extension(
 | 
			
		||||
const char *mpw_format_extension(
 | 
			
		||||
        const MPMarshalFormat format);
 | 
			
		||||
/**
 | 
			
		||||
 * @return An array (allocated, count) of filename extensions (static) that are used for files of this format,
 | 
			
		||||
 *         the first being the currently preferred/output extension.
 | 
			
		||||
 *         NULL if the format is unrecognized or does not support marshalling.
 | 
			
		||||
 */
 | 
			
		||||
const char **mpw_marshal_format_extensions(
 | 
			
		||||
const char **mpw_format_extensions(
 | 
			
		||||
        const MPMarshalFormat format, size_t *count);
 | 
			
		||||
 | 
			
		||||
#endif // _MPW_MARSHAL_H
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user