Skip to content

Commit

Permalink
Merge pull request #1260 from timopollmeier/script-based-exe-installers
Browse files Browse the repository at this point in the history
 Move EXE credential generation to a Python script
  • Loading branch information
mattmundell authored Aug 17, 2020
2 parents 28a7ae3 + de4b482 commit 5b32b80
Show file tree
Hide file tree
Showing 7 changed files with 239 additions and 165 deletions.
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)
File renamed without changes.
Loading

0 comments on commit 5b32b80

Please sign in to comment.