mirror of
https://github.com/opnsense/src.git
synced 2026-06-08 08:12:27 -04:00
Some logging operations require access to external resources to complete. Logging to F_WALL requires on-demand access to the user accounting database. Logging to F_CONSOLE requires access to the console. Logging to F_PIPE prompts execution of a command outside of capability mode. These operations cannot be performed in capability mode, so the "p_open", "ttymsg", and "wallmsg" commands may be sent to libcasper to circumvent these limitations. Reviewed by: markj Differential Revision: https://reviews.freebsd.org/D41465
211 lines
5.6 KiB
C
211 lines
5.6 KiB
C
/*-
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*
|
|
* Copyright (c) 2023 The FreeBSD Foundation
|
|
*
|
|
* This software was developed by Jake Freeland <jfree@FreeBSD.org>
|
|
* under sponsorship from the FreeBSD Foundation.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. 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.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 <assert.h>
|
|
#include <err.h>
|
|
#include <string.h>
|
|
|
|
#include "syslogd_cap.h"
|
|
|
|
struct cfiled_list cfiled_head;
|
|
|
|
int
|
|
cap_p_open(cap_channel_t *chan, size_t filed_idx, const char *prog,
|
|
int *procdesc)
|
|
{
|
|
nvlist_t *nvl = nvlist_create(0);
|
|
int error, pipedesc_w;
|
|
|
|
nvlist_add_string(nvl, "cmd", "p_open");
|
|
nvlist_add_number(nvl, "filed_idx", filed_idx);
|
|
nvlist_add_string(nvl, "prog", prog);
|
|
nvl = cap_xfer_nvlist(chan, nvl);
|
|
if (nvl == NULL) {
|
|
logerror("Failed to xfer p_open nvlist");
|
|
exit(1);
|
|
}
|
|
error = nvlist_get_number(nvl, "error");
|
|
if (error != 0) {
|
|
errno = error;
|
|
logerror("Failed to open piped command");
|
|
}
|
|
pipedesc_w = dnvlist_take_descriptor(nvl, "pipedesc_w", -1);
|
|
*procdesc = dnvlist_take_descriptor(nvl, "procdesc", -1);
|
|
|
|
nvlist_destroy(nvl);
|
|
return (pipedesc_w);
|
|
}
|
|
|
|
int
|
|
casper_p_open(nvlist_t *nvlin, nvlist_t *nvlout)
|
|
{
|
|
struct cap_filed *cfiled;
|
|
size_t filed_idx;
|
|
int pipedesc_w, procdesc = -1;
|
|
const char *prog;
|
|
|
|
filed_idx = nvlist_get_number(nvlin, "filed_idx");
|
|
prog = nvlist_get_string(nvlin, "prog");
|
|
SLIST_FOREACH(cfiled, &cfiled_head, next) {
|
|
if (cfiled->idx != filed_idx)
|
|
continue;
|
|
if (strcmp(cfiled->pipe_cmd, prog) != 0)
|
|
return (-1);
|
|
|
|
pipedesc_w = p_open(prog, &procdesc);
|
|
if (pipedesc_w == -1)
|
|
return (-1);
|
|
nvlist_move_descriptor(nvlout, "pipedesc_w", pipedesc_w);
|
|
nvlist_move_descriptor(nvlout, "procdesc", procdesc);
|
|
return (0);
|
|
}
|
|
|
|
return (-1);
|
|
}
|
|
|
|
const char *
|
|
cap_ttymsg(cap_channel_t *chan, struct iovec *iov, int iovcnt,
|
|
const char *line, int tmout)
|
|
{
|
|
nvlist_t *nvl = nvlist_create(0);
|
|
int error;
|
|
static char errbuf[1024];
|
|
char *ret = NULL;
|
|
|
|
nvlist_add_string(nvl, "cmd", "ttymsg");
|
|
for (int i = 0; i < iovcnt; ++i)
|
|
nvlist_append_string_array(nvl, "iov_strs", iov[i].iov_base);
|
|
nvlist_add_string(nvl, "line", line);
|
|
nvlist_add_number(nvl, "tmout", tmout);
|
|
|
|
nvl = cap_xfer_nvlist(chan, nvl);
|
|
if (nvl == NULL) {
|
|
logerror("Failed to xfer ttymsg nvlist");
|
|
exit(1);
|
|
}
|
|
error = nvlist_get_number(nvl, "error");
|
|
if (error != 0) {
|
|
errno = error;
|
|
logerror("Failed to ttymsg");
|
|
}
|
|
if (nvlist_exists_string(nvl, "errstr")) {
|
|
const char *errstr = nvlist_get_string(nvl, "errstr");
|
|
(void)strlcpy(errbuf, errstr, sizeof(errbuf));
|
|
ret = errbuf;
|
|
}
|
|
|
|
nvlist_destroy(nvl);
|
|
return (ret);
|
|
}
|
|
|
|
int
|
|
casper_ttymsg(nvlist_t *nvlin, nvlist_t *nvlout)
|
|
{
|
|
char **nvlstrs;
|
|
struct iovec *iov;
|
|
size_t iovcnt;
|
|
int tmout;
|
|
const char *line;
|
|
|
|
nvlstrs = nvlist_take_string_array(nvlin, "iov_strs", &iovcnt);
|
|
assert(iovcnt <= TTYMSG_IOV_MAX);
|
|
iov = calloc(iovcnt, sizeof(*iov));
|
|
if (iov == NULL)
|
|
err(EXIT_FAILURE, "calloc");
|
|
for (size_t i = 0; i < iovcnt; ++i) {
|
|
iov[i].iov_base = nvlstrs[i];
|
|
iov[i].iov_len = strlen(nvlstrs[i]);
|
|
}
|
|
line = nvlist_get_string(nvlin, "line");
|
|
tmout = nvlist_get_number(nvlin, "tmout");
|
|
line = ttymsg(iov, iovcnt, line, tmout);
|
|
if (line != NULL)
|
|
nvlist_add_string(nvlout, "errstr", line);
|
|
|
|
free(iov);
|
|
return (0);
|
|
}
|
|
|
|
void
|
|
cap_wallmsg(cap_channel_t *chan, const struct filed *f, struct iovec *iov,
|
|
int iovcnt)
|
|
{
|
|
nvlist_t *nvl = nvlist_create(0);
|
|
int error;
|
|
|
|
nvlist_add_string(nvl, "cmd", "wallmsg");
|
|
/*
|
|
* The filed_to_nvlist() function is not needed
|
|
* here because wallmsg() only uses f_type and
|
|
* fu_uname members, which are both inline.
|
|
*/
|
|
nvlist_add_binary(nvl, "filed", f, sizeof(*f));
|
|
for (int i = 0; i < iovcnt; ++i)
|
|
nvlist_append_string_array(nvl, "iov_strs", iov[i].iov_base);
|
|
|
|
nvl = cap_xfer_nvlist(chan, nvl);
|
|
if (nvl == NULL) {
|
|
logerror("Failed to xfer wallmsg nvlist");
|
|
exit(1);
|
|
}
|
|
error = nvlist_get_number(nvl, "error");
|
|
if (error != 0) {
|
|
errno = error;
|
|
logerror("Failed to wallmsg");
|
|
}
|
|
nvlist_destroy(nvl);
|
|
}
|
|
|
|
int
|
|
casper_wallmsg(nvlist_t *nvlin)
|
|
{
|
|
const struct filed *f;
|
|
char **nvlstrs;
|
|
struct iovec *iov;
|
|
size_t sz;
|
|
|
|
f = nvlist_get_binary(nvlin, "filed", &sz);
|
|
assert(sz == sizeof(*f));
|
|
nvlstrs = nvlist_take_string_array(nvlin, "iov_strs", &sz);
|
|
assert(sz <= TTYMSG_IOV_MAX);
|
|
iov = calloc(sz, sizeof(*iov));
|
|
if (iov == NULL)
|
|
err(EXIT_FAILURE, "calloc");
|
|
for (size_t i = 0; i < sz; ++i) {
|
|
iov[i].iov_base = nvlstrs[i];
|
|
iov[i].iov_len = strlen(nvlstrs[i]);
|
|
}
|
|
wallmsg(f, iov, sz);
|
|
|
|
for (size_t i = 0; i < sz; ++i)
|
|
free(iov[i].iov_base);
|
|
free(iov);
|
|
return (0);
|
|
}
|