2
0

Support for reading master password from an FD.

This commit is contained in:
Maarten Billemont 2017-08-30 19:04:22 -04:00
parent 17de69834e
commit 8562338b62

View File

@ -28,20 +28,25 @@ static void usage() {
inf( "" inf( ""
" Master Password v%s\n" " Master Password v%s\n"
" https://masterpasswordapp.com\n\n", stringify_def( MP_VERSION ) ); "--------------------------------------------------------------------------------\n"
" https://masterpasswordapp.com\n\n", stringify_def( MP_VERSION ) );
inf( "" inf( ""
"Usage:\n" "USAGE\n"
" mpw [-u|-U full-name] [-t pw-type] [-c counter] [-a algorithm] [-s value]\n" " mpw [-u|-U full-name] [-m fd] [-t pw-type] [-P value] [-c counter]\n"
" [-p purpose] [-C context] [-f|-F format] [-R 0|1] [-v|-q] [-h] site-name\n\n" ); " [-a version] [-p purpose] [-C context] [-f|-F format] [-R 0|1]\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"
" -U allows updating to a new master password.\n" " -U allows updating to a new master password.\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 );
trc( "" dbg( ""
" -M master-pw Specify the master password of the user.\n" " -M master-pw Specify the master password of the user.\n"
" This is not a safe method of passing the master password,\n" " Passing secrets as arguments is unsafe, for use in testing only.\n" );
" only use it for non-secret passwords, such as for tests.\n\n" ); 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\n" );
inf( "" inf( ""
" -t pw-type Specify the password's template.\n" " -t pw-type Specify the password's template.\n"
" Defaults to 'long' (-p a), 'name' (-p i) or 'phrase' (-p r).\n" " Defaults to 'long' (-p a), 'name' (-p i) or 'phrase' (-p r).\n"
@ -58,7 +63,7 @@ static void usage() {
inf( "" inf( ""
" -P value The parameter value.\n" " -P value The parameter value.\n"
" -p i | The login name for the site.\n" " -p i | The login name for the site.\n"
" -t K | The size of they key to generate, in bits (eg. 256).\n" " -t K | The bit size of the key to generate (eg. 256).\n"
" -t P | The personal password to encrypt.\n\n" ); " -t P | The personal password to encrypt.\n\n" );
inf( "" inf( ""
" -c counter The value of the counter.\n" " -c counter The value of the counter.\n"
@ -95,10 +100,11 @@ static void usage() {
" -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( "" inf( ""
" ENVIRONMENT\n\n" "ENVIRONMENT\n\n"
" %-14s | The full name of the user (see -u).\n" " %-12s The full name of the user (see -u).\n"
" %-14s | The default algorithm version (see -a).\n\n", " %-12s The default algorithm version (see -a).\n"
MP_ENV_fullName, MP_ENV_algorithm ); " %-12s The default mpsites format (see -f).\n\n",
MP_ENV_fullName, MP_ENV_algorithm, MP_ENV_format );
exit( 0 ); exit( 0 );
} }
@ -210,13 +216,24 @@ static bool mpw_mkdirs(const char *filePath) {
return success; return success;
} }
static char *mpw_read_file(FILE *file) {
char *buf = NULL;
size_t blockSize = 4096, bufSize = 0, bufOffset = 0, readSize = 0;
while ((mpw_realloc( &buf, &bufSize, blockSize )) &&
(bufOffset += (readSize = fread( buf + bufOffset, 1, blockSize, file ))) &&
(readSize == blockSize));
return buf;
}
int main(const int argc, char *const argv[]) { int main(const int argc, char *const argv[]) {
// CLI defaults. // CLI defaults.
bool allowPasswordUpdate = false, sitesFormatFixed = false; bool allowPasswordUpdate = false, sitesFormatFixed = false;
// Read the environment. // Read the environment.
const char *fullNameArg = NULL, *masterPasswordArg = NULL, *siteNameArg = NULL; const char *fullNameArg = NULL, *masterPasswordFDArg = NULL, *masterPasswordArg = NULL, *siteNameArg = NULL;
const char *resultTypeArg = NULL, *resultParamArg = NULL, *siteCounterArg = NULL, *algorithmVersionArg = NULL; const char *resultTypeArg = NULL, *resultParamArg = NULL, *siteCounterArg = NULL, *algorithmVersionArg = NULL;
const char *keyPurposeArg = NULL, *keyContextArg = NULL, *sitesFormatArg = NULL, *sitesRedactedArg = NULL; const char *keyPurposeArg = NULL, *keyContextArg = NULL, *sitesFormatArg = NULL, *sitesRedactedArg = NULL;
fullNameArg = mpw_getenv( MP_ENV_fullName ); fullNameArg = mpw_getenv( MP_ENV_fullName );
@ -224,7 +241,7 @@ int main(const int argc, char *const argv[]) {
sitesFormatArg = mpw_getenv( MP_ENV_format ); sitesFormatArg = mpw_getenv( MP_ENV_format );
// Read the command-line options. // Read the command-line options.
for (int opt; (opt = getopt( argc, argv, "u:U:M:t:P:c:a:p:C:f:F:R:vqh" )) != EOF;) for (int opt; (opt = getopt( argc, argv, "u:U:m:M:t:P:c:a:p:C:f:F:R:vqh" )) != EOF;)
switch (opt) { switch (opt) {
case 'u': case 'u':
fullNameArg = optarg && strlen( optarg )? strdup( optarg ): NULL; fullNameArg = optarg && strlen( optarg )? strdup( optarg ): NULL;
@ -234,6 +251,9 @@ int main(const int argc, char *const argv[]) {
fullNameArg = optarg && strlen( optarg )? strdup( optarg ): NULL; fullNameArg = optarg && strlen( optarg )? strdup( optarg ): NULL;
allowPasswordUpdate = true; allowPasswordUpdate = true;
break; break;
case 'm':
masterPasswordFDArg = optarg && strlen( optarg )? strdup( optarg ): NULL;
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; masterPasswordArg = optarg && strlen( optarg )? strdup( optarg ): NULL;
@ -300,21 +320,28 @@ int main(const int argc, char *const argv[]) {
// Determine fullName, siteName & masterPassword. // Determine fullName, siteName & masterPassword.
const char *fullName = NULL, *masterPassword = NULL, *siteName = NULL; const char *fullName = NULL, *masterPassword = NULL, *siteName = NULL;
if (!(fullNameArg && (fullName = strdup( fullNameArg ))) && if ((!fullName || !strlen( fullName )) && fullNameArg)
!(fullName = mpw_getline( "Your full name:" ))) { fullName = strdup( fullNameArg );
ftl( "Missing full name.\n" ); while (!fullName || !strlen( fullName ))
mpw_free_strings( &fullName, &masterPassword, &siteName, NULL ); fullName = mpw_getline( "Your full name:" );
return EX_DATAERR; if ((!masterPassword || !strlen( masterPassword )) && masterPasswordFDArg) {
} FILE *masterPasswordFile = fdopen( atoi( masterPasswordFDArg ), "r" );
if (!(masterPasswordArg && (masterPassword = strdup( masterPasswordArg )))) if (!masterPasswordFile)
while (!masterPassword || !strlen( masterPassword )) wrn( "Error opening master password FD %s: %s\n", masterPasswordFDArg, strerror( errno ) );
masterPassword = mpw_getpass( "Your master password: " ); else {
if (!(siteNameArg && (siteName = strdup( siteNameArg ))) && masterPassword = mpw_read_file( masterPasswordFile );
!(siteName = mpw_getline( "Site name:" ))) { if (ferror( masterPasswordFile ))
ftl( "Missing site name.\n" ); wrn( "Error reading master password from %s: %d\n", masterPasswordFDArg, ferror( masterPasswordFile ) );
mpw_free_strings( &fullName, &masterPassword, &siteName, NULL ); }
return EX_DATAERR;
} }
if ((!masterPassword || !strlen( masterPassword )) && masterPasswordArg)
masterPassword = strdup( masterPasswordArg );
while (!masterPassword || !strlen( masterPassword ))
masterPassword = mpw_getpass( "Your master password: " );
if ((!siteName || !strlen( siteName )) && siteNameArg)
siteName = strdup( siteNameArg );
while (!siteName || !strlen( siteName ))
siteName = mpw_getline( "Site name:" );
MPMarshallFormat sitesFormat = MPMarshallFormatDefault; MPMarshallFormat sitesFormat = MPMarshallFormatDefault;
if (sitesFormatArg) { if (sitesFormatArg) {
sitesFormat = mpw_formatWithName( sitesFormatArg ); sitesFormat = mpw_formatWithName( sitesFormatArg );
@ -362,11 +389,7 @@ int main(const int argc, char *const argv[]) {
else { else {
// Read file. // Read file.
size_t blockSize = 4096, bufSize = 0, bufOffset = 0, readSize = 0; char *sitesInputData = mpw_read_file( sitesFile );
char *sitesInputData = NULL;
while ((mpw_realloc( &sitesInputData, &bufSize, blockSize )) &&
(bufOffset += (readSize = fread( sitesInputData + bufOffset, 1, blockSize, sitesFile ))) &&
(readSize == blockSize));
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", sitesPath, ferror( sitesFile ) );
fclose( sitesFile ); fclose( sitesFile );
@ -382,8 +405,7 @@ int main(const int argc, char *const argv[]) {
if (!allowPasswordUpdate) { if (!allowPasswordUpdate) {
ftl( "Incorrect master password according to configuration:\n %s: %s\n", sitesPath, marshallError.description ); ftl( "Incorrect master password according to configuration:\n %s: %s\n", sitesPath, marshallError.description );
mpw_marshal_free( &user ); mpw_marshal_free( &user );
mpw_free( &sitesInputData, bufSize ); mpw_free_strings( &sitesInputData, &sitesPath, &fullName, &masterPassword, &siteName, NULL );
mpw_free_strings( &sitesPath, &fullName, &masterPassword, &siteName, NULL );
return EX_DATAERR; return EX_DATAERR;
} }
@ -405,7 +427,8 @@ int main(const int argc, char *const argv[]) {
user->masterPassword = strdup( masterPassword ); user->masterPassword = strdup( masterPassword );
} }
} }
mpw_free( &sitesInputData, bufSize ); mpw_free_string( &sitesInputData );
if (!user || marshallError.type != MPMarshallSuccess) { if (!user || marshallError.type != MPMarshallSuccess) {
err( "Couldn't parse configuration file:\n %s: %s\n", sitesPath, marshallError.description ); err( "Couldn't parse configuration file:\n %s: %s\n", sitesPath, marshallError.description );
mpw_marshal_free( &user ); mpw_marshal_free( &user );