diff --git a/.gitignore b/.gitignore index 405c314..1fc2bd8 100644 --- a/.gitignore +++ b/.gitignore @@ -55,7 +55,6 @@ Makefile /src/swtpm_cert/swtpm_cert /src/swtpm_ioctl/swtpm_ioctl /src/swtpm_setup/dist -/src/swtpm_setup/swtpm_setup /src/swtpm_setup/py_swtpm_setup/swtpm_setup_conf.py /test-driver tests/*.log diff --git a/configure.ac b/configure.ac index 33f878c..2f20e8f 100644 --- a/configure.ac +++ b/configure.ac @@ -563,9 +563,10 @@ AC_CONFIG_FILES([Makefile \ ]) AC_CONFIG_FILES([samples/swtpm-localca], [chmod 755 samples/swtpm-localca]) +AC_CONFIG_FILES([src/swtpm_setup/swtpm_setup], + [chmod 755 src/swtpm_setup/swtpm_setup]) dnl for out-of-tree builds: -AC_CONFIG_LINKS([src/swtpm_setup/swtpm_setup.sh:src/swtpm_setup/swtpm_setup.sh \ - src/swtpm_setup/py_swtpm_setup/__init__.py:src/swtpm_setup/py_swtpm_setup/__init__.py \ +AC_CONFIG_LINKS([src/swtpm_setup/py_swtpm_setup/__init__.py:src/swtpm_setup/py_swtpm_setup/__init__.py \ src/swtpm_setup/py_swtpm_setup/swtpm.py:src/swtpm_setup/py_swtpm_setup/swtpm.py \ src/swtpm_setup/py_swtpm_setup/swtpm_utils.py:src/swtpm_setup/py_swtpm_setup/swtpm_utils.py \ src/swtpm_setup/py_swtpm_setup/swtpm_setup.py:src/swtpm_setup/py_swtpm_setup/swtpm_setup.py]) diff --git a/src/swtpm_setup/Makefile.am b/src/swtpm_setup/Makefile.am index 7afa1f7..a369f36 100644 --- a/src/swtpm_setup/Makefile.am +++ b/src/swtpm_setup/Makefile.am @@ -4,12 +4,7 @@ # For the license, see the LICENSE file in the root directory. # -bin_PROGRAMS = \ - swtpm_setup - -swtpm_setup_SOURCES = swtpm_setup.c - -dist_bin_SCRIPTS = swtpm_setup.sh +dist_bin_SCRIPTS = swtpm_setup PY_SWTPM_SETUP_FILES = $(wildcard py_swtpm_setup/*.py) @@ -24,13 +19,6 @@ $(PY_PACKAGE): $(PY_SWTPM_SETUP_FILES) all-local: $(PY_PACKAGE) -# for in-tree testing on Cygwin we need to copy swtpm_setup.exe -# for it to find swtpm_setup.sh -all: - @if test "$(host_os)" = "cygwin"; then \ - $(CP) -f .libs/swtpm_setup.exe ./ ; \ - fi - install-exec-local: $(PY_PACKAGE) @if ! test $(findstring /usr, "$(DESTDIR)$(bindir)"); then \ echo "Warning: Not installing python package to $(DESTDIR)$(bindir)"; \ diff --git a/src/swtpm_setup/py_swtpm_setup/swtpm_setup.py b/src/swtpm_setup/py_swtpm_setup/swtpm_setup.py index 8c58949..9f06f31 100755 --- a/src/swtpm_setup/py_swtpm_setup/swtpm_setup.py +++ b/src/swtpm_setup/py_swtpm_setup/swtpm_setup.py @@ -10,7 +10,8 @@ A tool for simulating the manufacturing of a TPM 1.2 or 2.0 # R0914: Too many local variables (21/15) (too-many-locals) # R0101: Too many nested blocks (6/5) (too-many-nested-blocks) # W0703: Catching too general exception Exception (broad-except) -# pylint: disable=W0703,R0913,R0914,R0912,R0101 +# C0302: Too many lines in module (1032/1000) (too-many-lines) +# pylint: disable=W0703,R0913,R0914,R0912,R0101,C0302 # # swtpm_setup.py @@ -28,6 +29,7 @@ import glob import grp import json import os +import pwd import re import subprocess import sys @@ -651,6 +653,41 @@ def print_capabilities(swtpm_prg_l): return 0 +def change_process_owner(user): + """ change the process owner to the given one """ + if not user.isnumeric(): + try: + passwd = pwd.getpwnam(user) + except KeyError: + logerr(LOGFILE, "Error: User '%s' does not exist.\n" % user) + return 1 + + try: + os.initgroups(passwd.pw_name, passwd.pw_gid) + except PermissionError as err: + logerr(LOGFILE, "Error: initgroups() failed: %s\n" % str(err)) + return 1 + gid = passwd.pw_gid + uid = passwd.pw_uid + else: + if int(user) > 0xffffffff: + logerr(LOGFILE, "Error: uid %s outside valid range.\n" % user) + gid = int(user) + uid = int(user) + + try: + os.setgid(gid) + except PermissionError as err: + logerr(LOGFILE, "Error: setgid(%d) failed: %s\n" % (gid, str(err))) + return 1 + + try: + os.setuid(uid) + except PermissionError as err: + logerr(LOGFILE, "Error: setuid(%d) failed: %s\n" % (uid, str(err))) + return 1 + + return 0 # pylint: disable=R0915 def main(): @@ -721,6 +758,7 @@ def main(): rsa_keysize_str = "%d" % DEFAULT_RSA_KEYSIZE swtpm_keyopt = "" fds_to_pass = [] + runas = "" for opt, arg in opts: if opt in ['--tpm-state', '--tpmstate']: @@ -772,8 +810,7 @@ def main(): elif opt == '--cipher': cipher = arg elif opt == '--runas': - # ignored here - pass + runas = arg elif opt == '--logfile': LOGFILE = arg elif opt == '--overwrite': @@ -816,6 +853,11 @@ def main(): ret = print_capabilities(swtpm_prg_l) sys.exit(ret) + if runas: + ret = change_process_owner(runas) + if ret != 0: + sys.exit(1) + if not got_ownerpass: flags |= SETUP_OWNERPASS_ZEROS_F if not got_srkpass: diff --git a/src/swtpm_setup/swtpm_setup.c b/src/swtpm_setup/swtpm_setup.c deleted file mode 100644 index 8630dcd..0000000 --- a/src/swtpm_setup/swtpm_setup.c +++ /dev/null @@ -1,301 +0,0 @@ -/* - * swtpm_setup.c - * - * Authors: Stefan Berger - * - * (c) Copyright IBM Corporation 2011,2014,2015. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the names of the IBM Corporation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined __APPLE__ -#include -#include -#endif - -/* - * Those parameters interpreted by swtpm_setup.sh that have an additional - * parameter. - */ -const char *one_arg_params[] = { - "--tpm-state", - "--tpmstate", - "--tpm", - "--ownerpass", - "--srkpass", - "--config", - "--vmid", - "--logfile", - "--keyfile", - "--pwdfile", - "--swtpm_ioctl", - "--pcr-banks", - "--tcsd-system-ps-file", - "--rsa-keysize", - NULL -}; - -/* - * Those parameters interpreted by swtpm_setup.sh that have a file descriptor - * parameter. - */ -const char *fd_arg_params[] = { - "--keyfile-fd", - "--pwdfile-fd", - NULL -}; - -/* - * Sanitize the file descriptor we pass to swtpm_setup.sh so that it can - * freely use any fds in the range [100..109], e.g. 'exec 100 ... '. - */ -static int move_reserved_fd(const char *fdstring, char **newfdstring) -{ - char *endptr; - long fd; - int newfd; - - errno = 0; - fd = strtol(fdstring, &endptr, 10); - if (fdstring == endptr || *endptr != '\0' || fd < 0 || errno != 0) { - fprintf(stderr, "Invalid file descriptor '%s'.\n", fdstring); - return -1; - } - - /* reserve file descriptors 100 - 109 for swtpm_setup.sh to use */ - if (fd >= 100 && fd <= 109) { - newfd = fcntl(fd, F_DUPFD, 3); - if (newfd < 0) { - fprintf(stderr, "F_DUPFD failed: %s\n", strerror(errno)); - return -1; - } - if (newfd >= 100 && newfd <= 109) { - fprintf(stderr, "newfd is also in reserved range: %u\n", newfd); - return -1; - } - - close(fd); - - if (asprintf(newfdstring, "%u", newfd) < 0) { - fprintf(stderr, "Out of memory\n"); - return -1; - } - - return 1; - } - return 0; -} - -static int change_process_owner(const char *user) -{ - struct passwd *passwd; - long int uid, gid; - char *endptr = NULL; - - uid = strtoul(user, &endptr, 10); - if (*endptr != '\0') { - /* a string */ - passwd = getpwnam(user); - if (!passwd) { - fprintf(stderr, "Error: User '%s' does not exist.\n", user); - return -1; - } - - if (initgroups(passwd->pw_name, passwd->pw_gid) < 0) { - fprintf(stderr, "Error: initgroups(%s, %d) failed.\n", - passwd->pw_name, passwd->pw_gid); - return -1; - } - gid = passwd->pw_gid; - uid = passwd->pw_uid; - } else { - /* an integer */ - if ((unsigned long int)uid > UINT_MAX) { - fprintf(stderr, "Error: uid %s outside valid range.\n", user); - return -1; - } - gid = uid; - } - - if (setgid(gid) < 0) { - fprintf(stderr, "Error: setgid(%ld) failed.\n", gid); - return -1; - } - if (setuid(uid) < 0) { - fprintf(stderr, "Error: setuid(%ld) failed.\n", uid); - return -1; - } - return 0; -} - - -int main(int argc, char *argv[]) -{ - const char *program = "swtpm_setup.sh"; - char resolved_path[PATH_MAX]; - char *dir; - char *path_program; - size_t length; - struct passwd *passwd = NULL; - int i = 1, j; - const char *userid = NULL; - bool change_user = true; - const char *p; -#if defined __APPLE__ - char path[MAXPATHLEN]; - uint32_t pathlen = sizeof(path); -#endif - char *newargv; - int rc; - - while (i < argc) { - if (!strcmp("--runas", argv[i])) { - i++; - if (i == argc) { - fprintf(stderr, "Missing user argument for --runas\n"); - exit(1); - } - userid = argv[i]; - } else if (!strcmp("--help", argv[i]) || !strcmp("-h", argv[i])) { - change_user = false; - } else if (!strcmp("--version", argv[i])) { - change_user = false; - } else if (!strcmp("--print-capabilities", argv[i])) { - change_user = false; - } - for (j = 0; one_arg_params[j] != NULL; j++) { - if (!strcmp(one_arg_params[j], argv[i])) { - i++; - goto skip; - } - } - /* Ensure that no file descriptor overlaps with those reserved - * for free use by swtpm_setup.sh - */ - for (j = 0; fd_arg_params[j] != NULL; j++) { - if (!strcmp(fd_arg_params[j], argv[i]) && - i + 1 < argc) { - i++; - rc = move_reserved_fd(argv[i], &newargv); - switch (rc) { - case 0: - /* nothing to do */ - break; - case 1: - argv[i] = newargv; - break; - default: - return EXIT_FAILURE; - } - break; - } - } -skip: - i++; - } - -#if defined __OpenBSD__ || defined __FreeBSD__ || defined __DragonFly__ - p = getenv("_"); -#elif defined __APPLE__ - if (_NSGetExecutablePath(path, &pathlen) < 0) { - fprintf(stderr, "Could not get path of 'self'."); - return EXIT_FAILURE; - } - p = path; -#else - p = "/proc/self/exe"; -#endif - if (!realpath(p, resolved_path)) { - fprintf(stderr, "Could not resolve path (%s) to executable: %s\n", - p, strerror(errno)); - return EXIT_FAILURE; - } - - dir = dirname(resolved_path); - if (!dir) { - fprintf(stderr, "Could not get directory from path '%s'.", - resolved_path); - return EXIT_FAILURE; - } - - length = strlen(dir) + 1 + strlen(program) + 2; - - path_program = malloc(length); - if (!path_program) { - fprintf(stderr, "Out of memory.\n"); - goto exit_failure; - } - - if (snprintf(path_program, length, "%s/%s", dir, program) >= - (int)length) { - fprintf(stderr, "Internal error writing string.\n"); - goto exit_failure; - } - - /* - * Unless we saw --runas, we will not attempt to switch the user. - */ - if (!userid) - change_user = false; - - if (change_user && change_process_owner(userid)) - goto exit_failure; - /* - * need to pass unmodified argv to swtpm_setup.sh - */ - execv(path_program, argv); - - if (passwd) { - /* should never get here */ - fprintf(stderr, "As user %s:", passwd->pw_name); - } - - fprintf(stderr, "Could not execute '%s' : %s\n", - path_program, strerror(errno)); - -exit_failure: - free(path_program); - - return EXIT_FAILURE; -} diff --git a/src/swtpm_setup/swtpm_setup.in b/src/swtpm_setup/swtpm_setup.in new file mode 100755 index 0000000..31dda83 --- /dev/null +++ b/src/swtpm_setup/swtpm_setup.in @@ -0,0 +1,7 @@ +#!/usr/bin/env python3 +""" Launcher for swtpm_setup +""" + +from py_swtpm_setup.swtpm_setup import main + +main() diff --git a/src/swtpm_setup/swtpm_setup.sh b/src/swtpm_setup/swtpm_setup.sh deleted file mode 100755 index d9c8038..0000000 --- a/src/swtpm_setup/swtpm_setup.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash - -python3 -c " -import sys; -from py_swtpm_setup.swtpm_setup import main - -sys.argv.pop(0) -sys.argv[0]='$0' -main()" \ -- "$@" diff --git a/tests/_test_print_capabilities b/tests/_test_print_capabilities index fc2e19b..02abd26 100755 --- a/tests/_test_print_capabilities +++ b/tests/_test_print_capabilities @@ -6,8 +6,6 @@ ROOT=${abs_top_builddir:-$(pwd)/..} TESTDIR=${abs_top_testdir:-$(dirname "$0")} -# We need to be able to find swtpm_setup.py and swtpm_setup.py needs to find swtpm -export PYTHONPATH=$ROOT/src/swtpm_setup PATH=$ROOT/src/swtpm:$PATH [ "${SWTPM_IFACE}" == "cuse" ] && source ${TESTDIR}/test_cuse diff --git a/tests/_test_tpm2_print_capabilities b/tests/_test_tpm2_print_capabilities index cce6b15..d31c8fc 100755 --- a/tests/_test_tpm2_print_capabilities +++ b/tests/_test_tpm2_print_capabilities @@ -6,8 +6,6 @@ ROOT=${abs_top_builddir:-$(pwd)/..} TESTDIR=${abs_top_testdir:-$(dirname "$0")} -# We need to be able to find swtpm_setup.py and swtpm_setup.py needs to find swtpm -export PYTHONPATH=$ROOT/src/swtpm_setup PATH=$ROOT/src/swtpm:$PATH [ "${SWTPM_IFACE}" == "cuse" ] && source ${TESTDIR}/test_cuse diff --git a/tests/test_parameters b/tests/test_parameters index 78f9f09..49c27f7 100755 --- a/tests/test_parameters +++ b/tests/test_parameters @@ -6,8 +6,6 @@ ROOT=${abs_top_builddir:-$(dirname "$0")/..} TESTDIR=${abs_top_testdir:=$(dirname "$0")} SRCDIR=${abs_top_srcdir:-$(dirname "$0")/..} -# We need to be able to find swtpm_setup.py and swtpm_setup.py needs to find swtpm -export PYTHONPATH=$ROOT/src/swtpm_setup PATH=$ROOT/src/swtpm:$PATH PARAMETERS=( diff --git a/tests/test_samples_create_tpmca b/tests/test_samples_create_tpmca index 72aa22c..ebb4913 100755 --- a/tests/test_samples_create_tpmca +++ b/tests/test_samples_create_tpmca @@ -18,8 +18,6 @@ ROOT=${abs_top_builddir:-$(dirname "$0")/..} TESTDIR=${abs_top_testdir:=$(dirname "$0")} SRCDIR=${abs_top_srcdir:-$(dirname "$0")/..} -# We need to be able to find swtpm_setup.py and swtpm_setup.py needs to find swtpm -export PYTHONPATH=$ROOT/src/swtpm_setup PATH=$ROOT/src/swtpm:$PATH source ${abs_top_builddir:-$(dirname "$0")/..}/tests/test_config diff --git a/tests/test_swtpm_setup_create_cert b/tests/test_swtpm_setup_create_cert index a2b58cc..3bb753c 100755 --- a/tests/test_swtpm_setup_create_cert +++ b/tests/test_swtpm_setup_create_cert @@ -7,8 +7,6 @@ ROOT=${abs_top_builddir:-$(dirname "$0")/..} TESTDIR=${abs_top_testdir:=$(dirname "$0")} SRCDIR=${abs_top_srcdir:-$(dirname "$0")/..} -# We need to be able to find swtpm_setup.py and swtpm_setup.py needs to find swtpm -export PYTHONPATH=$ROOT/src/swtpm_setup PATH=$ROOT/src/swtpm:$PATH SWTPM_SETUP=${ROOT}/src/swtpm_setup/swtpm_setup diff --git a/tests/test_tpm2_parameters b/tests/test_tpm2_parameters index 386c9be..74cd21f 100755 --- a/tests/test_tpm2_parameters +++ b/tests/test_tpm2_parameters @@ -6,8 +6,6 @@ ROOT=${abs_top_builddir:-$(dirname "$0")/..} TESTDIR=${abs_top_testdir:-$(dirname "$0")} SRCDIR=${abs_top_srcdir:-$(dirname "$0")/..} -# We need to be able to find swtpm_setup.py and swtpm_setup.py needs to find swtpm -export PYTHONPATH=$ROOT/src/swtpm_setup PATH=$ROOT/src/swtpm:$PATH source ${abs_top_builddir:-$(dirname "$0")/..}/tests/test_config diff --git a/tests/test_tpm2_swtpm_setup_create_cert b/tests/test_tpm2_swtpm_setup_create_cert index 9bc15e6..ce746eb 100755 --- a/tests/test_tpm2_swtpm_setup_create_cert +++ b/tests/test_tpm2_swtpm_setup_create_cert @@ -6,8 +6,6 @@ TOPBUILD=${abs_top_builddir:-$(dirname "$0")/..} TOPSRC=${abs_top_srcdir:-$(dirname "$0")/..} TESTDIR=${abs_top_testdir:-$(dirname "$0")} -# We need to be able to find swtpm_setup.py and swtpm_setup.py needs to find swtpm -export PYTHONPATH=${TOPBUILD}/src/swtpm_setup PATH=${TOPBUILD}/src/swtpm:$PATH SWTPM_SETUP=${TOPBUILD}/src/swtpm_setup/swtpm_setup