blob: 14cc9762232d6ba9b425d894300296fd8f303eba [file] [log] [blame]
/*
* utils.s -- utilities
*
* (c) Copyright IBM Corporation 2014, 2015, 2019.
*
* Author: Stefan Berger <stefanb@us.ibm.com>
*
* 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.
*/
#include "config.h"
#include <grp.h>
#include <pwd.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#if defined __APPLE__
#include <fcntl.h>
#include <sys/param.h>
#endif
#include "utils.h"
#include "logging.h"
#include "tpmlib.h"
#include "swtpm_debug.h"
void uninstall_sighandlers()
{
if (signal(SIGTERM, SIG_DFL) == SIG_ERR)
logprintf(STDERR_FILENO, "Could not uninstall signal handler for SIGTERM.\n");
if (signal(SIGPIPE, SIG_DFL) == SIG_ERR)
logprintf(STDERR_FILENO, "Could not uninstall signal handler for SIGPIPE.\n");
}
int install_sighandlers(int pipefd[2], sighandler_t handler)
{
if (pipe(pipefd) < 0) {
logprintf(STDERR_FILENO, "Error: Could not open pipe.\n");
goto err_exit;
}
if (signal(SIGTERM, handler) == SIG_ERR) {
logprintf(STDERR_FILENO, "Could not install signal handler for SIGTERM.\n");
goto err_close_pipe;
}
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
logprintf(STDERR_FILENO, "Could not install signal handler for SIGPIPE.\n");
goto err_close_pipe;
}
return 0;
err_close_pipe:
close(pipefd[0]);
pipefd[0] = -1;
close(pipefd[1]);
pipefd[1] = -1;
err_exit:
return -1;
}
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) {
logprintf(STDERR_FILENO,
"Error: User '%s' does not exist.\n",
user);
return -14;
}
if (initgroups(passwd->pw_name, passwd->pw_gid) < 0) {
logprintf(STDERR_FILENO,
"Error: initgroups(%s, %d) failed.\n",
passwd->pw_name, passwd->pw_gid);
return -10;
}
gid = passwd->pw_gid;
uid = passwd->pw_uid;
} else {
/* an integer */
if ((unsigned long int)uid > UINT_MAX) {
logprintf(STDERR_FILENO,
"Error: uid %s outside valid range.\n",
user);
return -13;
}
gid = uid;
}
if (setgid(gid) < 0) {
logprintf(STDERR_FILENO,
"Error: setgid(%d) failed.\n",
gid);
return -11;
}
if (setuid(uid) < 0) {
logprintf(STDERR_FILENO,
"Error: setuid(%d) failed.\n",
uid);
return -12;
}
return 0;
}
int
do_chroot(const char *path)
{
if (chroot(path) < 0) {
logprintf(STDERR_FILENO, "chroot failed: %s\n",
strerror(errno));
return -1;
}
if (chdir("/") < 0) {
logprintf(STDERR_FILENO, "chdir failed: %s\n",
strerror(errno));
return -1;
}
return 0;
}
void tpmlib_debug_libtpms_parameters(TPMLIB_TPMVersion tpmversion)
{
switch (tpmversion) {
case TPMLIB_TPM_VERSION_1_2:
TPM_DEBUG("TPM 1.2: Compiled for %u auth, %u transport, "
"and %u DAA session slots\n",
tpmlib_get_tpm_property(TPMPROP_TPM_MIN_AUTH_SESSIONS),
tpmlib_get_tpm_property(TPMPROP_TPM_MIN_TRANS_SESSIONS),
tpmlib_get_tpm_property(TPMPROP_TPM_MIN_DAA_SESSIONS));
TPM_DEBUG("TPM 1.2: Compiled for %u key slots, %u owner evict slots\n",
tpmlib_get_tpm_property(TPMPROP_TPM_KEY_HANDLES),
tpmlib_get_tpm_property(TPMPROP_TPM_OWNER_EVICT_KEY_HANDLES));
TPM_DEBUG("TPM 1.2: Compiled for %u counters, %u saved sessions\n",
tpmlib_get_tpm_property(TPMPROP_TPM_MIN_COUNTERS),
tpmlib_get_tpm_property(TPMPROP_TPM_MIN_SESSION_LIST));
TPM_DEBUG("TPM 1.2: Compiled for %u family, "
"%u delegate table entries\n",
tpmlib_get_tpm_property(TPMPROP_TPM_NUM_FAMILY_TABLE_ENTRY_MIN),
tpmlib_get_tpm_property(TPMPROP_TPM_NUM_DELEGATE_TABLE_ENTRY_MIN));
TPM_DEBUG("TPM 1.2: Compiled for %u total NV, %u savestate, "
"%u volatile space\n",
tpmlib_get_tpm_property(TPMPROP_TPM_MAX_NV_SPACE),
tpmlib_get_tpm_property(TPMPROP_TPM_MAX_SAVESTATE_SPACE),
tpmlib_get_tpm_property(TPMPROP_TPM_MAX_VOLATILESTATE_SPACE));
#if 0
TPM_DEBUG("TPM1.2: Compiled for %u NV defined space\n",
tpmlib_get_tpm_property(TPMPROP_TPM_MAX_NV_DEFINED_SIZE));
#endif
break;
case TPMLIB_TPM_VERSION_2:
break;
}
}
char *fd_to_filename(int fd)
{
#if defined __linux__
char buffer[64];
char *path;
snprintf(buffer, sizeof(buffer), "/proc/self/fd/%d", fd);
path = realpath(buffer, NULL);
if (!path) {
logprintf(STDERR_FILENO, "Could not read %s: %s\n",
buffer, strerror(errno));
return NULL;
}
return path;
#elif defined __APPLE__
char *path = malloc(MAXPATHLEN);
if (!path) {
logprintf(STDERR_FILENO, "Out of memory.\n");
return NULL;
}
if (fcntl(fd, F_GETPATH, path) < 0) {
logprintf(STDERR_FILENO, "fcntl for F_GETPATH failed: %\n",
strerror(errno));
free(path);
return NULL;
}
return path;
#else
(void)fd;
logprintf(STDERR_FILENO,
"Cannot convert file descriptor to filename on this platform.\n");
return NULL;
#endif
}
/*
* write_full: Write all bytes of a buffer into the file descriptor
* and handle partial writes on the way.
*
* @fd: file descriptor to write to
* @buffer: buffer
* @buflen: length of buffer
*
* Returns -1 in case not all bytes could be transferred, number of
* bytes written otherwise (must be equal to buflen).
*/
ssize_t write_full(int fd, const void *buffer, size_t buflen)
{
size_t written = 0;
ssize_t n;
while (written < buflen) {
n = write(fd, buffer, buflen - written);
if (n == 0)
return -1;
if (n < 0) {
if (errno == EINTR)
continue;
return -1;
}
written += n;
buffer += n;
}
return written;
}
/*
* writev_full: Write all bytes of an iovec into the file descriptor
* and handle partial writes on the way.
* @fd: file descriptor to write to
* @iov: pointer to iov
* @iovcnt: length of iov array
*
* Returns -1 in case not all bytes could be transferred, number of
* bytes written otherwise (must be equal to buflen).
*/
ssize_t writev_full(int fd, const struct iovec *iov, int iovcnt)
{
int i;
size_t off;
unsigned char *buf;
ssize_t n;
size_t bytecount = 0;
size_t numbufs = 0;
size_t lastidx = -1;
for (i = 0; i < iovcnt; i++) {
if (iov[i].iov_len) {
bytecount += iov[i].iov_len;
numbufs++;
lastidx = i;
}
}
if (numbufs == 1)
return write_full(fd, iov[lastidx].iov_base, iov[lastidx].iov_len);
buf = malloc(bytecount);
if (!buf) {
errno = ENOMEM;
return -1;
}
off = 0;
for (i = 0; i < iovcnt; i++) {
if (!iov[i].iov_len)
continue;
memcpy(&buf[off], iov[i].iov_base, iov[i].iov_len);
off += iov[i].iov_len;
}
n = write_full(fd, buf, off);
free(buf);
return n;
}
/*
* read_einter: Read bytes from a file descriptor into a buffer
* and handle EINTR. Perform one read().
*
* @fd: file descriptor to read from
* @buffer: buffer
* @buflen: length of buffer
*
* Returns -1 in case an error occurred, number of bytes read otherwise.
*/
ssize_t read_eintr(int fd, void *buffer, size_t buflen)
{
ssize_t n;
while (true) {
n = read(fd, buffer, buflen);
if (n < 0) {
if (errno == EINTR)
continue;
return -1;
}
return n;
}
}