mirror of
https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
synced 2025-04-18 21:44:02 +03:00
255 lines
5.8 KiB
C++
255 lines
5.8 KiB
C++
/*
|
|
* Copyright (c) 2016 MariaDB Corporation Ab
|
|
*
|
|
* Use of this software is governed by the Business Source License included
|
|
* in the LICENSE.TXT file and at www.mariadb.com/bsl11.
|
|
*
|
|
* Change Date: 2025-05-25
|
|
*
|
|
* On the date above, in accordance with the Business Source License, use
|
|
* of this software will be governed by version 2 or later of the General
|
|
* Public License.
|
|
*/
|
|
|
|
/**
|
|
* @file cspasswd.cpp - Implementation of pasword encoding
|
|
* Modified from MariaDB internal implementations
|
|
*/
|
|
|
|
#include <cstdio>
|
|
#include <getopt.h>
|
|
#include <termios.h>
|
|
#include <unistd.h>
|
|
|
|
#include <iostream>
|
|
|
|
#include "secrets.h"
|
|
#include "mcsconfig.h"
|
|
|
|
using std::cin;
|
|
using std::cout;
|
|
using std::endl;
|
|
using std::flush;
|
|
using std::string;
|
|
|
|
struct option options[] = {{"help", no_argument, nullptr, 'h'},
|
|
{"decrypt", no_argument, nullptr, 'd'},
|
|
{"interactive", no_argument, nullptr, 'i'},
|
|
{nullptr, 0, nullptr, 0}};
|
|
|
|
void print_usage(const char* executable, const char* directory)
|
|
{
|
|
const char msg[] =
|
|
R"(Usage: %s [-h|--help] [-i|--interactive] [-d|--decrypt] [path] password
|
|
Encrypt a Columnstore plaintext password using the encryption key in the key file
|
|
'%s'. The key file may be generated using the 'cskeys'-utility.
|
|
-h, --help Display this help.
|
|
-d, --decrypt Decrypt an encrypted password instead.
|
|
-i, --interactive - If cspasswd is reading from a pipe, it will read a line and
|
|
use that as the password.
|
|
- If cspasswd is connected to a terminal console, it will prompt
|
|
for the password.
|
|
If '-i' is specified, a single argument is assumed to be the path
|
|
and two arguments is treated like an error.
|
|
path The key file directory (default: '%s')
|
|
password The password to encrypt or decrypt
|
|
)";
|
|
|
|
printf(msg, executable, SECRETS_FILENAME, directory);
|
|
}
|
|
|
|
bool read_password(string* pPassword)
|
|
{
|
|
bool rv = false;
|
|
string password;
|
|
|
|
if (isatty(STDIN_FILENO))
|
|
{
|
|
struct termios tty;
|
|
tcgetattr(STDIN_FILENO, &tty);
|
|
|
|
bool echo = (tty.c_lflag & ECHO);
|
|
if (echo)
|
|
{
|
|
tty.c_lflag &= ~ECHO;
|
|
tcsetattr(STDIN_FILENO, TCSANOW, &tty);
|
|
}
|
|
|
|
cout << "Enter password : " << flush;
|
|
string s1;
|
|
std::getline(std::cin, s1);
|
|
cout << endl;
|
|
|
|
cout << "Repeat password: " << flush;
|
|
string s2;
|
|
std::getline(std::cin, s2);
|
|
cout << endl;
|
|
|
|
if (echo)
|
|
{
|
|
tty.c_lflag |= ECHO;
|
|
tcsetattr(STDIN_FILENO, TCSANOW, &tty);
|
|
}
|
|
|
|
if (s1 == s2)
|
|
{
|
|
password = s1;
|
|
rv = true;
|
|
}
|
|
else
|
|
{
|
|
cout << "Passwords are not identical." << endl;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::getline(std::cin, password);
|
|
rv = true;
|
|
}
|
|
|
|
if (rv)
|
|
{
|
|
*pPassword = password;
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
std::ios::sync_with_stdio();
|
|
const string default_directory = string(MCSDATADIR);
|
|
|
|
enum class Mode
|
|
{
|
|
ENCRYPT,
|
|
DECRYPT
|
|
};
|
|
|
|
auto mode = Mode::ENCRYPT;
|
|
bool interactive = false;
|
|
|
|
int c;
|
|
while ((c = getopt_long(argc, argv, "hdi", options, NULL)) != -1)
|
|
{
|
|
switch (c)
|
|
{
|
|
case 'h': print_usage(argv[0], default_directory.c_str()); return EXIT_SUCCESS;
|
|
|
|
case 'd': mode = Mode::DECRYPT; break;
|
|
|
|
case 'i': interactive = true; break;
|
|
|
|
default: print_usage(argv[0], default_directory.c_str()); return EXIT_FAILURE;
|
|
}
|
|
}
|
|
|
|
string input;
|
|
string path = default_directory;
|
|
|
|
switch (argc - optind)
|
|
{
|
|
case 2:
|
|
// Two args provided.
|
|
path = argv[optind];
|
|
if (!interactive)
|
|
{
|
|
input = argv[optind + 1];
|
|
}
|
|
else
|
|
{
|
|
print_usage(argv[0], default_directory.c_str());
|
|
return EXIT_FAILURE;
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
// One arg provided.
|
|
if (!interactive)
|
|
{
|
|
input = argv[optind];
|
|
}
|
|
else
|
|
{
|
|
path = argv[optind];
|
|
}
|
|
break;
|
|
|
|
case 0:
|
|
if (!interactive)
|
|
{
|
|
print_usage(argv[0], default_directory.c_str());
|
|
return EXIT_FAILURE;
|
|
}
|
|
break;
|
|
|
|
default: print_usage(argv[0], default_directory.c_str()); return EXIT_FAILURE;
|
|
}
|
|
|
|
if (interactive)
|
|
{
|
|
if (!read_password(&input))
|
|
{
|
|
return EXIT_FAILURE;
|
|
}
|
|
}
|
|
|
|
int rval = EXIT_FAILURE;
|
|
|
|
string filepath = path;
|
|
filepath.append("/").append(SECRETS_FILENAME);
|
|
|
|
auto keydata = secrets_readkeys(filepath);
|
|
if (keydata.ok)
|
|
{
|
|
bool encrypting = (mode == Mode::ENCRYPT);
|
|
bool new_mode = keydata.iv.empty(); // false -> constant IV from file
|
|
if (keydata.key.empty())
|
|
{
|
|
printf("Password encryption key file '%s' not found, cannot %s password.\n", filepath.c_str(),
|
|
encrypting ? "encrypt" : "decrypt");
|
|
}
|
|
else if (encrypting)
|
|
{
|
|
string encrypted = new_mode ? encrypt_password(keydata.key, input)
|
|
: encrypt_password_old(keydata.key, keydata.iv, input);
|
|
if (!encrypted.empty())
|
|
{
|
|
printf("%s\n", encrypted.c_str());
|
|
rval = EXIT_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
printf("Password encryption failed.\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
auto is_hex = std::all_of(input.begin(), input.end(), isxdigit);
|
|
if (is_hex && input.length() % 2 == 0)
|
|
{
|
|
string decrypted = new_mode ? decrypt_password(keydata.key, input)
|
|
: decrypt_password_old(keydata.key, keydata.iv, input);
|
|
if (!decrypted.empty())
|
|
{
|
|
printf("%s\n", decrypted.c_str());
|
|
rval = EXIT_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
printf("Password decryption failed.\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
printf("Input is not a valid hex-encoded encrypted password.\n");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
printf("Could not read encryption key file '%s'.\n", filepath.c_str());
|
|
}
|
|
return rval;
|
|
}
|