diff options
author | ailin-nemui <ailin-nemui@users.noreply.github.com> | 2017-11-26 00:31:01 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-11-26 00:31:01 +0100 |
commit | 466d074200e4893f57c4c716c746e8549af65339 (patch) | |
tree | dce2b3013e63b295c14af90d62f9acbd908c2ac7 /src/core | |
parent | 8dfeca57ede1e726de07522a87203ce13676882d (diff) | |
parent | 3792bc9ba95b8b9fd12ad60b86b8bbb06e913dc1 (diff) | |
download | irssi-466d074200e4893f57c4c716c746e8549af65339.zip |
Merge branch 'master' into hide-lines
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/Makefile.am | 7 | ||||
-rw-r--r-- | src/core/capsicum.c | 508 | ||||
-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 | 42 | ||||
-rw-r--r-- | src/core/network-openssl.h | 6 | ||||
-rw-r--r-- | src/core/network.c | 75 | ||||
-rw-r--r-- | src/core/network.h | 9 | ||||
-rw-r--r-- | src/core/rawlog.c | 19 | ||||
-rw-r--r-- | src/core/recode.c | 7 | ||||
-rw-r--r-- | src/core/settings.c | 10 | ||||
-rw-r--r-- | src/core/settings.h | 7 |
13 files changed, 676 insertions, 51 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..568b5542 --- /dev/null +++ b/src/core/capsicum.c @@ -0,0 +1,508 @@ +/* + 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/param.h> +#include <sys/capsicum.h> +#include <sys/filio.h> +#include <sys/nv.h> +#include <sys/procdesc.h> +#include <sys/socket.h> +#include <string.h> +#include <termios.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; + + /* The directory already exists, nothing to do. */ + if (strcmp(path, irclogs_path) == 0) + return; + + /* +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); +} + +/* + * The main difference between this and caph_limit_stdio(3) is that this + * one permits TIOCSETAW, which is requred for restoring the terminal state + * on exit. + */ +static int +limit_stdio_fd(int fd) +{ + cap_rights_t rights; + unsigned long cmds[] = { TIOCGETA, TIOCGWINSZ, TIOCSETAW, FIODTYPE }; + + cap_rights_init(&rights, CAP_READ, CAP_WRITE, CAP_EVENT, CAP_FCNTL, + CAP_FSTAT, CAP_IOCTL, CAP_SEEK); + + if (cap_rights_limit(fd, &rights) < 0) { + g_warning("cap_rights_limit(3) failed: %s", strerror(errno)); + return (-1); + } + + if (cap_ioctls_limit(fd, cmds, nitems(cmds)) < 0) { + g_warning("cap_ioctls_limit(3) failed: %s", strerror(errno)); + return (-1); + } + + if (cap_fcntls_limit(fd, CAP_FCNTL_GETFL) < 0) { + g_warning("cap_fcntls_limit(3) failed: %s", strerror(errno)); + return (-1); + } + + return (0); +} + +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; + } + + /* + * XXX: We should use pdwait(2) to wait for children. Unfortunately + * it's not implemented yet. Thus the workaround, to get rid + * of the zombies at least. + */ + signal(SIGCHLD, SIG_IGN); + + if (limit_stdio_fd(STDIN_FILENO) != 0 || + limit_stdio_fd(STDOUT_FILENO) != 0 || + limit_stdio_fd(STDERR_FILENO) != 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", 9999); + + 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..7ec902fb 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" @@ -44,6 +45,19 @@ #define ASN1_STRING_data(x) ASN1_STRING_get0_data(x) #endif +/* OpenSSL 1.1.0 also introduced some useful additions to the api */ +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined (LIBRESSL_VERSION_NUMBER) +static int X509_STORE_up_ref(X509_STORE *vfy) +{ + int n; + + n = CRYPTO_add(&vfy->references, 1, CRYPTO_LOCK_X509_STORE); + g_assert(n > 1); + + return (n > 1) ? 1 : 0; +} +#endif + /* ssl i/o channel object */ typedef struct { @@ -58,6 +72,7 @@ typedef struct } GIOSSLChannel; static int ssl_inited = FALSE; +static X509_STORE *store = NULL; static void irssi_ssl_free(GIOChannel *handle) { @@ -362,8 +377,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 +391,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 +522,12 @@ 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) { + /* Make sure to increment the refcount every time the store is + * used, that's essential not to get it free'd by OpenSSL when + * the SSL_CTX is destroyed. */ + X509_STORE_up_ref(store); + 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..d280b463 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> @@ -45,9 +48,6 @@ GIOChannel *g_io_channel_new(int handle) return chan; } -/* Cygwin need this, don't know others.. */ -/*#define BLOCKING_SOCKETS 1*/ - IPADDR ip4_any = { AF_INET, #if defined(IN6ADDR_ANY_INIT) @@ -110,42 +110,7 @@ static int sin_get_port(union sockaddr_union *so) so->sin.sin_port); } -/* Connect to socket */ -GIOChannel *net_connect(const char *addr, int port, IPADDR *my_ip) -{ - IPADDR ip4, ip6, *ip; - - g_return_val_if_fail(addr != NULL, NULL); - - if (net_gethostbyname(addr, &ip4, &ip6) == -1) - return NULL; - - if (my_ip == NULL) { - /* prefer IPv4 addresses */ - ip = ip4.family != 0 ? &ip4 : &ip6; - } else if (IPADDR_IS_V6(my_ip)) { - /* my_ip is IPv6 address, use it if possible */ - if (ip6.family != 0) - ip = &ip6; - else { - my_ip = NULL; - ip = &ip4; - } - } else { - /* my_ip is IPv4 address, use it if possible */ - if (ip4.family != 0) - ip = &ip4; - else { - my_ip = NULL; - ip = &ip6; - } - } - - 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 +126,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 +141,7 @@ GIOChannel *net_connect_ip(IPADDR *ip, int port, IPADDR *my_ip) close(handle); errno = old_errno; - return NULL; + return -1; } } @@ -190,9 +155,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 +368,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)); @@ -462,6 +452,7 @@ int net_gethostbyaddr(IPADDR *ip, char **name) int net_ip2host(IPADDR *ip, char *host) { + host[0] = '\0'; return inet_ntop(ip->family, &ip->ip, host, MAX_IP_LEN) ? 0 : -1; } diff --git a/src/core/network.h b/src/core/network.h index 8757f78c..e60f607f 100644 --- a/src/core/network.h +++ b/src/core/network.h @@ -33,11 +33,12 @@ extern IPADDR ip4_any; GIOChannel *g_io_channel_new(int handle); -/* returns 1 if IPADDRs are the same */ -int net_ip_compare(IPADDR *ip1, IPADDR *ip2); +/* Returns 1 if IPADDRs are the same. */ +/* Deprecated since it is unused. It will be deleted in a later release. */ +int net_ip_compare(IPADDR *ip1, IPADDR *ip2) G_GNUC_DEPRECATED; + +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*/ GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, IPADDR *my_ip, SERVER_REC *server); /* Start TLS */ 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/core/recode.c b/src/core/recode.c index d001a46a..d3fc91e7 100644 --- a/src/core/recode.c +++ b/src/core/recode.c @@ -198,7 +198,12 @@ char **recode_split(const SERVER_REC *server, const char *str, int n = 0; char **ret; - g_return_val_if_fail(str != NULL, NULL); + g_warn_if_fail(str != NULL); + if (str == NULL) { + ret = g_new(char *, 1); + ret[0] = NULL; + return ret; + } if (settings_get_bool("recode")) { to = find_conversion(server, target); diff --git a/src/core/settings.c b/src/core/settings.c index 4e0717cd..3ebb9e4a 100644 --- a/src/core/settings.c +++ b/src/core/settings.c @@ -39,6 +39,7 @@ static GString *last_errors; static GSList *last_invalid_modules; static int fe_initialized; static int config_changed; /* FIXME: remove after .98 (unless needed again) */ +static unsigned int user_settings_changed; static GHashTable *settings; static int timeout_tag; @@ -464,6 +465,11 @@ SETTINGS_REC *settings_get_record(const char *key) return g_hash_table_lookup(settings, key); } +static void sig_init_userinfo_changed(gpointer changedp) +{ + user_settings_changed |= GPOINTER_TO_UINT(changedp); +} + static void sig_init_finished(void) { fe_initialized = TRUE; @@ -479,6 +485,8 @@ static void sig_init_finished(void) "updated, please /SAVE"); signal_emit("setup changed", 0); } + + signal_emit("settings userinfo changed", 1, GUINT_TO_POINTER(user_settings_changed)); } static void settings_clean_invalid_module(const char *module) @@ -875,6 +883,7 @@ void settings_init(void) timeout_tag = g_timeout_add(SETTINGS_AUTOSAVE_TIMEOUT, (GSourceFunc) sig_autosave, NULL); signal_add("irssi init finished", (SIGNAL_FUNC) sig_init_finished); + signal_add("irssi init userinfo changed", (SIGNAL_FUNC) sig_init_userinfo_changed); signal_add("gui exit", (SIGNAL_FUNC) sig_autosave); } @@ -887,6 +896,7 @@ void settings_deinit(void) { g_source_remove(timeout_tag); signal_remove("irssi init finished", (SIGNAL_FUNC) sig_init_finished); + signal_remove("irssi init userinfo changed", (SIGNAL_FUNC) sig_init_userinfo_changed); signal_remove("gui exit", (SIGNAL_FUNC) sig_autosave); g_slist_foreach(last_invalid_modules, (GFunc) g_free, NULL); diff --git a/src/core/settings.h b/src/core/settings.h index d174f250..b67a9e44 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -30,6 +30,13 @@ typedef struct { char **choices; } SETTINGS_REC; +enum { + USER_SETTINGS_REAL_NAME = 0x1, + USER_SETTINGS_USER_NAME = 0x2, + USER_SETTINGS_NICK = 0x4, + USER_SETTINGS_HOSTNAME = 0x8, +}; + /* macros for handling the default Irssi configuration */ #define iconfig_get_str(a, b, c) config_get_str(mainconfig, a, b, c) #define iconfig_get_int(a, b, c) config_get_int(mainconfig, a, b, c) |