2014-12-20 04:15:32 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <pwd.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
#if defined(READLINE)
|
|
|
|
#include <readline/readline.h>
|
|
|
|
#elif defined(EDITLINE)
|
|
|
|
#include <histedit.h>
|
|
|
|
#endif
|
|
|
|
|
2014-12-20 19:30:34 +00:00
|
|
|
#include "mpw-algorithm.h"
|
|
|
|
#include "mpw-util.h"
|
2017-07-16 01:13:49 +00:00
|
|
|
#include "mpw-marshall.h"
|
2014-12-20 19:30:34 +00:00
|
|
|
|
2017-07-16 01:13:49 +00:00
|
|
|
#define MP_env_fullName "MP_FULLNAME"
|
2015-01-17 16:17:16 +00:00
|
|
|
#define MP_env_algorithm "MP_ALGORITHM"
|
2014-12-20 04:15:32 +00:00
|
|
|
|
|
|
|
static void usage() {
|
|
|
|
|
2017-07-16 01:13:49 +00:00
|
|
|
inf( ""
|
2017-08-01 17:45:54 +00:00
|
|
|
"Usage: mpw [-u name] [-t type] [-c counter] [-a algorithm] [-p purpose] [-C context] [-v|-q] [-h] site\n\n" );
|
2017-07-16 01:13:49 +00:00
|
|
|
inf( ""
|
|
|
|
" -u name Specify the full name of the user.\n"
|
|
|
|
" Defaults to %s in env or prompts.\n\n", MP_env_fullName );
|
|
|
|
inf( ""
|
|
|
|
" -t type Specify the password's template.\n"
|
2017-08-01 17:45:54 +00:00
|
|
|
" Defaults to 'long' for auth, 'name' for ident and 'phrase' for recovery.\n"
|
2014-12-20 04:15:32 +00:00
|
|
|
" x, max, maximum | 20 characters, contains symbols.\n"
|
|
|
|
" l, long | Copy-friendly, 14 characters, contains symbols.\n"
|
|
|
|
" m, med, medium | Copy-friendly, 8 characters, contains symbols.\n"
|
|
|
|
" b, basic | 8 characters, no symbols.\n"
|
|
|
|
" s, short | Copy-friendly, 4 characters, no symbols.\n"
|
|
|
|
" i, pin | 4 numbers.\n"
|
|
|
|
" n, name | 9 letter name.\n"
|
2017-08-01 17:45:54 +00:00
|
|
|
" p, phrase | 20 character sentence.\n\n" );
|
2017-07-16 01:13:49 +00:00
|
|
|
inf( ""
|
|
|
|
" -c counter The value of the counter.\n"
|
2017-08-01 17:45:54 +00:00
|
|
|
" Defaults to 1.\n\n" );
|
2017-07-16 01:13:49 +00:00
|
|
|
inf( ""
|
|
|
|
" -a version The algorithm version to use.\n"
|
2015-01-17 16:17:16 +00:00
|
|
|
" Defaults to %s in env or %d.\n\n", MP_env_algorithm, MPAlgorithmVersionCurrent );
|
2017-07-16 01:13:49 +00:00
|
|
|
inf( ""
|
2017-08-01 17:45:54 +00:00
|
|
|
" -p purpose The purpose of the generated token.\n"
|
2014-12-20 04:15:32 +00:00
|
|
|
" Defaults to 'password'.\n"
|
2017-08-01 17:45:54 +00:00
|
|
|
" a, auth | An authentication token such as a password.\n"
|
|
|
|
" i, ident | An identification token such as a username.\n"
|
|
|
|
" r, rec | A recovery token such as a security answer.\n\n" );
|
2017-07-16 01:13:49 +00:00
|
|
|
inf( ""
|
2017-08-01 17:45:54 +00:00
|
|
|
" -C context A purpose-specific context.\n"
|
2014-12-20 04:15:32 +00:00
|
|
|
" Defaults to empty.\n"
|
2017-08-01 17:45:54 +00:00
|
|
|
" -p a, auth | -\n"
|
|
|
|
" -p i, ident | -\n"
|
|
|
|
" -p r, rec | Most significant word in security question.\n\n" );
|
2017-07-16 01:13:49 +00:00
|
|
|
inf( ""
|
|
|
|
" -v Increase output verbosity (can be repeated).\n\n" );
|
|
|
|
inf( ""
|
|
|
|
" -q Decrease output verbosity (can be repeated).\n\n" );
|
|
|
|
inf( ""
|
|
|
|
" ENVIRONMENT\n\n"
|
2016-01-04 19:52:05 +00:00
|
|
|
" %-14s | The full name of the user (see -u).\n"
|
|
|
|
" %-14s | The default algorithm version (see -a).\n\n",
|
2017-08-01 17:45:54 +00:00
|
|
|
MP_env_fullName, MP_env_algorithm );
|
2014-12-20 04:15:32 +00:00
|
|
|
exit( 0 );
|
|
|
|
}
|
|
|
|
|
2017-07-16 01:13:49 +00:00
|
|
|
static char *mpwPath(const char *prefix, const char *extension) {
|
2014-12-20 04:15:32 +00:00
|
|
|
|
|
|
|
char *homedir = NULL;
|
|
|
|
struct passwd *passwd = getpwuid( getuid() );
|
|
|
|
if (passwd)
|
|
|
|
homedir = passwd->pw_dir;
|
|
|
|
if (!homedir)
|
|
|
|
homedir = getenv( "HOME" );
|
|
|
|
if (!homedir)
|
|
|
|
homedir = getcwd( NULL, 0 );
|
|
|
|
|
2017-07-16 01:13:49 +00:00
|
|
|
char *mpwPath = NULL;
|
|
|
|
asprintf( &mpwPath, "%s.%s", prefix, extension );
|
|
|
|
|
|
|
|
char *slash = strstr( mpwPath, "/" );
|
|
|
|
if (slash)
|
|
|
|
*slash = '\0';
|
|
|
|
|
|
|
|
asprintf( &mpwPath, "%s/.mpw.d/%s", homedir, mpwPath );
|
|
|
|
return mpwPath;
|
2014-12-20 04:15:32 +00:00
|
|
|
}
|
|
|
|
|
2016-11-03 14:31:07 +00:00
|
|
|
static char *getline_prompt(const char *prompt) {
|
2014-12-20 04:15:32 +00:00
|
|
|
|
|
|
|
char *buf = NULL;
|
|
|
|
size_t bufSize = 0;
|
|
|
|
ssize_t lineSize;
|
|
|
|
fprintf( stderr, "%s", prompt );
|
|
|
|
fprintf( stderr, " " );
|
2016-11-06 15:42:23 +00:00
|
|
|
if ((lineSize = getline( &buf, &bufSize, stdin )) <= 1) {
|
2014-12-20 04:15:32 +00:00
|
|
|
free( buf );
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
buf[lineSize - 1] = 0;
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char *const argv[]) {
|
|
|
|
|
2017-07-16 01:13:49 +00:00
|
|
|
// Master Password defaults.
|
2017-08-01 17:45:54 +00:00
|
|
|
const char *fullName = NULL, *masterPassword = NULL, *siteName = NULL, *keyContext = NULL;
|
|
|
|
MPPasswordType passwordType = MPPasswordTypeDefault;
|
|
|
|
MPKeyPurpose keyPurpose = MPKeyPurposeAuthentication;
|
2015-01-16 05:25:18 +00:00
|
|
|
MPAlgorithmVersion algorithmVersion = MPAlgorithmVersionCurrent;
|
2017-07-16 01:13:49 +00:00
|
|
|
uint32_t siteCounter = 1;
|
|
|
|
|
|
|
|
// Read the environment.
|
|
|
|
const char *fullNameArg = getenv( MP_env_fullName ), *masterPasswordArg = NULL, *siteNameArg = NULL;
|
2017-08-01 17:45:54 +00:00
|
|
|
const char *passwordTypeArg = NULL, *keyPurposeArg = NULL, *keyContextArg = NULL, *siteCounterArg = NULL;
|
2017-07-16 01:13:49 +00:00
|
|
|
const char *algorithmVersionArg = getenv( MP_env_algorithm );
|
2014-12-20 04:15:32 +00:00
|
|
|
|
2017-07-16 01:13:49 +00:00
|
|
|
// Read the command-line options.
|
2016-01-04 19:52:05 +00:00
|
|
|
for (int opt; (opt = getopt( argc, argv, "u:P:t:c:V:a:C:vqh" )) != -1;)
|
2014-12-20 04:15:32 +00:00
|
|
|
switch (opt) {
|
|
|
|
case 'u':
|
2017-07-16 01:13:49 +00:00
|
|
|
fullNameArg = optarg;
|
2014-12-20 04:15:32 +00:00
|
|
|
break;
|
2015-01-20 02:20:25 +00:00
|
|
|
case 'P':
|
2017-07-16 01:13:49 +00:00
|
|
|
// Passing your master password via the command-line is insecure. Testing purposes only.
|
|
|
|
masterPasswordArg = optarg;
|
2015-01-20 02:20:25 +00:00
|
|
|
break;
|
2014-12-20 04:15:32 +00:00
|
|
|
case 't':
|
2017-08-01 17:45:54 +00:00
|
|
|
passwordTypeArg = optarg;
|
2014-12-20 04:15:32 +00:00
|
|
|
break;
|
|
|
|
case 'c':
|
2017-07-16 01:13:49 +00:00
|
|
|
siteCounterArg = optarg;
|
2014-12-20 04:15:32 +00:00
|
|
|
break;
|
2017-08-01 17:45:54 +00:00
|
|
|
case 'p':
|
|
|
|
keyPurposeArg = optarg;
|
2014-12-20 04:15:32 +00:00
|
|
|
break;
|
2016-01-04 19:52:05 +00:00
|
|
|
case 'a':
|
2017-07-16 01:13:49 +00:00
|
|
|
algorithmVersionArg = optarg;
|
2015-01-16 05:25:18 +00:00
|
|
|
break;
|
2014-12-20 04:15:32 +00:00
|
|
|
case 'C':
|
2017-08-01 17:45:54 +00:00
|
|
|
keyContextArg = optarg;
|
2014-12-20 04:15:32 +00:00
|
|
|
break;
|
2016-01-04 19:52:05 +00:00
|
|
|
case 'v':
|
|
|
|
++mpw_verbosity;
|
|
|
|
break;
|
|
|
|
case 'q':
|
|
|
|
--mpw_verbosity;
|
|
|
|
break;
|
2014-12-20 04:15:32 +00:00
|
|
|
case 'h':
|
|
|
|
usage();
|
|
|
|
break;
|
|
|
|
case '?':
|
|
|
|
switch (optopt) {
|
|
|
|
case 'u':
|
2014-12-20 19:30:34 +00:00
|
|
|
ftl( "Missing full name to option: -%c\n", optopt );
|
2017-08-01 20:50:50 +00:00
|
|
|
abort();
|
2014-12-20 04:15:32 +00:00
|
|
|
case 't':
|
2014-12-20 19:30:34 +00:00
|
|
|
ftl( "Missing type name to option: -%c\n", optopt );
|
2017-08-01 20:50:50 +00:00
|
|
|
abort();
|
2014-12-20 04:15:32 +00:00
|
|
|
case 'c':
|
2014-12-20 19:30:34 +00:00
|
|
|
ftl( "Missing counter value to option: -%c\n", optopt );
|
2017-08-01 20:50:50 +00:00
|
|
|
abort();
|
2014-12-20 04:15:32 +00:00
|
|
|
default:
|
2014-12-20 19:30:34 +00:00
|
|
|
ftl( "Unknown option: -%c\n", optopt );
|
2017-08-01 20:50:50 +00:00
|
|
|
abort();
|
2014-12-20 04:15:32 +00:00
|
|
|
}
|
|
|
|
default:
|
2017-07-16 01:13:49 +00:00
|
|
|
ftl( "Unexpected option: %c", opt );
|
2017-08-01 20:50:50 +00:00
|
|
|
abort();
|
2014-12-20 04:15:32 +00:00
|
|
|
}
|
|
|
|
if (optind < argc)
|
2017-07-16 01:13:49 +00:00
|
|
|
siteNameArg = argv[optind];
|
2014-12-20 04:15:32 +00:00
|
|
|
|
2017-07-16 01:13:49 +00:00
|
|
|
// Empty strings unset the argument.
|
|
|
|
fullNameArg = fullNameArg && strlen( fullNameArg )? fullNameArg: NULL;
|
|
|
|
masterPasswordArg = masterPasswordArg && strlen( masterPasswordArg )? masterPasswordArg: NULL;
|
|
|
|
siteNameArg = siteNameArg && strlen( siteNameArg )? siteNameArg: NULL;
|
2017-08-01 17:45:54 +00:00
|
|
|
passwordTypeArg = passwordTypeArg && strlen( passwordTypeArg )? passwordTypeArg: NULL;
|
|
|
|
keyPurposeArg = keyPurposeArg && strlen( keyPurposeArg )? keyPurposeArg: NULL;
|
|
|
|
keyContextArg = keyContextArg && strlen( keyContextArg )? keyContextArg: NULL;
|
2017-07-16 01:13:49 +00:00
|
|
|
siteCounterArg = siteCounterArg && strlen( siteCounterArg )? siteCounterArg: NULL;
|
|
|
|
algorithmVersionArg = algorithmVersionArg && strlen( algorithmVersionArg )? algorithmVersionArg: NULL;
|
|
|
|
|
2017-07-23 01:38:53 +00:00
|
|
|
// Determine fullName, siteName & masterPassword.
|
2017-07-16 01:13:49 +00:00
|
|
|
if (!(fullNameArg && (fullName = strdup( fullNameArg ))) &&
|
2017-08-01 20:50:50 +00:00
|
|
|
!(fullName = getline_prompt( "Your full name:" ))) {
|
2014-12-20 19:30:34 +00:00
|
|
|
ftl( "Missing full name.\n" );
|
2017-08-01 20:50:50 +00:00
|
|
|
abort();
|
|
|
|
}
|
2017-07-16 01:13:49 +00:00
|
|
|
if (!(siteNameArg && (siteName = strdup( siteNameArg ))) &&
|
2017-08-01 20:50:50 +00:00
|
|
|
!(siteName = getline_prompt( "Site name:" ))) {
|
2014-12-20 19:30:34 +00:00
|
|
|
ftl( "Missing site name.\n" );
|
2017-08-01 20:50:50 +00:00
|
|
|
abort();
|
|
|
|
}
|
2017-07-23 01:38:53 +00:00
|
|
|
if (!(masterPasswordArg && (masterPassword = strdup( masterPasswordArg ))))
|
|
|
|
while (!masterPassword || !strlen( masterPassword ))
|
|
|
|
masterPassword = getpass( "Your master password: " );
|
2017-07-16 01:13:49 +00:00
|
|
|
|
2017-07-23 03:45:54 +00:00
|
|
|
// Find the user's sites file.
|
|
|
|
FILE *mpwSites = NULL;
|
|
|
|
MPMarshallFormat mpwSitesFormat = MPMarshallFormatJSON;
|
|
|
|
char *mpwSitesPath = mpwPath( fullName, "mpsites.json" );
|
|
|
|
if (!mpwSitesPath || !(mpwSites = fopen( mpwSitesPath, "r" ))) {
|
2017-07-16 01:13:49 +00:00
|
|
|
free( mpwSitesPath );
|
2017-07-23 03:45:54 +00:00
|
|
|
mpwSitesFormat = MPMarshallFormatFlat;
|
|
|
|
mpwSitesPath = mpwPath( fullName, "mpsites" );
|
|
|
|
if (!mpwSitesPath || !(mpwSites = fopen( mpwSitesPath, "r" )))
|
2017-08-01 21:35:13 +00:00
|
|
|
dbg( "Couldn't open configuration file:\n %s: %s\n",
|
|
|
|
mpwSitesPath, strerror( errno ) );
|
2017-07-23 03:45:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Read the user's sites file.
|
|
|
|
if (mpwSites) {
|
|
|
|
// Read file.
|
|
|
|
size_t readAmount = 4096, bufSize = 0, bufPointer = 0, readSize = 0;
|
|
|
|
char *buf = NULL;
|
|
|
|
while ((buf = realloc( buf, bufSize += readAmount )) &&
|
|
|
|
(bufPointer += (readSize = fread( buf + bufPointer, 1, readAmount, mpwSites ))) &&
|
|
|
|
(readSize == readAmount));
|
|
|
|
if (ferror( mpwSites ))
|
2017-08-01 21:35:13 +00:00
|
|
|
wrn( "Error while reading configuration file:\n %s: %d",
|
|
|
|
mpwSitesPath, ferror( mpwSites ) );
|
2017-07-23 03:45:54 +00:00
|
|
|
fclose( mpwSites );
|
|
|
|
|
|
|
|
// Parse file.
|
2017-07-23 20:49:55 +00:00
|
|
|
MPMarshallError marshallError = MPMarshallSuccess;
|
|
|
|
MPMarshalledUser *user = mpw_marshall_read( buf, mpwSitesFormat, masterPassword, &marshallError );
|
2017-07-23 03:45:54 +00:00
|
|
|
mpw_free_string( buf );
|
2017-07-23 20:49:55 +00:00
|
|
|
if (!user || marshallError != MPMarshallSuccess)
|
2017-08-01 21:35:13 +00:00
|
|
|
wrn( "Couldn't parse configuration file:\n %s: %s\n",
|
|
|
|
mpwSitesPath, mpw_explainMarshallError( marshallError ) );
|
2017-07-16 01:13:49 +00:00
|
|
|
|
|
|
|
else {
|
2017-07-23 03:45:54 +00:00
|
|
|
// Load defaults.
|
|
|
|
mpw_free_string( fullName );
|
|
|
|
mpw_free_string( masterPassword );
|
|
|
|
fullName = strdup( user->name );
|
|
|
|
masterPassword = strdup( user->masterPassword );
|
|
|
|
algorithmVersion = user->algorithm;
|
2017-08-01 17:45:54 +00:00
|
|
|
passwordType = user->defaultType;
|
2017-07-28 13:50:26 +00:00
|
|
|
for (size_t s = 0; s < user->sites_count; ++s) {
|
2017-07-23 03:45:54 +00:00
|
|
|
MPMarshalledSite site = user->sites[s];
|
|
|
|
if (strcmp( siteName, site.name ) == 0) {
|
2017-08-01 17:45:54 +00:00
|
|
|
passwordType = site.type;
|
2017-07-23 03:45:54 +00:00
|
|
|
siteCounter = site.counter;
|
|
|
|
algorithmVersion = site.algorithm;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Current format is not current, write out a new current format config file.
|
|
|
|
if (mpwSitesFormat != MPMarshallFormatJSON) {
|
|
|
|
mpwSitesPath = mpwPath( fullName, "mpsites.json" );
|
|
|
|
if (!mpwSitesPath || !(mpwSites = fopen( mpwSitesPath, "w" )))
|
2017-08-01 21:35:13 +00:00
|
|
|
wrn( "Couldn't create updated configuration file:\n %s: %s\n",
|
|
|
|
mpwSitesPath, strerror( errno ) );
|
2017-07-23 03:45:54 +00:00
|
|
|
|
|
|
|
else {
|
|
|
|
buf = NULL;
|
2017-07-23 20:49:55 +00:00
|
|
|
if (!mpw_marshall_write( &buf, MPMarshallFormatJSON, user, &marshallError ) || marshallError != MPMarshallSuccess)
|
2017-08-01 21:35:13 +00:00
|
|
|
wrn( "Couldn't encode updated configuration file:\n %s: %s",
|
|
|
|
mpwSitesPath, mpw_explainMarshallError( marshallError ) );
|
2017-07-23 03:45:54 +00:00
|
|
|
|
|
|
|
else if (fwrite( buf, sizeof( char ), strlen( buf ), mpwSites ) != strlen( buf ))
|
2017-08-01 21:35:13 +00:00
|
|
|
wrn( "Error while writing updated configuration file:\n %s: %d\n",
|
|
|
|
mpwSitesPath, ferror( mpwSites ) );
|
2017-07-23 03:45:54 +00:00
|
|
|
|
|
|
|
mpw_free_string( buf );
|
|
|
|
fclose( mpwSites );
|
2017-07-16 01:13:49 +00:00
|
|
|
}
|
|
|
|
}
|
2017-07-23 03:45:54 +00:00
|
|
|
mpw_marshal_free( user );
|
2017-07-16 01:13:49 +00:00
|
|
|
}
|
|
|
|
}
|
2017-08-01 21:35:13 +00:00
|
|
|
free( mpwSitesPath );
|
2017-07-16 01:13:49 +00:00
|
|
|
|
2017-07-23 01:38:53 +00:00
|
|
|
// Parse default/config-overriding command-line parameters.
|
|
|
|
if (algorithmVersionArg) {
|
|
|
|
int algorithmVersionInt = atoi( algorithmVersionArg );
|
2017-08-01 20:50:50 +00:00
|
|
|
if (algorithmVersionInt < MPAlgorithmVersionFirst || algorithmVersionInt > MPAlgorithmVersionLast) {
|
2017-07-23 01:38:53 +00:00
|
|
|
ftl( "Invalid algorithm version: %s\n", algorithmVersionArg );
|
2017-08-01 20:50:50 +00:00
|
|
|
abort();
|
|
|
|
}
|
2017-07-23 01:38:53 +00:00
|
|
|
algorithmVersion = (MPAlgorithmVersion)algorithmVersionInt;
|
|
|
|
}
|
2017-07-16 01:13:49 +00:00
|
|
|
if (siteCounterArg) {
|
|
|
|
long long int siteCounterInt = atoll( siteCounterArg );
|
2017-08-01 20:50:50 +00:00
|
|
|
if (siteCounterInt < 0 || siteCounterInt > UINT32_MAX) {
|
2017-07-16 01:13:49 +00:00
|
|
|
ftl( "Invalid site counter: %s\n", siteCounterArg );
|
2017-08-01 20:50:50 +00:00
|
|
|
abort();
|
|
|
|
}
|
2017-07-16 01:13:49 +00:00
|
|
|
siteCounter = (uint32_t)siteCounterInt;
|
|
|
|
}
|
2017-08-01 17:45:54 +00:00
|
|
|
if (keyPurposeArg)
|
|
|
|
keyPurpose = mpw_purposeWithName( keyPurposeArg );
|
|
|
|
if (keyPurpose == MPKeyPurposeIdentification)
|
|
|
|
passwordType = MPPasswordTypeGeneratedName;
|
|
|
|
if (keyPurpose == MPKeyPurposeRecovery)
|
|
|
|
passwordType = MPPasswordTypeGeneratedPhrase;
|
|
|
|
if (passwordTypeArg)
|
|
|
|
passwordType = mpw_typeWithName( passwordTypeArg );
|
|
|
|
if (keyContextArg)
|
|
|
|
keyContext = strdup( keyContextArg );
|
2014-12-20 04:15:32 +00:00
|
|
|
|
|
|
|
// Summarize operation.
|
2016-11-03 14:31:07 +00:00
|
|
|
const char *identicon = mpw_identicon( fullName, masterPassword );
|
2017-07-16 01:13:49 +00:00
|
|
|
if (!identicon)
|
|
|
|
wrn( "Couldn't determine identicon.\n" );
|
|
|
|
dbg( "-----------------\n" );
|
|
|
|
dbg( "fullName : %s\n", fullName );
|
|
|
|
trc( "masterPassword : %s\n", masterPassword );
|
|
|
|
dbg( "identicon : %s\n", identicon );
|
|
|
|
dbg( "siteName : %s\n", siteName );
|
|
|
|
dbg( "siteCounter : %u\n", siteCounter );
|
2017-08-01 18:34:15 +00:00
|
|
|
dbg( "keyPurpose : %s (%u)\n", mpw_nameForPurpose( keyPurpose ), keyPurpose );
|
|
|
|
dbg( "keyContext : %s\n", keyContext );
|
|
|
|
dbg( "passwordType : %s (%u)\n", mpw_nameForType( passwordType ), passwordType );
|
|
|
|
dbg( "algorithmVersion : %u\n", algorithmVersion );
|
2017-07-16 01:13:49 +00:00
|
|
|
dbg( "-----------------\n\n" );
|
|
|
|
inf( "%s's password for %s:\n[ %s ]: ", fullName, siteName, identicon );
|
|
|
|
mpw_free_string( identicon );
|
2014-12-20 04:15:32 +00:00
|
|
|
|
|
|
|
// Output the password.
|
2017-08-01 12:31:39 +00:00
|
|
|
MPMasterKey masterKey = mpw_masterKey(
|
2015-01-16 05:25:18 +00:00
|
|
|
fullName, masterPassword, algorithmVersion );
|
2016-11-03 14:04:18 +00:00
|
|
|
mpw_free_string( masterPassword );
|
2016-11-03 14:31:07 +00:00
|
|
|
mpw_free_string( fullName );
|
2017-08-01 20:50:50 +00:00
|
|
|
if (!masterKey) {
|
2014-12-21 17:37:21 +00:00
|
|
|
ftl( "Couldn't derive master key." );
|
2017-08-01 20:50:50 +00:00
|
|
|
abort();
|
|
|
|
}
|
2014-12-20 19:30:34 +00:00
|
|
|
|
2017-08-01 17:45:54 +00:00
|
|
|
MPSiteKey siteKey = mpw_siteKey( masterKey, siteName, siteCounter, keyPurpose, keyContext, algorithmVersion );
|
2017-08-01 21:35:13 +00:00
|
|
|
const char *sitePassword = mpw_sitePassword( siteKey, passwordType, algorithmVersion );
|
2017-07-16 01:13:49 +00:00
|
|
|
mpw_free( masterKey, MPMasterKeySize );
|
2017-08-01 12:31:39 +00:00
|
|
|
mpw_free( siteKey, MPSiteKeySize );
|
2016-11-03 14:31:07 +00:00
|
|
|
mpw_free_string( siteName );
|
2017-08-01 17:45:54 +00:00
|
|
|
mpw_free_string( keyContext );
|
2017-08-01 20:50:50 +00:00
|
|
|
if (!sitePassword) {
|
2014-12-21 17:37:21 +00:00
|
|
|
ftl( "Couldn't derive site password." );
|
2017-08-01 20:50:50 +00:00
|
|
|
abort();
|
|
|
|
}
|
2014-12-20 04:15:32 +00:00
|
|
|
|
2014-12-21 17:37:21 +00:00
|
|
|
fprintf( stdout, "%s\n", sitePassword );
|
2016-11-03 14:31:07 +00:00
|
|
|
mpw_free_string( sitePassword );
|
|
|
|
|
2014-12-20 04:15:32 +00:00
|
|
|
return 0;
|
|
|
|
}
|