mirror of
https://github.com/stefanberger/swtpm.git
synced 2026-02-01 09:18:07 +00:00
swtpm_setup: Get rid of 'c' code and support changing user in python
Get rid of the 'c' code that only changed the user and add for support of the --runas option to change to a different user in the python part. To get 'make distcheck' to work I needed to name the swtpm_setup python script with the suffix .in so that it gets copied to the build directory as swtpm_setup. We need to change execute permissions on this file after copying. Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
This commit is contained in:
parent
094dba930f
commit
3064a72ff0
1
.gitignore
vendored
1
.gitignore
vendored
@ -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
|
||||
|
||||
@ -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])
|
||||
|
||||
@ -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)"; \
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -1,301 +0,0 @@
|
||||
/*
|
||||
* swtpm_setup.c
|
||||
*
|
||||
* Authors: Stefan Berger <stefanb@us.ibm.com>
|
||||
*
|
||||
* (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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <libgen.h>
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#if defined __APPLE__
|
||||
#include <sys/mount.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#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;
|
||||
}
|
||||
7
src/swtpm_setup/swtpm_setup.in
Executable file
7
src/swtpm_setup/swtpm_setup.in
Executable file
@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
""" Launcher for swtpm_setup
|
||||
"""
|
||||
|
||||
from py_swtpm_setup.swtpm_setup import main
|
||||
|
||||
main()
|
||||
@ -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()" \
|
||||
- "$@"
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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=(
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user