Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move EXE credential generation to a Python script #1260

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## [21.4] (unreleased)

### Changed
- Move EXE credential generation to a Python script [#1260](https://github.com/greenbone/gvmd/pull/1260)

[21.4]: https://github.com/greenbone/gvmd/compare/gvmd-20.08...master

## [20.08] (unreleased)

### Added
Expand Down
9 changes: 7 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -396,13 +396,18 @@ install (FILES ${CMAKE_BINARY_DIR}/tools/greenbone-certdata-sync
PERMISSIONS OWNER_EXECUTE OWNER_READ OWNER_WRITE
GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)

install (FILES ${CMAKE_SOURCE_DIR}/tools/gvm-lsc-deb-creator.sh
${CMAKE_SOURCE_DIR}/tools/gvm-lsc-rpm-creator.sh
install (FILES ${CMAKE_SOURCE_DIR}/tools/gvm-lsc-deb-creator
${CMAKE_SOURCE_DIR}/tools/gvm-lsc-exe-creator
${CMAKE_SOURCE_DIR}/tools/gvm-lsc-rpm-creator
DESTINATION ${GVM_DATA_DIR}
PERMISSIONS OWNER_EXECUTE OWNER_READ OWNER_WRITE
GROUP_READ GROUP_EXECUTE
WORLD_READ WORLD_EXECUTE)

install (FILES ${CMAKE_SOURCE_DIR}/tools/template.nsis
DESTINATION ${GVMD_DATA_DIR}
PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ)

install (FILES ${CMAKE_BINARY_DIR}/tools/gvm-manage-certs
DESTINATION ${BINDIR}
PERMISSIONS OWNER_EXECUTE OWNER_READ OWNER_WRITE
Expand Down
233 changes: 70 additions & 163 deletions src/lsc_user.c
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ lsc_user_rpm_create (const gchar *username,
g_debug ("%s: Attempting RPM build", __func__);
cmd = (gchar **) g_malloc (6 * sizeof (gchar *));
cmd[0] = g_build_filename (GVM_DATA_DIR,
"gvm-lsc-rpm-creator.sh",
"gvm-lsc-rpm-creator",
NULL);
cmd[1] = g_strdup (username);
cmd[2] = g_strdup (new_pubkey_filename);
Expand Down Expand Up @@ -413,7 +413,7 @@ lsc_user_deb_create (const gchar *username,
g_debug ("%s: Attempting DEB build", __func__);
cmd = (gchar **) g_malloc (7 * sizeof (gchar *));
cmd[0] = g_build_filename (GVM_DATA_DIR,
"gvm-lsc-deb-creator.sh",
"gvm-lsc-deb-creator",
NULL);
cmd[1] = g_strdup (username);
cmd[2] = g_strdup (new_pubkey_filename);
Expand Down Expand Up @@ -553,149 +553,78 @@ lsc_user_deb_recreate (const gchar *name, const char *public_key,
/* Exe generation. */

/**
* @brief Write an NSIS installer script to file.
* @brief Create a Windows EXE installer for adding a user.
*
* @param[in] script_name Name of script.
* @param[in] package_name Name of package.
* @param[in] user_name User name.
* @param[in] password User password.
* @param[in] username Name of user.
* @param[in] password Password of user.
* @param[in] to_filename Destination filename for package.
*
* @return 0 success, -1 error.
*/
static int
create_nsis_script (const gchar *script_name, const gchar *package_name,
const gchar *user_name, const gchar *password)
static gboolean
lsc_user_exe_create (const gchar *username,
const gchar *password,
const gchar *to_filename)
{
FILE* fd;
gint exit_status;
gchar **cmd;
char tmpdir[] = "/tmp/lsc_user_exe_create_XXXXXX";
gchar *password_file_path, *template_file_path;
gboolean ret = 0;
gchar *standard_out = NULL;
gchar *standard_err = NULL;
GError *error = NULL;

fd = fopen (script_name, "w");
if (fd == NULL)
return -1;
/* Create a temporary directory. */

// Write part about default section
fprintf (fd, "#Installer filename\n");
fprintf (fd, "outfile ");
fprintf (fd, "%s", package_name);
fprintf (fd, "\n\n");

fprintf (fd, "# Set desktop as install directory\n");
fprintf (fd, "installDir $DESKTOP\n\n");

fprintf (fd, "# Put some text\n");
fprintf (fd, "BrandingText \"GVM Local Security Checks User\"\n\n");

// For ms vista installers we need the UAC plugin and use the following lines:
// This requires the user to have the UAC plugin installed and to provide the
// the path to it.
//fprintf (fd, "# Request application privileges for Windows Vista\n");
//fprintf (fd, "RequestExecutionLevel admin\n\n");

fprintf (fd, "#\n# Default (installer) section.\n#\n");
fprintf (fd, "section\n\n");

fprintf (fd, "# Define output path\n");
fprintf (fd, "setOutPath $INSTDIR\n\n");

fprintf (fd, "# Uninstaller name\n");
fprintf (fd, "writeUninstaller $INSTDIR\\openvas_lsc_remove_%s.exe\n\n",
user_name);

// Need to find localized Administrators group name, create a
// GetAdminGroupName - vb script (Thanks to Thomas Rotter)
fprintf (fd, "# Create Thomas Rotters GetAdminGroupName.vb script\n");
fprintf (fd, "ExecWait \"cmd /C Echo Set objWMIService = GetObject($\\\"winmgmts:\\\\.\\root\\cimv2$\\\") > $\\\"%%temp%%\\GetAdminGroupName.vbs$\\\" \"\n");
fprintf (fd, "ExecWait \"cmd /C Echo Set colAccounts = objWMIService.ExecQuery ($\\\"Select * From Win32_Group Where SID = 'S-1-5-32-544'$\\\") >> $\\\"%%temp%%\\GetAdminGroupName.vbs$\\\"\"\n");
fprintf (fd, "ExecWait \"cmd /C Echo For Each objAccount in colAccounts >> $\\\"%%temp%%\\GetAdminGroupName.vbs$\\\"\"\n");
fprintf (fd, "ExecWait \"cmd /C Echo Wscript.Echo objAccount.Name >> $\\\"%%temp%%\\GetAdminGroupName.vbs$\\\"\"\n");
fprintf (fd, "ExecWait \"cmd /C Echo Next >> $\\\"%%temp%%\\GetAdminGroupName.vbs$\\\"\"\n");
fprintf (fd, "ExecWait \"cmd /C cscript //nologo $\\\"%%temp%%\\GetAdminGroupName.vbs$\\\" > $\\\"%%temp%%\\AdminGroupName.txt$\\\"\"\n\n");

/** @todo provide /comment:"GVM User" /fullname:"GVM Testuser" */
fprintf (fd, "# Create batch script that installs the user\n");
fprintf (fd, "ExecWait \"cmd /C Echo Set /P AdminGroupName= ^<$\\\"%%temp%%\\AdminGroupName.txt$\\\" > $\\\"%%temp%%\\AddUser.bat$\\\"\" \n");
fprintf (fd, "ExecWait \"cmd /C Echo net user %s %s /add /active:yes >> $\\\"%%temp%%\\AddUser.bat$\\\"\"\n",
user_name,
password);
fprintf (fd, "ExecWait \"cmd /C Echo net localgroup %%AdminGroupName%% %%COMPUTERNAME%%\\%s /add >> $\\\"%%temp%%\\AddUser.bat$\\\"\"\n\n",
user_name);

fprintf (fd, "# Execute AddUser script\n");
fprintf (fd, "ExecWait \"cmd /C $\\\"%%temp%%\\AddUser.bat$\\\"\"\n\n");

// Remove up temporary files for localized Administrators group names
fprintf (fd, "# Remove temporary files for localized admin group names\n");
fprintf (fd, "ExecWait \"del $\\\"%%temp%%\\AdminGroupName.txt$\\\"\"\n");
fprintf (fd, "ExecWait \"del $\\\"%%temp%%\\GetAdminGroupName.vbs$\\\"\"\n\n");
fprintf (fd, "ExecWait \"del $\\\"%%temp%%\\AddUser.bat$\\\"\"\n\n");

/** @todo Display note about NTLM and SMB signing and encryption, 'Easy Filesharing' in WIN XP */
fprintf (fd, "# Display message that everything seems to be fine\n");
fprintf (fd, "messageBox MB_OK \"A user has been added. An uninstaller is placed on your Desktop.\"\n\n");

fprintf (fd, "# Default (install) section end\n");
fprintf (fd, "sectionEnd\n\n");

// Write part about uninstall section
fprintf (fd, "#\n# Uninstaller section.\n#\n");
fprintf (fd, "section \"Uninstall\"\n\n");

fprintf (fd, "# Run cmd to remove user\n");
fprintf (fd, "ExecWait \"net user %s /delete\"\n\n",
user_name);

/** @todo Uninstaller should remove itself */
fprintf (fd, "# Unistaller should remove itself (from desktop/installdir)\n\n");

fprintf (fd, "# Display message that everything seems to be fine\n");
fprintf (fd, "messageBox MB_OK \"A user has been removed. You can now safely remove the uninstaller from your Desktop.\"\n\n");

fprintf (fd, "# Uninstaller section end\n");
fprintf (fd, "sectionEnd\n\n");

if (fclose (fd))
return -1;
g_debug ("%s: create temporary directory", __func__);
if (mkdtemp (tmpdir) == NULL)
return FALSE;
g_debug ("%s: temporary directory: %s", __func__, tmpdir);

return 0;
}
/* Create password file. */

/**
* @brief Execute makensis to create a package from an NSIS script.
*
* Run makensis in the directory that nsis_script is in.
*
* @param[in] nsis_script Name of resulting package.
*
* @return 0 success, -1 error.
*/
static int
execute_makensis (const gchar *nsis_script)
{
gchar *dirname = g_path_get_dirname (nsis_script);
gchar **cmd;
gint exit_status;
int ret = 0;
gchar *standard_out = NULL;
gchar *standard_err = NULL;
g_debug ("%s: create password file", __func__);
password_file_path = g_build_filename (tmpdir, "pw.txt", NULL);
if (g_file_set_contents (password_file_path, password, -1, &error) == FALSE)
{
g_warning ("%s: failed to create password file %s: %s",
__func__, password_file_path, error->message);
g_free (password_file_path);
return -1;
}

cmd = (gchar **) g_malloc (3 * sizeof (gchar *));
/* Build template file path */
template_file_path = g_build_filename (GVMD_DATA_DIR, "template.nsis", NULL);

/* Execute create-deb script with the temporary directory as the
* target and the public key in the temporary directory as the key. */

cmd[0] = g_strdup ("makensis");
cmd[1] = g_strdup (nsis_script);
cmd[2] = NULL;
g_debug ("--- executing makensis");
g_debug ("%s: Spawning in %s: %s %s",
__func__,
dirname, cmd[0], cmd[1]);
if ((g_spawn_sync (dirname,
g_debug ("%s: Attempting EXE build", __func__);
cmd = (gchar **) g_malloc (7 * sizeof (gchar *));
cmd[0] = g_build_filename (GVM_DATA_DIR,
"gvm-lsc-exe-creator",
NULL);
cmd[1] = g_strdup (username);
cmd[2] = g_strdup (password_file_path);
cmd[3] = g_strdup (tmpdir);
cmd[4] = g_strdup (to_filename);
cmd[5] = g_strdup (template_file_path);
cmd[6] = NULL;
g_debug ("%s: Spawning in %s: %s %s %s %s %s %s",
__func__, tmpdir,
cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5]);
if ((g_spawn_sync (tmpdir,
cmd,
NULL, /* Environment. */
G_SPAWN_SEARCH_PATH,
NULL, /* Setup func. */
NULL, /* Setup function. */
NULL,
&standard_out,
&standard_err,
&exit_status,
NULL) == FALSE)
NULL)
== FALSE)
|| (WIFEXITED (exit_status) == 0)
|| WEXITSTATUS (exit_status))
{
Expand All @@ -704,55 +633,33 @@ execute_makensis (const gchar *nsis_script)
exit_status,
WIFEXITED (exit_status),
WEXITSTATUS (exit_status));
g_debug ("%s: stdout: %s", __func__, standard_out);
g_debug ("%s: stderr: %s", __func__, standard_err);
g_message ("%s: stdout: %s", __func__, standard_out);
g_message ("%s: stderr: %s", __func__, standard_err);
ret = -1;
}

g_free (cmd[0]);
g_free (cmd[1]);
g_free (cmd[2]);
g_free (cmd[3]);
g_free (cmd[4]);
g_free (cmd[5]);
g_free (cmd);
g_free (dirname);
g_free (password_file_path);
g_free (template_file_path);
g_free (standard_out);
g_free (standard_err);

return ret;
}

/**
* @brief Create an NSIS package.
*
* @param[in] user_name Name of user.
* @param[in] password Password of user.
* @param[in] to_filename Destination filename for package.
*
* @return 0 success, -1 error.
*/
static int
lsc_user_exe_create (const gchar *user_name, const gchar *password,
const gchar *to_filename)
{
gchar *dirname = g_path_get_dirname (to_filename);
gchar *nsis_script = g_build_filename (dirname, "p.nsis", NULL);

g_free (dirname);

if (create_nsis_script (nsis_script, to_filename, user_name, password))
{
g_warning ("%s: Failed to create NSIS script", __func__);
g_free (nsis_script);
return -1;
}
/* Remove the copy of the public key and the temporary directory. */

if (execute_makensis (nsis_script))
if (gvm_file_remove_recurse (tmpdir) != 0 && ret == 0)
{
g_warning ("%s: Failed to execute makensis", __func__);
g_free (nsis_script);
return -1;
g_warning ("%s: failed to remove temporary directory %s",
__func__, tmpdir);
ret = -1;
}

g_free (nsis_script);
return 0;
return ret;
}

/**
Expand Down
File renamed without changes.
66 changes: 66 additions & 0 deletions tools/gvm-lsc-exe-creator
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/usr/bin/env python3
# Copyright (C) 2020 Greenbone Networks GmbH
#
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

# This script generates a Windows installer that creates a user for GVM
# local security checks.

import argparse
import os
import string
import subprocess
import sys
import tempfile

# Parse command line arguments
description = "Generate a Windows EXE credential installer"
argparser = argparse.ArgumentParser(description=description)
argparser.add_argument("username",
help="Name of the user to create")
argparser.add_argument("password_file_path",
help="Path to a file containing the user's password")
argparser.add_argument("temp_dir",
help="Directory to create temporary files in")
argparser.add_argument("output_path",
help="Path for finished installer")
argparser.add_argument("template_path",
help="Path of the NSIS script template file")
args = argparser.parse_args()

# Read password
with open(args.password_file_path, "r") as password_file:
password = password_file.read().rstrip("\n")

# Read NSIS script template
with open(args.template_path, "r") as template_file:
template_string = template_file.read()

template = string.Template(template_string)

# Create NSIS script by replacing placeholders in the given template
substitutions = {
"__USERNAME__" : args.username,
"__PASSWORD__" : password,
"__OUTPUT_PATH__" : args.output_path,
}
nsis_script = template.safe_substitute(substitutions)
nsis_script_path = os.path.join(args.temp_dir, "script.nsis")
with open(nsis_script_path, "w") as nsis_script_file:
nsis_script_file.write(nsis_script)

run = subprocess.run(["makensis", nsis_script_path])
sys,exit(run.returncode)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is typo. Needs to be sys.exit

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And the code should be put into a function that gets called instead

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should be fixed in #1262

File renamed without changes.
Loading