1
0
mirror of https://github.com/mariadb-corporation/mariadb-columnstore-engine.git synced 2025-04-18 21:44:02 +03:00
2022-01-21 16:43:49 +00:00

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;
}