v5.2.2.1
-the built in ssl cert generater was deprecated so it needed to be updated or removed. I opted to calling openssl via external command line execution. doing it this way make it easier to update if deprecated again and reduces dependancy on libssl. -tweaked the documentation a little. -updated build.py to explicitly get the plugins directoy instead of deriving it from the bin directory.
This commit is contained in:
parent
fabc82a0a2
commit
51072f0a59
12
README.md
12
README.md
|
@ -23,7 +23,7 @@ Usage: mrci <argument>
|
||||||
-load_ssl : re-load the host SSL certificate without stopping the host instance.
|
-load_ssl : re-load the host SSL certificate without stopping the host instance.
|
||||||
-elevate : elevate any user account to rank 1.
|
-elevate : elevate any user account to rank 1.
|
||||||
-res_pw : reset a user account password with a randomized one time password.
|
-res_pw : reset a user account password with a randomized one time password.
|
||||||
-add_admin : create a rank 1 account with a randomized password.
|
-add_admin : create a rank 1 account with a randomized one time password.
|
||||||
|
|
||||||
Internal module | -public_cmds, -user_cmds, -exempt_cmds, -run_cmd |:
|
Internal module | -public_cmds, -user_cmds, -exempt_cmds, -run_cmd |:
|
||||||
|
|
||||||
|
@ -46,9 +46,9 @@ add_admin - this argument takes a single string representing a user name to crea
|
||||||
elevate - this argument takes a single string representing a user name to an account to promote to rank 1.
|
elevate - this argument takes a single string representing a user name to an account to promote to rank 1.
|
||||||
example: -elevate somebody
|
example: -elevate somebody
|
||||||
|
|
||||||
run_cmd - this argument is used by the host itself, along side the internal module arguments below to run
|
run_cmd - this argument is used by the host itself along with the internal module arguments to run the
|
||||||
the internal command names passed by it. this is not meant to be run directly by human input.
|
internal command names passed by it. this is not ment to be run directly by human input. the
|
||||||
the executable will auto close if it fails to connect to the pipe and/or shared memory segments
|
executable will auto close if it fails to connect to the pipe and/or shared memory segments
|
||||||
```
|
```
|
||||||
|
|
||||||
The host can be managed via a connected client that supports text input/output so the host application is always listening for clients while running entirely in the background. By default the host listen for clients on address 0.0.0.0 and port 35516, effectively making it reachable on any network interface of the host platform via that specific port.
|
The host can be managed via a connected client that supports text input/output so the host application is always listening for clients while running entirely in the background. By default the host listen for clients on address 0.0.0.0 and port 35516, effectively making it reachable on any network interface of the host platform via that specific port.
|
||||||
|
@ -60,7 +60,7 @@ Typical use for a MRCI host is to run commands on a remote host that clients ask
|
||||||
* Broadcast any type of data to all peers connected to the host.
|
* Broadcast any type of data to all peers connected to the host.
|
||||||
* Run remote commands on connected peers.
|
* Run remote commands on connected peers.
|
||||||
* Host object positioning data for peers (online games do this).
|
* Host object positioning data for peers (online games do this).
|
||||||
* Send data to/from a peer client directly.
|
* Send data to/from a peer clients directly.
|
||||||
* Fully featured user account management system.
|
* Fully featured user account management system.
|
||||||
* Built in permissions and command access management.
|
* Built in permissions and command access management.
|
||||||
* Host limits management (max concurrent users, max failed password attempts, etc...).
|
* Host limits management (max concurrent users, max failed password attempts, etc...).
|
||||||
|
@ -103,7 +103,7 @@ Python3
|
||||||
|
|
||||||
### Build ###
|
### Build ###
|
||||||
|
|
||||||
To build this project from source you just need to run the build.py and then the install.py python scripts. While running the build the script, it will try to find the Qt API installed in your machine according to the PATH env variable. If not found, it will ask you to input where it can find the Qt bin folder where the qmake executable exists or you can bypass all of this by passing the -qt_dir option on it's command line.
|
To build this project from source you just need to run the ```build.py``` and then the ```install.py``` python scripts. While running the build the script, it will try to find the Qt API installed in your machine according to the PATH env variable. If not found, it will ask you to input where it can find the Qt bin folder where the qmake executable exists or you can bypass all of this by passing the -qt_dir option on it's command line.
|
||||||
|
|
||||||
while running the install script, it will ask you to input 1 of 3 options:
|
while running the install script, it will ask you to input 1 of 3 options:
|
||||||
|
|
||||||
|
|
45
build.py
45
build.py
|
@ -25,6 +25,15 @@ def get_qt_path():
|
||||||
|
|
||||||
return input("Please enter the QT bin path (leave blank to cancel the build): ")
|
return input("Please enter the QT bin path (leave blank to cancel the build): ")
|
||||||
|
|
||||||
|
def get_qt_plugin_path():
|
||||||
|
try:
|
||||||
|
return str(subprocess.check_output(["qtpaths", "--plugin-dir"]), 'utf-8').strip()
|
||||||
|
|
||||||
|
except:
|
||||||
|
print("A direct call to 'qtpaths' has failed so automatic retrieval of the QT plugins folder is not possible.")
|
||||||
|
|
||||||
|
return input("Please enter the QT plugins path (leave blank to cancel the build): ")
|
||||||
|
|
||||||
def get_qt_from_cli():
|
def get_qt_from_cli():
|
||||||
for arg in sys.argv:
|
for arg in sys.argv:
|
||||||
if arg == "-qt_dir":
|
if arg == "-qt_dir":
|
||||||
|
@ -38,6 +47,19 @@ def get_qt_from_cli():
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
def get_qt_plug_from_cli():
|
||||||
|
for arg in sys.argv:
|
||||||
|
if arg == "-qt_plugin":
|
||||||
|
index = sys.argv.index(arg)
|
||||||
|
|
||||||
|
try:
|
||||||
|
return sys.argv[index + 1]
|
||||||
|
|
||||||
|
except:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
return ""
|
||||||
|
|
||||||
def get_info_header():
|
def get_info_header():
|
||||||
current_dir = os.path.dirname(__file__)
|
current_dir = os.path.dirname(__file__)
|
||||||
|
|
||||||
|
@ -130,17 +152,17 @@ def verbose_copy(src, dst):
|
||||||
else:
|
else:
|
||||||
print("wrn: " + src + " does not exists. skipping.")
|
print("wrn: " + src + " does not exists. skipping.")
|
||||||
|
|
||||||
def linux_build_app_dir(app_ver, app_name, app_target, qt_bin):
|
def linux_build_app_dir(app_ver, app_name, app_target, qt_bin, qt_plug):
|
||||||
if not os.path.exists("app_dir/linux/sqldrivers"):
|
if not os.path.exists("app_dir/linux/sqldrivers"):
|
||||||
os.makedirs("app_dir/linux/sqldrivers")
|
os.makedirs("app_dir/linux/sqldrivers")
|
||||||
|
|
||||||
if not os.path.exists("app_dir/linux/lib"):
|
if not os.path.exists("app_dir/linux/lib"):
|
||||||
os.makedirs("app_dir/linux/lib")
|
os.makedirs("app_dir/linux/lib")
|
||||||
|
|
||||||
verbose_copy(qt_bin + "/../plugins/sqldrivers/libqsqlite.so", "app_dir/linux/sqldrivers/libqsqlite.so")
|
verbose_copy(qt_plug + "/sqldrivers/libqsqlite.so", "app_dir/linux/sqldrivers/libqsqlite.so")
|
||||||
verbose_copy(qt_bin + "/../plugins/sqldrivers/libqsqlodbc.so", "app_dir/linux/sqldrivers/libqsqlodbc.so")
|
verbose_copy(qt_plug + "/sqldrivers/libqsqlodbc.so", "app_dir/linux/sqldrivers/libqsqlodbc.so")
|
||||||
verbose_copy(qt_bin + "/../plugins/sqldrivers/libqsqlpsql.so", "app_dir/linux/sqldrivers/libqsqlpsql.so")
|
verbose_copy(qt_plug + "/sqldrivers/libqsqlpsql.so", "app_dir/linux/sqldrivers/libqsqlpsql.so")
|
||||||
verbose_copy(qt_bin + "/../plugins/sqldrivers/libqsqlmysql.so", "app_dir/linux/sqldrivers/libqsqlmysql.so")
|
verbose_copy(qt_plug + "/sqldrivers/libqsqlmysql.so", "app_dir/linux/sqldrivers/libqsqlmysql.so")
|
||||||
verbose_copy("build/linux/" + app_target, "app_dir/linux/" + app_target)
|
verbose_copy("build/linux/" + app_target, "app_dir/linux/" + app_target)
|
||||||
|
|
||||||
shutil.copyfile("build/linux/" + app_target, "/tmp/" + app_target)
|
shutil.copyfile("build/linux/" + app_target, "/tmp/" + app_target)
|
||||||
|
@ -221,17 +243,26 @@ def main():
|
||||||
app_ver = get_app_ver(text)
|
app_ver = get_app_ver(text)
|
||||||
app_name = get_app_name(text)
|
app_name = get_app_name(text)
|
||||||
qt_bin = get_qt_from_cli()
|
qt_bin = get_qt_from_cli()
|
||||||
|
qt_plug = get_qt_plug_from_cli()
|
||||||
|
|
||||||
if qt_bin == "":
|
if qt_bin == "":
|
||||||
qt_bin = get_qt_path()
|
qt_bin = get_qt_path()
|
||||||
|
|
||||||
|
if qt_plug == "":
|
||||||
|
if platform.system() == "Linux":
|
||||||
|
qt_plug = get_qt_plugin_path()
|
||||||
|
|
||||||
|
else:
|
||||||
|
qt_plug = "not-needed"
|
||||||
|
|
||||||
maker = get_maker(qt_bin)
|
maker = get_maker(qt_bin)
|
||||||
|
|
||||||
if qt_bin != "":
|
if qt_bin != "" and qt_plug != "":
|
||||||
print("app_target = " + app_target)
|
print("app_target = " + app_target)
|
||||||
print("app_version = " + app_ver)
|
print("app_version = " + app_ver)
|
||||||
print("app_name = " + app_name)
|
print("app_name = " + app_name)
|
||||||
print("qt_bin = " + qt_bin)
|
print("qt_bin = " + qt_bin)
|
||||||
|
print("qt_plugins = " + qt_plug)
|
||||||
print("maker = " + maker + "\n")
|
print("maker = " + maker + "\n")
|
||||||
|
|
||||||
if maker == "":
|
if maker == "":
|
||||||
|
@ -264,7 +295,7 @@ def main():
|
||||||
info_file.write(app_name + "\n")
|
info_file.write(app_name + "\n")
|
||||||
|
|
||||||
if platform.system() == "Linux":
|
if platform.system() == "Linux":
|
||||||
linux_build_app_dir(app_ver, app_name, app_target, qt_bin)
|
linux_build_app_dir(app_ver, app_name, app_target, qt_bin, qt_plug)
|
||||||
|
|
||||||
elif platform.system() == "Windows":
|
elif platform.system() == "Windows":
|
||||||
windows_build_app_dir(app_ver, app_name, app_target, qt_bin)
|
windows_build_app_dir(app_ver, app_name, app_target, qt_bin)
|
||||||
|
|
|
@ -47,7 +47,7 @@ notes:
|
||||||
|
|
||||||
* When the session detects that the module successfully established a pipe connection, it will send a [HOST_VER](type_ids.md) frame to the module so the module can decide if it supports the host. If the host is not compatible or the module fails for what ever other reason, the module can send a useful error message [ERR](type_ids.md) and then terminate gracefully. The error message will be added to the host debug log where it can be used by host admins to find out what went wrong. The HOST_VER frame is sent only when the module is called with the -public_cmds, -exempt_cmds or -user_cmds parameter.
|
* When the session detects that the module successfully established a pipe connection, it will send a [HOST_VER](type_ids.md) frame to the module so the module can decide if it supports the host. If the host is not compatible or the module fails for what ever other reason, the module can send a useful error message [ERR](type_ids.md) and then terminate gracefully. The error message will be added to the host debug log where it can be used by host admins to find out what went wrong. The HOST_VER frame is sent only when the module is called with the -public_cmds, -exempt_cmds or -user_cmds parameter.
|
||||||
|
|
||||||
* When the module sends a [NEW_CMD](type_ids.md) frame, the 16bit command id is needed but does not need to be valid, it just needs to be there as a place holder. The session will auto fill a valid command id before sending the data to the client. A valid NEW_CMD frame must have a minimum of 259 bytes and a valid command name. the session will ignore all NEW_CMD frames the doesn't meet these requirements. See section [6.3](shared_data.md) for what would be considered a valid command name.
|
* When the module sends a [NEW_CMD](type_ids.md) frame, the 16bit command id is needed but does not need to be valid, it just needs to be there as a place holder. The session will auto fill a valid command id before sending the data to the client. A valid NEW_CMD frame must have a minimum of 259 bytes and a valid command name. the session will ignore all NEW_CMD frames the doesn't meet these requirements. See section [6.4](shared_data.md) for what would be considered a valid command name.
|
||||||
|
|
||||||
* When a session starts, it will call all modules with the -public_cmds and it doesn't matter if the command names returned to the session overlap with -exempt_cmd or -user_cmds. When a user is logged in, it will then call 2 instances of each module with the -exempt_cmds and -user_cmds parameters so the command names should not overlap when these parameters are active.
|
* When a session starts, it will call all modules with the -public_cmds and it doesn't matter if the command names returned to the session overlap with -exempt_cmd or -user_cmds. When a user is logged in, it will then call 2 instances of each module with the -exempt_cmds and -user_cmds parameters so the command names should not overlap when these parameters are active.
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ notes:
|
||||||
|
|
||||||
| Data | Type | Vaild Size Range | Forbidden Chars | Must Contain |
|
| Data | Type | Vaild Size Range | Forbidden Chars | Must Contain |
|
||||||
| ---------------------- | ------ | ---------------- | ------------------ | ----------------------------------------------------------- |
|
| ---------------------- | ------ | ---------------- | ------------------ | ----------------------------------------------------------- |
|
||||||
| Module Executable Path | String | 1-512 | ```|*:\"?<>``` | |
|
| Module Executable Path | String | 1-512 | ```\|*:"?<>``` | |
|
||||||
| User Name | String | 2-24 | spaces or newlines | |
|
| User Name | String | 2-24 | spaces or newlines | |
|
||||||
| Email Address | String | 4-64 | spaces or newlines | ```@``` and ```.``` |
|
| Email Address | String | 4-64 | spaces or newlines | ```@``` and ```.``` |
|
||||||
| Password | String | 8-200 | | special chars, numbers, capital letters and common letters. |
|
| Password | String | 8-200 | | special chars, numbers, capital letters and common letters. |
|
||||||
|
|
|
@ -80,7 +80,7 @@
|
||||||
#include "mem_share.h"
|
#include "mem_share.h"
|
||||||
|
|
||||||
#define APP_NAME "MRCI"
|
#define APP_NAME "MRCI"
|
||||||
#define APP_VER "5.1.2.1"
|
#define APP_VER "5.2.2.1"
|
||||||
#define APP_TARGET "mrci"
|
#define APP_TARGET "mrci"
|
||||||
#define SERVER_HEADER_TAG "MRCI"
|
#define SERVER_HEADER_TAG "MRCI"
|
||||||
#define HOST_CONTROL_PIPE "MRCI_HOST_CONTROL"
|
#define HOST_CONTROL_PIPE "MRCI_HOST_CONTROL"
|
||||||
|
@ -111,8 +111,8 @@
|
||||||
#define DEFAULT_DB_DRIVER "QSQLITE"
|
#define DEFAULT_DB_DRIVER "QSQLITE"
|
||||||
#define DEFAULT_DB_FILENAME "data.db"
|
#define DEFAULT_DB_FILENAME "data.db"
|
||||||
#define DEFAULT_LOG_FILENAME "messages.log"
|
#define DEFAULT_LOG_FILENAME "messages.log"
|
||||||
#define DEFAULT_CERT_FILENAME "tls_chain.pem"
|
#define DEFAULT_CERT_FILENAME "tls_chain.crt"
|
||||||
#define DEFAULT_PRIV_FILENAME "tls_priv.pem"
|
#define DEFAULT_PRIV_FILENAME "tls_priv.key"
|
||||||
#define DEFAULT_RES_PW_FILENAME "res_pw_template.txt"
|
#define DEFAULT_RES_PW_FILENAME "res_pw_template.txt"
|
||||||
#define DEFAULT_EVERIFY_FILENAME "email_verify_template.txt"
|
#define DEFAULT_EVERIFY_FILENAME "email_verify_template.txt"
|
||||||
#define DEFAULT_CONFIRM_SUBJECT "Email Verification"
|
#define DEFAULT_CONFIRM_SUBJECT "Email Verification"
|
||||||
|
|
|
@ -186,8 +186,6 @@ int main(int argc, char *argv[])
|
||||||
QCoreApplication::setApplicationName(APP_NAME);
|
QCoreApplication::setApplicationName(APP_NAME);
|
||||||
QCoreApplication::setApplicationVersion(APP_VER);
|
QCoreApplication::setApplicationVersion(APP_VER);
|
||||||
|
|
||||||
// args.append("-ls_sql_drvs"); // debug
|
|
||||||
|
|
||||||
if (args.contains("-run_cmd", Qt::CaseInsensitive) ||
|
if (args.contains("-run_cmd", Qt::CaseInsensitive) ||
|
||||||
args.contains("-public_cmds", Qt::CaseInsensitive) ||
|
args.contains("-public_cmds", Qt::CaseInsensitive) ||
|
||||||
args.contains("-exempt_cmds", Qt::CaseInsensitive) ||
|
args.contains("-exempt_cmds", Qt::CaseInsensitive) ||
|
||||||
|
|
|
@ -16,217 +16,65 @@
|
||||||
// along with MRCI_Client under the LICENSE.md file. If not, see
|
// along with MRCI_Client under the LICENSE.md file. If not, see
|
||||||
// <http://www.gnu.org/licenses/>.
|
// <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
Cert::Cert(QObject *parent) : QObject(parent)
|
|
||||||
{
|
|
||||||
pKey = EVP_PKEY_new();
|
|
||||||
x509 = X509_new();
|
|
||||||
bne = BN_new();
|
|
||||||
rsa = RSA_new();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Cert::cleanup()
|
|
||||||
{
|
|
||||||
EVP_PKEY_free(pKey);
|
|
||||||
X509_free(x509);
|
|
||||||
BN_free(bne);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool genRSAKey(Cert *cert, QTextStream &msg)
|
|
||||||
{
|
|
||||||
bool ret = false;
|
|
||||||
|
|
||||||
if (cert->pKey && cert->bne && cert->rsa)
|
|
||||||
{
|
|
||||||
if (BN_set_word(cert->bne, RSA_F4))
|
|
||||||
{
|
|
||||||
if (RSA_generate_key_ex(cert->rsa, 2048, cert->bne, NULL))
|
|
||||||
{
|
|
||||||
if (EVP_PKEY_assign_RSA(cert->pKey, cert->rsa))
|
|
||||||
{
|
|
||||||
ret = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
msg << "Failed to assign the generated RSA key to a PKEY object." << Qt::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
msg << "Failed to generate the RSA private key." << Qt::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
msg << "Failed to initialize a BIGNUM object needed to generate the RSA key." << Qt::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
msg << "The x509 object did not initialize correctly." << Qt::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool genX509(Cert *cert, const QString &outsideAddr, QTextStream &msg)
|
|
||||||
{
|
|
||||||
auto ret = false;
|
|
||||||
auto interfaces = QNetworkInterface::allAddresses();
|
|
||||||
|
|
||||||
QList<QByteArray> cnNames;
|
|
||||||
|
|
||||||
if (!outsideAddr.isEmpty())
|
|
||||||
{
|
|
||||||
msg << "x509 gen_wan_ip: " << outsideAddr << Qt::endl;
|
|
||||||
|
|
||||||
cnNames.append(outsideAddr.toUtf8());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto&& addr : interfaces)
|
|
||||||
{
|
|
||||||
if (addr.isGlobal())
|
|
||||||
{
|
|
||||||
msg << "x509 gen_lan_ip: " << addr.toString() << Qt::endl;
|
|
||||||
|
|
||||||
cnNames.append(addr.toString().toUtf8());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cert->x509 && cert->pKey && !cnNames.isEmpty())
|
|
||||||
{
|
|
||||||
ASN1_INTEGER_set(X509_get_serialNumber(cert->x509), QDateTime::currentDateTime().toSecsSinceEpoch());
|
|
||||||
|
|
||||||
X509_gmtime_adj(X509_get_notBefore(cert->x509), 0); // now
|
|
||||||
X509_gmtime_adj(X509_get_notAfter(cert->x509), 31536000L); // 365 days
|
|
||||||
X509_set_pubkey(cert->x509, cert->pKey);
|
|
||||||
|
|
||||||
// copy the subject name to the issuer name.
|
|
||||||
|
|
||||||
auto *name = X509_get_subject_name(cert->x509);
|
|
||||||
|
|
||||||
X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char *) cnNames[0].data(), -1, -1, 0);
|
|
||||||
|
|
||||||
X509_set_issuer_name(cert->x509, name);
|
|
||||||
|
|
||||||
cnNames.removeAt(0);
|
|
||||||
|
|
||||||
QByteArray sanField;
|
|
||||||
|
|
||||||
for (int i = 0; i < cnNames.size(); ++i)
|
|
||||||
{
|
|
||||||
sanField.append("DNS:" + cnNames[i]);
|
|
||||||
|
|
||||||
if (i != cnNames.size() - 1)
|
|
||||||
{
|
|
||||||
sanField.append(", ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!sanField.isEmpty())
|
|
||||||
{
|
|
||||||
addExt(cert->x509, NID_subject_alt_name, sanField.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (X509_sign(cert->x509, cert->pKey, EVP_sha1()))
|
|
||||||
{
|
|
||||||
ret = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
msg << "Failed to self-sign the generated x509 cert." << Qt::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
msg << "No usable IP addresses could be found to be used as common names in the self-signed cert." << Qt::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void addExt(X509 *cert, int nid, char *value)
|
|
||||||
{
|
|
||||||
X509_EXTENSION *ext = X509V3_EXT_conf_nid(NULL, NULL, nid, value);
|
|
||||||
|
|
||||||
if (ext != NULL)
|
|
||||||
{
|
|
||||||
X509_add_ext(cert, ext, -1);
|
|
||||||
X509_EXTENSION_free(ext);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FILE *openFileForWrite(const char *path, QTextStream &msg)
|
|
||||||
{
|
|
||||||
auto file = fopen(path, "wb");
|
|
||||||
|
|
||||||
if (!file)
|
|
||||||
{
|
|
||||||
msg << "Cannot open file: '" << path << "' for writing. " << strerror(errno);
|
|
||||||
}
|
|
||||||
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
void encodeErr(const char *path, QTextStream &msg)
|
|
||||||
{
|
|
||||||
msg << "Failed to encode file '" << path << "' to PEM format." << Qt::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool writePrivateKey(const char *path, Cert* cert, QTextStream &msg)
|
|
||||||
{
|
|
||||||
auto ret = false;
|
|
||||||
FILE *file = openFileForWrite(path, msg);
|
|
||||||
|
|
||||||
if (file)
|
|
||||||
{
|
|
||||||
if (PEM_write_PrivateKey(file, cert->pKey, NULL, NULL, 0, NULL, NULL))
|
|
||||||
{
|
|
||||||
ret = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
encodeErr(path, msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(file);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool writeX509(const char *path, Cert *cert, QTextStream &msg)
|
|
||||||
{
|
|
||||||
auto ret = false;
|
|
||||||
FILE *file = openFileForWrite(path, msg);
|
|
||||||
|
|
||||||
if (file)
|
|
||||||
{
|
|
||||||
if (PEM_write_X509(file, cert->x509))
|
|
||||||
{
|
|
||||||
ret = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
encodeErr(path, msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(file);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool genDefaultSSLFiles(const QString &outsideAddr, QTextStream &msg)
|
bool genDefaultSSLFiles(const QString &outsideAddr, QTextStream &msg)
|
||||||
{
|
{
|
||||||
auto *cert = new Cert();
|
QProcess proc;
|
||||||
auto ret = genRSAKey(cert, msg);
|
QStringList args;
|
||||||
|
|
||||||
if (ret) ret = genX509(cert, outsideAddr, msg);
|
args << "req";
|
||||||
if (ret) ret = writePrivateKey(DEFAULT_PRIV_FILENAME, cert, msg);
|
args << "-newkey" << "rsa:4096";
|
||||||
if (ret) ret = writeX509(DEFAULT_CERT_FILENAME, cert, msg);
|
args << "-x509";
|
||||||
|
args << "-sha256";
|
||||||
|
args << "-days" << "365";
|
||||||
|
args << "-nodes";
|
||||||
|
args << "-out" << getLocalFilePath(DEFAULT_CERT_FILENAME);
|
||||||
|
args << "-keyout" << getLocalFilePath(DEFAULT_PRIV_FILENAME);
|
||||||
|
args << "-subj" << "/CN=" + outsideAddr;
|
||||||
|
|
||||||
cert->cleanup();
|
proc.setProgram("openssl");
|
||||||
cert->deleteLater();
|
proc.setArguments(args);
|
||||||
|
proc.start();
|
||||||
|
|
||||||
|
msg << "openssl args: " << args.join(' ') << Qt::endl;
|
||||||
|
|
||||||
|
auto ret = false;
|
||||||
|
|
||||||
|
if (!proc.waitForStarted())
|
||||||
|
{
|
||||||
|
msg << "err: openssl failed to start, reason: " << proc.errorString() << Qt::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
proc.waitForFinished();
|
||||||
|
|
||||||
|
msg << "--openssl-output--" << Qt::endl;
|
||||||
|
|
||||||
|
auto outText = proc.readAllStandardOutput();
|
||||||
|
auto errText = proc.readAllStandardError();
|
||||||
|
|
||||||
|
msg << "std-out:" << Qt::endl;
|
||||||
|
|
||||||
|
for (auto line : outText.split('\n'))
|
||||||
|
{
|
||||||
|
msg << line << Qt::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg << "std-err:" << Qt::endl;
|
||||||
|
|
||||||
|
for (auto line: errText.split('\n'))
|
||||||
|
{
|
||||||
|
msg << line << Qt::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proc.exitCode() != 0)
|
||||||
|
{
|
||||||
|
msg << "err: openssl failed with return code: " << proc.exitCode() << Qt::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,46 +17,8 @@
|
||||||
// along with MRCI_Client under the LICENSE.md file. If not, see
|
// along with MRCI_Client under the LICENSE.md file. If not, see
|
||||||
// <http://www.gnu.org/licenses/>.
|
// <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
#include <openssl/ssl.h>
|
|
||||||
#include <openssl/x509.h>
|
|
||||||
#include <openssl/x509v3.h>
|
|
||||||
|
|
||||||
#include <QDateTime>
|
|
||||||
#include <QCoreApplication>
|
|
||||||
#include <QIODevice>
|
|
||||||
#include <QFile>
|
|
||||||
#include <QSslCertificate>
|
|
||||||
#include <QList>
|
|
||||||
#include <QNetworkInterface>
|
|
||||||
#include <QHostAddress>
|
|
||||||
#include <QSslKey>
|
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
class Cert : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
EVP_PKEY *pKey;
|
|
||||||
X509 *x509;
|
|
||||||
BIGNUM *bne;
|
|
||||||
RSA *rsa;
|
|
||||||
|
|
||||||
void cleanup();
|
|
||||||
|
|
||||||
explicit Cert(QObject *parent = nullptr);
|
|
||||||
};
|
|
||||||
|
|
||||||
FILE *openFileForWrite(const char *path, QTextStream &msg);
|
|
||||||
bool genRSAKey(Cert *cert, QTextStream &msg);
|
|
||||||
bool genX509(Cert *cert, const QString &outsideAddr, QTextStream &msg);
|
|
||||||
bool writePrivateKey(const char *path, Cert *cert, QTextStream &msg);
|
|
||||||
bool writeX509(const char *path, Cert *cert, QTextStream &msg);
|
|
||||||
bool genDefaultSSLFiles(const QString &outsideAddr, QTextStream &msg);
|
bool genDefaultSSLFiles(const QString &outsideAddr, QTextStream &msg);
|
||||||
void addExt(X509 *cert, int nid, char *value);
|
|
||||||
void encodeErr(const char *path, QTextStream &msg);
|
|
||||||
|
|
||||||
#endif // MAKE_CERT_H
|
#endif // MAKE_CERT_H
|
||||||
|
|
|
@ -26,6 +26,8 @@ TCPServer::TCPServer(QObject *parent) : QTcpServer(parent)
|
||||||
controlSocket = nullptr;
|
controlSocket = nullptr;
|
||||||
flags = 0;
|
flags = 0;
|
||||||
|
|
||||||
|
controlPipe->setSocketOptions(QLocalServer::OtherAccessOption);
|
||||||
|
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
|
|
||||||
setupUnixSignalHandlers();
|
setupUnixSignalHandlers();
|
||||||
|
|
|
@ -55,15 +55,23 @@ UnixSignalHandler::UnixSignalHandler(QObject *parent) : QObject(parent)
|
||||||
void UnixSignalHandler::hupSignalHandler(int)
|
void UnixSignalHandler::hupSignalHandler(int)
|
||||||
{
|
{
|
||||||
char chr = 1;
|
char chr = 1;
|
||||||
|
auto sz = static_cast<uint>(sizeof(chr));
|
||||||
|
|
||||||
write(sighupFd[0], &chr, sizeof(chr));
|
if (write(sighupFd[0], &chr, sz) != sz)
|
||||||
|
{
|
||||||
|
QTextStream(stderr) << "err: Failed write out HUP signal in the signal handler." << Qt::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnixSignalHandler::termSignalHandler(int)
|
void UnixSignalHandler::termSignalHandler(int)
|
||||||
{
|
{
|
||||||
char chr = 1;
|
char chr = 1;
|
||||||
|
auto sz = static_cast<uint>(sizeof(chr));
|
||||||
|
|
||||||
write(sigtermFd[0], &chr, sizeof(chr));
|
if (write(sigtermFd[0], &chr, sz) != sz)
|
||||||
|
{
|
||||||
|
QTextStream(stderr) << "err: Failed write out TERM signal in the signal handler." << Qt::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnixSignalHandler::handleSigTerm()
|
void UnixSignalHandler::handleSigTerm()
|
||||||
|
@ -71,8 +79,12 @@ void UnixSignalHandler::handleSigTerm()
|
||||||
snTerm->setEnabled(false);
|
snTerm->setEnabled(false);
|
||||||
|
|
||||||
char chr;
|
char chr;
|
||||||
|
auto sz = static_cast<uint>(sizeof(chr));
|
||||||
|
|
||||||
read(sigtermFd[1], &chr, sizeof(chr));
|
if (read(sigtermFd[1], &chr, sz) != sz)
|
||||||
|
{
|
||||||
|
QTextStream(stderr) << "wrn: Failed to read TERM signal data, however this should not affect signal handler operation." << Qt::endl;
|
||||||
|
}
|
||||||
|
|
||||||
emit closeServer();
|
emit closeServer();
|
||||||
|
|
||||||
|
@ -84,8 +96,12 @@ void UnixSignalHandler::handleSigHup()
|
||||||
snHup->setEnabled(false);
|
snHup->setEnabled(false);
|
||||||
|
|
||||||
char chr;
|
char chr;
|
||||||
|
auto sz = static_cast<uint>(sizeof(chr));
|
||||||
|
|
||||||
read(sighupFd[1], &chr, sizeof(chr));
|
if (read(sighupFd[1], &chr, sz) != sz)
|
||||||
|
{
|
||||||
|
QTextStream(stderr) << "wrn: Failed to read HUP signal data, however this should not affect signal handler operation." << Qt::endl;
|
||||||
|
}
|
||||||
|
|
||||||
emit closeServer();
|
emit closeServer();
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QTextStream>
|
||||||
#include <QSocketNotifier>
|
#include <QSocketNotifier>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user