diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/core/Makefile.am | 7 | ||||
-rw-r--r-- | src/core/capsicum.c | 456 | ||||
-rw-r--r-- | src/core/capsicum.h | 15 | ||||
-rw-r--r-- | src/core/core.c | 9 | ||||
-rw-r--r-- | src/core/log.c | 13 | ||||
-rw-r--r-- | src/core/network-openssl.c | 25 | ||||
-rw-r--r-- | src/core/network-openssl.h | 6 | ||||
-rw-r--r-- | src/core/network.c | 37 | ||||
-rw-r--r-- | src/core/network.h | 2 | ||||
-rw-r--r-- | src/core/rawlog.c | 19 | ||||
-rw-r--r-- | src/fe-common/core/Makefile.am | 6 | ||||
-rw-r--r-- | src/fe-common/core/fe-capsicum.c | 63 | ||||
-rw-r--r-- | src/fe-common/core/fe-capsicum.h | 7 | ||||
-rw-r--r-- | src/fe-common/core/fe-common-core.c | 9 | ||||
-rw-r--r-- | src/fe-common/core/fe-core-commands.c | 14 | ||||
-rw-r--r-- | src/fe-common/core/fe-log.c | 7 | ||||
-rw-r--r-- | src/fe-common/core/module-formats.c | 3 | ||||
-rw-r--r-- | src/fe-common/core/module-formats.h | 3 |
18 files changed, 692 insertions, 9 deletions
diff --git a/src/core/Makefile.am b/src/core/Makefile.am index 91daba3f..f64d9e2e 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -56,6 +56,11 @@ libcore_a_SOURCES = \ tls.c \ write-buffer.c +if HAVE_CAPSICUM +libcore_a_SOURCES += \ + capsicum.c +endif + structure_headers = \ channel-rec.h \ channel-setup-rec.h \ @@ -69,6 +74,7 @@ structure_headers = \ pkginc_coredir=$(pkgincludedir)/src/core pkginc_core_HEADERS = \ args.h \ + capsicum.h \ channels.h \ channels-setup.h \ commands.h \ @@ -89,6 +95,7 @@ pkginc_core_HEADERS = \ net-nonblock.h \ net-sendbuffer.h \ network.h \ + network-openssl.h \ nick-rec.h \ nicklist.h \ nickmatch-cache.h \ diff --git a/src/core/capsicum.c b/src/core/capsicum.c new file mode 100644 index 00000000..79db780a --- /dev/null +++ b/src/core/capsicum.c @@ -0,0 +1,456 @@ +/* + capsicum.c : Capsicum sandboxing support + + Copyright (C) 2017 Edward Tomasz Napierala <trasz@FreeBSD.org> + + This software was developed by SRI International and the University of + Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237 + ("CTSRD"), as part of the DARPA CRASH research programme. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 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 General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "module.h" +#include "capsicum.h" +#include "commands.h" +#include "log.h" +#include "misc.h" +#include "network.h" +#include "network-openssl.h" +#include "settings.h" +#include "signals.h" + +#include <sys/types.h> +#include <sys/capsicum.h> +#include <sys/nv.h> +#include <sys/procdesc.h> +#include <sys/socket.h> +#include <string.h> + +#define OPCODE_CONNECT 1 +#define OPCODE_GETHOSTBYNAME 2 + +static char *irclogs_path; +static size_t irclogs_path_len; +static int irclogs_fd; +static int symbiontfds[2]; +static int port_min; +static int port_max; + +gboolean capsicum_enabled(void) +{ + u_int mode; + int error; + + error = cap_getmode(&mode); + if (error != 0) + return FALSE; + + if (mode == 0) + return FALSE; + + return TRUE; +} + +int capsicum_net_connect_ip(IPADDR *ip, int port, IPADDR *my_ip) +{ + nvlist_t *nvl; + int error, saved_errno, sock; + + /* Send request to the symbiont. */ + nvl = nvlist_create(0); + nvlist_add_number(nvl, "opcode", OPCODE_CONNECT); + nvlist_add_binary(nvl, "ip", ip, sizeof(*ip)); + nvlist_add_number(nvl, "port", port); + if (my_ip != NULL) { + /* nvlist_add_binary(3) can't handle NULL values. */ + nvlist_add_binary(nvl, "my_ip", my_ip, sizeof(*my_ip)); + } + error = nvlist_send(symbiontfds[1], nvl); + nvlist_destroy(nvl); + if (error != 0) { + g_warning("nvlist_send: %s", strerror(errno)); + return -1; + } + + /* Receive response. */ + nvl = nvlist_recv(symbiontfds[1], 0); + if (nvl == NULL) { + g_warning("nvlist_recv: %s", strerror(errno)); + return -1; + } + if (nvlist_exists_descriptor(nvl, "sock")) { + sock = nvlist_take_descriptor(nvl, "sock"); + } else { + sock = -1; + } + saved_errno = nvlist_get_number(nvl, "errno"); + nvlist_destroy(nvl); + + if (sock == -1 && (port < port_min || port > port_max)) { + g_warning("Access restricted to ports between %d and %d " + "due to capability mode", + port_min, port_max); + } + + errno = saved_errno; + + return sock; +} + +int capsicum_net_gethostbyname(const char *addr, IPADDR *ip4, IPADDR *ip6) +{ + nvlist_t *nvl; + const IPADDR *received_ip4, *received_ip6; + int error, ret, saved_errno; + + /* Send request to the symbiont. */ + nvl = nvlist_create(0); + nvlist_add_number(nvl, "opcode", OPCODE_GETHOSTBYNAME); + nvlist_add_string(nvl, "addr", addr); + error = nvlist_send(symbiontfds[1], nvl); + nvlist_destroy(nvl); + if (error != 0) { + g_warning("nvlist_send: %s", strerror(errno)); + return -1; + } + + /* Receive response. */ + nvl = nvlist_recv(symbiontfds[1], 0); + if (nvl == NULL) { + g_warning("nvlist_recv: %s", strerror(errno)); + return -1; + } + + received_ip4 = nvlist_get_binary(nvl, "ip4", NULL); + received_ip6 = nvlist_get_binary(nvl, "ip6", NULL); + memcpy(ip4, received_ip4, sizeof(*ip4)); + memcpy(ip6, received_ip6, sizeof(*ip6)); + + ret = nvlist_get_number(nvl, "ret"); + saved_errno = nvlist_get_number(nvl, "errno"); + nvlist_destroy(nvl); + errno = saved_errno; + + return ret; +} + +int capsicum_open(const char *path, int flags, int mode) +{ + int fd; + + /* +1 is for the slash separating irclogs_path and the rest. */ + if (strlen(path) > irclogs_path_len + 1 && + path[irclogs_path_len] == '/' && + strncmp(path, irclogs_path, irclogs_path_len) == 0) { + fd = openat(irclogs_fd, path + irclogs_path_len + 1, + flags, mode); + } else { + fd = open(path, flags, mode); + } + + if (fd < 0 && (errno == ENOTCAPABLE || errno == ECAPMODE)) + g_warning("File system access restricted to %s " + "due to capability mode", irclogs_path); + + return (fd); +} + +int capsicum_open_wrapper(const char *path, int flags, int mode) +{ + if (capsicum_enabled()) { + return capsicum_open(path, flags, mode); + } + return open(path, flags, mode); +} + +void capsicum_mkdir_with_parents(const char *path, int mode) +{ + char *component, *copy, *tofree; + int error, fd, newfd; + + /* +1 is for the slash separating irclogs_path and the rest. */ + if (strlen(path) <= irclogs_path_len + 1 || + path[irclogs_path_len] != '/' || + strncmp(path, irclogs_path, irclogs_path_len) != 0) { + g_warning("Cannot create %s: file system access restricted " + "to %s due to capability mode", path, irclogs_path); + return; + } + + copy = tofree = g_strdup(path + irclogs_path_len + 1); + fd = irclogs_fd; + for (;;) { + component = strsep(©, "/"); + if (component == NULL) + break; + error = mkdirat(fd, component, mode); + if (error != 0 && errno != EEXIST) { + g_warning("cannot create %s: %s", + component, strerror(errno)); + break; + } + newfd = openat(fd, component, O_DIRECTORY); + if (newfd < 0) { + g_warning("cannot open %s: %s", + component, strerror(errno)); + break; + } + if (fd != irclogs_fd) + close(fd); + fd = newfd; + } + g_free(tofree); + if (fd != irclogs_fd) + close(fd); +} + +void capsicum_mkdir_with_parents_wrapper(const char *path, int mode) +{ + if (capsicum_enabled()) { + capsicum_mkdir_with_parents(path, mode); + return; + } + g_mkdir_with_parents(path, mode); +} + +nvlist_t *symbiont_connect(const nvlist_t *request) +{ + nvlist_t *response; + const IPADDR *ip, *my_ip; + int port, saved_errno, sock; + + ip = nvlist_get_binary(request, "ip", NULL); + port = (int)nvlist_get_number(request, "port"); + if (nvlist_exists(request, "my_ip")) + my_ip = nvlist_get_binary(request, "my_ip", NULL); + else + my_ip = NULL; + + /* + * Check if the port is in allowed range. This is to minimize + * the chance of the attacker rooting another system in case of + * compromise. + */ + if (port < port_min || port > port_max) { + sock = -1; + saved_errno = EPERM; + } else { + /* Connect. */ + sock = net_connect_ip_handle(ip, port, my_ip); + saved_errno = errno; + } + + /* Send back the socket fd. */ + response = nvlist_create(0); + + if (sock != -1) + nvlist_move_descriptor(response, "sock", sock); + nvlist_add_number(response, "errno", saved_errno); + + return (response); +} + +nvlist_t *symbiont_gethostbyname(const nvlist_t *request) +{ + nvlist_t *response; + IPADDR ip4, ip6; + const char *addr; + int ret, saved_errno; + + addr = nvlist_get_string(request, "addr"); + + /* Connect. */ + ret = net_gethostbyname(addr, &ip4, &ip6); + saved_errno = errno; + + /* Send back the IPs. */ + response = nvlist_create(0); + + nvlist_add_number(response, "ret", ret); + nvlist_add_number(response, "errno", saved_errno); + nvlist_add_binary(response, "ip4", &ip4, sizeof(ip4)); + nvlist_add_binary(response, "ip6", &ip6, sizeof(ip6)); + + return (response); +} + +/* + * Child process, running outside the Capsicum sandbox. + */ +_Noreturn static void symbiont(void) +{ + nvlist_t *request, *response; + int error, opcode; + + setproctitle("capsicum symbiont"); + close(symbiontfds[1]); + close(0); + close(1); + close(2); + + for (;;) { + /* Receive parameters from the main irssi process. */ + request = nvlist_recv(symbiontfds[0], 0); + if (request == NULL) + exit(1); + + opcode = nvlist_get_number(request, "opcode"); + switch (opcode) { + case OPCODE_CONNECT: + response = symbiont_connect(request); + break; + case OPCODE_GETHOSTBYNAME: + response = symbiont_gethostbyname(request); + break; + default: + exit(1); + } + + /* Send back the response. */ + error = nvlist_send(symbiontfds[0], response); + if (error != 0) + exit(1); + nvlist_destroy(request); + nvlist_destroy(response); + } +} + +static int start_symbiont(void) +{ + int childfd, error; + pid_t pid; + + error = socketpair(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, symbiontfds); + if (error != 0) { + g_warning("socketpair: %s", strerror(errno)); + return 1; + } + + pid = pdfork(&childfd, PD_CLOEXEC); + if (pid < 0) { + g_warning("pdfork: %s", strerror(errno)); + return 1; + } + + if (pid > 0) { + close(symbiontfds[0]); + return 0; + } + + symbiont(); + /* NOTREACHED */ +} + +static void cmd_capsicum(const char *data, SERVER_REC *server, void *item) +{ + command_runsub("capsicum", data, server, item); +} + +static void cmd_capsicum_enter(void) +{ + u_int mode; + gboolean inited; + int error; + + error = cap_getmode(&mode); + if (error == 0 && mode != 0) { + g_warning("Already in capability mode"); + return; + } + + inited = irssi_ssl_init(); + if (!inited) { + signal_emit("capability mode failed", 1, strerror(errno)); + return; + } + + port_min = settings_get_int("capsicum_port_min"); + port_max = settings_get_int("capsicum_port_max"); + + irclogs_path = convert_home(settings_get_str("capsicum_irclogs_path")); + irclogs_path_len = strlen(irclogs_path); + + /* Strip trailing slashes, if any. */ + while (irclogs_path_len > 0 && irclogs_path[irclogs_path_len - 1] == '/') { + irclogs_path[irclogs_path_len - 1] = '\0'; + irclogs_path_len--; + } + + g_mkdir_with_parents(irclogs_path, log_dir_create_mode); + irclogs_fd = open(irclogs_path, O_DIRECTORY | O_CLOEXEC); + if (irclogs_fd < 0) { + g_warning("Unable to open %s: %s", irclogs_path, strerror(errno)); + signal_emit("capability mode failed", 1, strerror(errno)); + return; + } + + error = start_symbiont(); + if (error != 0) { + signal_emit("capability mode failed", 1, strerror(errno)); + return; + } + + error = cap_enter(); + if (error != 0) { + signal_emit("capability mode failed", 1, strerror(errno)); + } else { + signal_emit("capability mode enabled", 0); + } +} + +static void cmd_capsicum_status(void) +{ + u_int mode; + int error; + + error = cap_getmode(&mode); + if (error != 0) { + signal_emit("capability mode failed", 1, strerror(errno)); + } else if (mode == 0) { + signal_emit("capability mode disabled", 0); + } else { + signal_emit("capability mode enabled", 0); + } +} + +void sig_init_finished(void) +{ + if (settings_get_bool("capsicum")) + cmd_capsicum_enter(); +} + +void capsicum_init(void) +{ + settings_add_bool("misc", "capsicum", FALSE); + settings_add_str("misc", "capsicum_irclogs_path", "~/irclogs"); + settings_add_int("misc", "capsicum_port_min", 6667); + settings_add_int("misc", "capsicum_port_max", 6697); + + signal_add("irssi init finished", (SIGNAL_FUNC) sig_init_finished); + + command_bind("capsicum", NULL, (SIGNAL_FUNC) cmd_capsicum); + command_bind("capsicum enter", NULL, (SIGNAL_FUNC) cmd_capsicum_enter); + command_bind("capsicum status", NULL, (SIGNAL_FUNC) cmd_capsicum_status); +} + +void capsicum_deinit(void) +{ + signal_remove("irssi init finished", (SIGNAL_FUNC) sig_init_finished); + + command_unbind("capsicum", (SIGNAL_FUNC) cmd_capsicum); + command_unbind("capsicum enter", (SIGNAL_FUNC) cmd_capsicum_enter); + command_unbind("capsicum status", (SIGNAL_FUNC) cmd_capsicum_status); +} diff --git a/src/core/capsicum.h b/src/core/capsicum.h new file mode 100644 index 00000000..7d89f2aa --- /dev/null +++ b/src/core/capsicum.h @@ -0,0 +1,15 @@ +#ifndef __CAPSICUM_H +#define __CAPSICUM_H + +gboolean capsicum_enabled(void); +int capsicum_net_connect_ip(IPADDR *ip, int port, IPADDR *my_ip); +int capsicum_net_gethostbyname(const char *addr, IPADDR *ip4, IPADDR *ip6); +int capsicum_open(const char *path, int flags, int mode); +int capsicum_open_wrapper(const char *path, int flags, int mode); +void capsicum_mkdir_with_parents(const char *path, int mode); +void capsicum_mkdir_with_parents_wrapper(const char *path, int mode); + +void capsicum_init(void); +void capsicum_deinit(void); + +#endif /* !__CAPSICUM_H */ diff --git a/src/core/core.c b/src/core/core.c index bf7cdd6b..506d6a13 100644 --- a/src/core/core.c +++ b/src/core/core.c @@ -29,6 +29,9 @@ #include "signals.h" #include "settings.h" #include "session.h" +#ifdef HAVE_CAPSICUM +#include "capsicum.h" +#endif #include "chat-protocols.h" #include "servers.h" @@ -235,6 +238,9 @@ void core_init(void) commands_init(); nickmatch_cache_init(); session_init(); +#ifdef HAVE_CAPSICUM + capsicum_init(); +#endif chat_protocols_init(); chatnets_init(); @@ -292,6 +298,9 @@ void core_deinit(void) chatnets_deinit(); chat_protocols_deinit(); +#ifdef HAVE_CAPSICUM + capsicum_deinit(); +#endif session_deinit(); nickmatch_cache_deinit(); commands_deinit(); diff --git a/src/core/log.c b/src/core/log.c index cee1dab5..f7741d3d 100644 --- a/src/core/log.c +++ b/src/core/log.c @@ -26,6 +26,9 @@ #include "servers.h" #include "log.h" #include "write-buffer.h" +#ifdef HAVE_CAPSICUM +#include "capsicum.h" +#endif #include "lib-config/iconfig.h" #include "settings.h" @@ -114,13 +117,23 @@ int log_start_logging(LOG_REC *log) /* path may contain variables (%time, $vars), make sure the directory is created */ dir = g_path_get_dirname(log->real_fname); +#ifdef HAVE_CAPSICUM + capsicum_mkdir_with_parents_wrapper(dir, log_dir_create_mode); +#else g_mkdir_with_parents(dir, log_dir_create_mode); +#endif g_free(dir); } +#ifdef HAVE_CAPSICUM + log->handle = log->real_fname == NULL ? -1 : + capsicum_open_wrapper(log->real_fname, O_WRONLY | O_APPEND | O_CREAT, + log_file_create_mode); +#else log->handle = log->real_fname == NULL ? -1 : open(log->real_fname, O_WRONLY | O_APPEND | O_CREAT, log_file_create_mode); +#endif if (log->handle == -1) { signal_emit("log create failed", 1, log); log->failed = TRUE; diff --git a/src/core/network-openssl.c b/src/core/network-openssl.c index 4de3cb3c..2054f28a 100644 --- a/src/core/network-openssl.c +++ b/src/core/network-openssl.c @@ -20,6 +20,7 @@ #include "module.h" #include "network.h" +#include "network-openssl.h" #include "net-sendbuffer.h" #include "misc.h" #include "servers.h" @@ -58,6 +59,7 @@ typedef struct } GIOSSLChannel; static int ssl_inited = FALSE; +static X509_STORE *store = NULL; static void irssi_ssl_free(GIOChannel *handle) { @@ -362,8 +364,10 @@ static GIOFuncs irssi_ssl_channel_funcs = { irssi_ssl_get_flags }; -static gboolean irssi_ssl_init(void) +gboolean irssi_ssl_init(void) { + int success; + #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER) if (!OPENSSL_init_ssl(OPENSSL_INIT_SSL_DEFAULT, NULL)) { g_error("Could not initialize OpenSSL"); @@ -374,6 +378,20 @@ static gboolean irssi_ssl_init(void) SSL_load_error_strings(); OpenSSL_add_all_algorithms(); #endif + store = X509_STORE_new(); + if (store == NULL) { + g_error("Could not initialize OpenSSL: X509_STORE_new() failed"); + return FALSE; + } + + success = X509_STORE_set_default_paths(store); + if (success == 0) { + g_warning("Could not load default certificates"); + X509_STORE_free(store); + store = NULL; + /* Don't return an error; the user might have their own cafile/capath. */ + } + ssl_inited = TRUE; return TRUE; @@ -491,9 +509,8 @@ static GIOChannel *irssi_ssl_get_iochannel(GIOChannel *handle, int port, SERVER_ g_free(scafile); g_free(scapath); verify = TRUE; - } else { - if (!SSL_CTX_set_default_verify_paths(ctx)) - g_warning("Could not load default certificates"); + } else if (store != NULL) { + SSL_CTX_set_cert_store(ctx, store); } if(!(ssl = SSL_new(ctx))) diff --git a/src/core/network-openssl.h b/src/core/network-openssl.h new file mode 100644 index 00000000..4cd6d711 --- /dev/null +++ b/src/core/network-openssl.h @@ -0,0 +1,6 @@ +#ifndef __NETWORK_OPENSSL_H +#define __NETWORK_OPENSSL_H + +gboolean irssi_ssl_init(void); + +#endif /* !__NETWORK_OPENSSL_H */ diff --git a/src/core/network.c b/src/core/network.c index 3e1b7c70..4494dbc6 100644 --- a/src/core/network.c +++ b/src/core/network.c @@ -20,6 +20,9 @@ #include "module.h" #include "network.h" +#ifdef HAVE_CAPSICUM +#include "capsicum.h" +#endif #include <sys/un.h> @@ -144,8 +147,7 @@ GIOChannel *net_connect(const char *addr, int port, IPADDR *my_ip) return net_connect_ip(ip, port, my_ip); } -/* Connect to socket with ip address */ -GIOChannel *net_connect_ip(IPADDR *ip, int port, IPADDR *my_ip) +int net_connect_ip_handle(const IPADDR *ip, int port, const IPADDR *my_ip) { union sockaddr_union so; int handle, ret, opt = 1; @@ -161,7 +163,7 @@ GIOChannel *net_connect_ip(IPADDR *ip, int port, IPADDR *my_ip) handle = socket(ip->family, SOCK_STREAM, 0); if (handle == -1) - return NULL; + return -1; /* set socket options */ fcntl(handle, F_SETFL, O_NONBLOCK); @@ -176,7 +178,7 @@ GIOChannel *net_connect_ip(IPADDR *ip, int port, IPADDR *my_ip) close(handle); errno = old_errno; - return NULL; + return -1; } } @@ -190,9 +192,29 @@ GIOChannel *net_connect_ip(IPADDR *ip, int port, IPADDR *my_ip) int old_errno = errno; close(handle); errno = old_errno; - return NULL; + return -1; } + return handle; +} + +/* Connect to socket with ip address */ +GIOChannel *net_connect_ip(IPADDR *ip, int port, IPADDR *my_ip) +{ + int handle = -1; + +#ifdef HAVE_CAPSICUM + if (capsicum_enabled()) + handle = capsicum_net_connect_ip(ip, port, my_ip); + else + handle = net_connect_ip_handle(ip, port, my_ip); +#else + handle = net_connect_ip_handle(ip, port, my_ip); +#endif + + if (handle == -1) + return (NULL); + return g_io_channel_new(handle); } @@ -383,6 +405,11 @@ int net_gethostbyname(const char *addr, IPADDR *ip4, IPADDR *ip6) struct addrinfo hints, *ai, *ailist; int ret, count_v4, count_v6, use_v4, use_v6; +#ifdef HAVE_CAPSICUM + if (capsicum_enabled()) + return (capsicum_net_gethostbyname(addr, ip4, ip6)); +#endif + g_return_val_if_fail(addr != NULL, -1); memset(ip4, 0, sizeof(IPADDR)); diff --git a/src/core/network.h b/src/core/network.h index 8757f78c..d1582a2e 100644 --- a/src/core/network.h +++ b/src/core/network.h @@ -36,6 +36,8 @@ GIOChannel *g_io_channel_new(int handle); /* returns 1 if IPADDRs are the same */ int net_ip_compare(IPADDR *ip1, IPADDR *ip2); +int net_connect_ip_handle(const IPADDR *ip, int port, const IPADDR *my_ip); + /* Connect to socket */ GIOChannel *net_connect(const char *addr, int port, IPADDR *my_ip) G_GNUC_DEPRECATED; /* Connect to socket with ip address and SSL*/ diff --git a/src/core/rawlog.c b/src/core/rawlog.c index 2ec155fa..fdd51241 100644 --- a/src/core/rawlog.c +++ b/src/core/rawlog.c @@ -27,6 +27,9 @@ #include "misc.h" #include "write-buffer.h" #include "settings.h" +#ifdef HAVE_CAPSICUM +#include "capsicum.h" +#endif #include "servers.h" @@ -126,8 +129,15 @@ void rawlog_open(RAWLOG_REC *rawlog, const char *fname) return; path = convert_home(fname); +#ifdef HAVE_CAPSICUM + rawlog->handle = capsicum_open_wrapper(path, + O_WRONLY | O_APPEND | O_CREAT, + log_file_create_mode); +#else rawlog->handle = open(path, O_WRONLY | O_APPEND | O_CREAT, log_file_create_mode); +#endif + g_free(path); if (rawlog->handle == -1) { @@ -154,11 +164,20 @@ void rawlog_save(RAWLOG_REC *rawlog, const char *fname) int f; dir = g_path_get_dirname(fname); +#ifdef HAVE_CAPSICUM + capsicum_mkdir_with_parents_wrapper(dir, log_dir_create_mode); +#else g_mkdir_with_parents(dir, log_dir_create_mode); +#endif g_free(dir); path = convert_home(fname); +#ifdef HAVE_CAPSICUM + f = capsicum_open_wrapper(path, O_WRONLY | O_APPEND | O_CREAT, + log_file_create_mode); +#else f = open(path, O_WRONLY | O_APPEND | O_CREAT, log_file_create_mode); +#endif g_free(path); if (f < 0) { diff --git a/src/fe-common/core/Makefile.am b/src/fe-common/core/Makefile.am index 6efff411..29cc941a 100644 --- a/src/fe-common/core/Makefile.am +++ b/src/fe-common/core/Makefile.am @@ -38,11 +38,17 @@ libfe_common_core_a_SOURCES = \ windows-layout.c \ fe-windows.c +if HAVE_CAPSICUM +libfe_common_core_a_SOURCES += \ + fe-capsicum.c +endif + pkginc_fe_common_coredir=$(pkgincludedir)/src/fe-common/core pkginc_fe_common_core_HEADERS = \ command-history.h \ chat-completion.h \ completion.h \ + fe-capsicum.h \ fe-channels.h \ fe-common-core.h \ fe-core-commands.h \ diff --git a/src/fe-common/core/fe-capsicum.c b/src/fe-common/core/fe-capsicum.c new file mode 100644 index 00000000..54a43d27 --- /dev/null +++ b/src/fe-common/core/fe-capsicum.c @@ -0,0 +1,63 @@ +/* + fe-capsicum.c : irssi + + Copyright (C) 2017 Edward Tomasz Napierala <trasz@FreeBSD.org> + + This software was developed by SRI International and the University of + Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237 + ("CTSRD"), as part of the DARPA CRASH research programme. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 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 General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "module.h" +#include "fe-capsicum.h" +#include "levels.h" +#include "module-formats.h" +#include "printtext.h" +#include "signals.h" + +static void capability_mode_enabled(void) +{ + + printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_CAPSICUM_ENABLED); +} + +static void capability_mode_disabled(void) +{ + + printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_CAPSICUM_DISABLED); +} + +static void capability_mode_failed(gchar *msg) +{ + + printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, TXT_CAPSICUM_FAILED, msg); +} + +void fe_capsicum_init(void) +{ + + signal_add("capability mode enabled", (SIGNAL_FUNC) capability_mode_enabled); + signal_add("capability mode disabled", (SIGNAL_FUNC) capability_mode_disabled); + signal_add("capability mode failed", (SIGNAL_FUNC) capability_mode_failed); +} + +void fe_capsicum_deinit(void) +{ + signal_remove("capability mode enabled", (SIGNAL_FUNC) capability_mode_enabled); + signal_remove("capability mode disabled", (SIGNAL_FUNC) capability_mode_disabled); + signal_remove("capability mode failed", (SIGNAL_FUNC) capability_mode_failed); +} diff --git a/src/fe-common/core/fe-capsicum.h b/src/fe-common/core/fe-capsicum.h new file mode 100644 index 00000000..a7cb743b --- /dev/null +++ b/src/fe-common/core/fe-capsicum.h @@ -0,0 +1,7 @@ +#ifndef __FE_CAPSICUM_H +#define __FE_CAPSICUM_H + +void fe_capsicum_init(void); +void fe_capsicum_deinit(void); + +#endif diff --git a/src/fe-common/core/fe-common-core.c b/src/fe-common/core/fe-common-core.c index 512fc84c..a3b7364c 100644 --- a/src/fe-common/core/fe-common-core.c +++ b/src/fe-common/core/fe-common-core.c @@ -32,6 +32,9 @@ #include "special-vars.h" #include "fe-core-commands.h" #include "fe-queries.h" +#ifdef HAVE_CAPSICUM +#include "fe-capsicum.h" +#endif #include "hilight-text.h" #include "command-history.h" #include "completion.h" @@ -179,6 +182,9 @@ void fe_common_core_init(void) fe_server_init(); fe_settings_init(); fe_tls_init(); +#ifdef HAVE_CAPSICUM + fe_capsicum_init(); +#endif windows_init(); window_activity_init(); window_commands_init(); @@ -221,6 +227,9 @@ void fe_common_core_deinit(void) fe_server_deinit(); fe_settings_deinit(); fe_tls_deinit(); +#ifdef HAVE_CAPSICUM + fe_capsicum_deinit(); +#endif windows_deinit(); window_activity_deinit(); window_commands_deinit(); diff --git a/src/fe-common/core/fe-core-commands.c b/src/fe-common/core/fe-core-commands.c index 97a246ec..fb98cc25 100644 --- a/src/fe-common/core/fe-core-commands.c +++ b/src/fe-common/core/fe-core-commands.c @@ -28,6 +28,9 @@ #include "settings.h" #include "irssi-version.h" #include "servers.h" +#ifdef HAVE_CAPSICUM +#include "capsicum.h" +#endif #include "fe-windows.h" #include "printtext.h" @@ -120,6 +123,9 @@ static void cmd_cat(const char *data) GIOChannel *handle; GString *buf; gsize tpos; +#ifdef HAVE_CAPSICUM + int fd; +#endif if (!cmd_get_params(data, &free_arg, 2, &fname, &fposstr)) return; @@ -128,7 +134,15 @@ static void cmd_cat(const char *data) fpos = atoi(fposstr); cmd_params_free(free_arg); +#ifdef HAVE_CAPSICUM + fd = capsicum_open_wrapper(fname, O_RDONLY, 0); + if (fd > 0) + handle = g_io_channel_unix_new(fd); + else + handle = NULL; +#else handle = g_io_channel_new_file(fname, "r", NULL); +#endif g_free(fname); if (handle == NULL) { diff --git a/src/fe-common/core/fe-log.c b/src/fe-common/core/fe-log.c index 37b29990..0fed8642 100644 --- a/src/fe-common/core/fe-log.c +++ b/src/fe-common/core/fe-log.c @@ -30,6 +30,9 @@ #include "special-vars.h" #include "settings.h" #include "lib-config/iconfig.h" +#ifdef HAVE_CAPSICUM +#include "capsicum.h" +#endif #include "fe-windows.h" #include "window-items.h" @@ -451,7 +454,11 @@ static void autolog_open(SERVER_REC *server, const char *server_tag, log_item_add(log, LOG_ITEM_TARGET, target, server_tag); dir = g_path_get_dirname(log->real_fname); +#ifdef HAVE_CAPSICUM + capsicum_mkdir_with_parents_wrapper(dir, log_dir_create_mode); +#else g_mkdir_with_parents(dir, log_dir_create_mode); +#endif g_free(dir); log->temp = TRUE; diff --git a/src/fe-common/core/module-formats.c b/src/fe-common/core/module-formats.c index da9705be..eb0ddb61 100644 --- a/src/fe-common/core/module-formats.c +++ b/src/fe-common/core/module-formats.c @@ -290,6 +290,9 @@ FORMAT_REC fecommon_core_formats[] = { { "completion_header", "%#Key Value Auto", 0 }, { "completion_line", "%#$[10]0 $[!40]1 $2", 3, { 0, 0, 0 } }, { "completion_footer", "", 0 }, + { "capsicum_enabled", "Capability mode enabled", 0 }, + { "capsicum_disabled", "Capability mode not enabled", 0 }, + { "capsicum_failed", "Capability mode failed: $0", 1, { 0 } }, /* ---- */ { NULL, "TLS", 0 }, diff --git a/src/fe-common/core/module-formats.h b/src/fe-common/core/module-formats.h index f361befb..97ac60bb 100644 --- a/src/fe-common/core/module-formats.h +++ b/src/fe-common/core/module-formats.h @@ -255,6 +255,9 @@ enum { TXT_COMPLETION_HEADER, TXT_COMPLETION_LINE, TXT_COMPLETION_FOOTER, + TXT_CAPSICUM_ENABLED, + TXT_CAPSICUM_DISABLED, + TXT_CAPSICUM_FAILED, TLS_FILL_15, |