summaryrefslogtreecommitdiffstats
path: root/watchquagga
diff options
context:
space:
mode:
authorDavid Lamparter <equinox@opensourcerouting.org>2016-11-09 14:15:34 +0100
committerDavid Lamparter <equinox@opensourcerouting.org>2016-11-09 14:29:39 +0100
commit95c4aff294f6c1bf1450cbebc4133cad3560dfc9 (patch)
tree38656626e6a4b3ff2d7edb80cffe31162fa6d3d9 /watchquagga
parentwatchquagga: add ZLOG_WATCHQUAGGA (diff)
downloadfrr-95c4aff294f6c1bf1450cbebc4133cad3560dfc9.tar.xz
frr-95c4aff294f6c1bf1450cbebc4133cad3560dfc9.zip
watchquagga: add "write integrated"
This new command - available for internal use by vtysh and explicit usage by users - calls "vtysh -w" from watchquagga. This ensures vtysh is run with privileges to actually write the integrated-config file. Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
Diffstat (limited to 'watchquagga')
-rw-r--r--watchquagga/Makefile.am4
-rw-r--r--watchquagga/watchquagga.c29
-rw-r--r--watchquagga/watchquagga.h29
-rw-r--r--watchquagga/watchquagga_vty.c128
4 files changed, 187 insertions, 3 deletions
diff --git a/watchquagga/Makefile.am b/watchquagga/Makefile.am
index 1f05f26ce..43f743eba 100644
--- a/watchquagga/Makefile.am
+++ b/watchquagga/Makefile.am
@@ -7,5 +7,7 @@ AM_CFLAGS = $(WERROR)
sbin_PROGRAMS = watchquagga
-watchquagga_SOURCES = watchquagga.c
+noinst_HEADERS = watchquagga.h
+
+watchquagga_SOURCES = watchquagga.c watchquagga_vty.c
watchquagga_LDADD = ../lib/libzebra.la @LIBCAP@
diff --git a/watchquagga/watchquagga.c b/watchquagga/watchquagga.c
index aa5d1bcd8..70b35f775 100644
--- a/watchquagga/watchquagga.c
+++ b/watchquagga/watchquagga.c
@@ -24,12 +24,16 @@
#include <network.h>
#include <sigevent.h>
#include <lib/version.h>
+#include "command.h"
+
#include <getopt.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <memory.h>
#include <systemd.h>
+#include "watchquagga.h"
+
#ifndef MIN
#define MIN(X,Y) (((X) <= (Y)) ? (X) : (Y))
#endif
@@ -437,6 +441,12 @@ sigchild(void)
return;
}
+ if (child == integrated_write_pid)
+ {
+ integrated_write_sigchld(status);
+ return;
+ }
+
if ((restart = find_child(child)) != NULL)
{
name = restart->name;
@@ -775,9 +785,9 @@ try_connect(struct daemon *dmn)
return -1;
}
- if (set_nonblocking(sock) < 0)
+ if (set_nonblocking(sock) < 0 || set_cloexec(sock) < 0)
{
- zlog_err("%s(%s): set_nonblocking(%d) failed",
+ zlog_err("%s(%s): set_nonblocking/cloexec(%d) failed",
__func__, addr.sun_path, sock);
close(sock);
return -1;
@@ -1028,6 +1038,13 @@ translate_blanks(const char *cmd, const char *blankstr)
return res;
}
+struct zebra_privs_t watchquagga_privs =
+{
+#ifdef VTY_GROUP
+ .vty_group = VTY_GROUP,
+#endif
+};
+
int
main(int argc, char **argv)
{
@@ -1283,7 +1300,15 @@ main(int argc, char **argv)
}
gs.restart.interval = gs.min_restart_interval;
+
+ zprivs_init (&watchquagga_privs);
+
master = thread_master_create();
+ cmd_init(1);
+ vty_init(master);
+ watchquagga_vty_init();
+ vty_serv_sock(NULL, 0, WATCHQUAGGA_VTYSH_PATH);
+
systemd_send_started (master, 0);
signal_init (master, array_size(my_signals), my_signals);
srandom(time(NULL));
diff --git a/watchquagga/watchquagga.h b/watchquagga/watchquagga.h
new file mode 100644
index 000000000..ecadf22c5
--- /dev/null
+++ b/watchquagga/watchquagga.h
@@ -0,0 +1,29 @@
+/*
+ Common definitions for watchquagga API socket.
+
+ Copyright (C) 2016 David Lamparter for NetDEF, Inc.
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef QUAGGA_WATCHQUAGGA_H
+#define QUAGGA_WATCHQUAGGA_H
+
+extern void watchquagga_vty_init(void);
+
+extern pid_t integrated_write_pid;
+extern void integrated_write_sigchld(int status);
+
+#endif /* QUAGGA_WATCHQUAGGA_H */
diff --git a/watchquagga/watchquagga_vty.c b/watchquagga/watchquagga_vty.c
new file mode 100644
index 000000000..bf413376a
--- /dev/null
+++ b/watchquagga/watchquagga_vty.c
@@ -0,0 +1,128 @@
+/*
+ watchquagga CLI functions.
+
+ Copyright (C) 2016 David Lamparter for NetDEF, Inc.
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <zebra.h>
+#include <sys/wait.h>
+
+#include "memory.h"
+#include "log.h"
+#include "vty.h"
+#include "command.h"
+
+#include "watchquagga.h"
+
+pid_t integrated_write_pid;
+static int integrated_result_fd;
+
+DEFUN (config_write_integrated,
+ config_write_integrated_cmd,
+ "write integrated",
+ "Write running configuration to memory, network, or terminal\n"
+ "Write integrated all-daemon Quagga.conf file\n")
+{
+ pid_t child;
+ sigset_t oldmask, sigmask;
+
+ if (integrated_write_pid != -1) {
+ vty_out(vty, "%% configuration write already in progress.%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ fflush(stdout);
+ fflush(stderr);
+
+ /* need to temporarily block SIGCHLD because it could arrive between
+ * fork() call and setting the integrated_write_pid variable. This
+ * would mean the completion call gets lost and this hangs forever.
+ */
+ sigemptyset(&oldmask);
+ sigemptyset(&sigmask);
+ sigaddset(&sigmask, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &sigmask, &oldmask);
+
+ child = fork();
+ if (child == -1) {
+ vty_out(vty, "%% configuration write fork() failed: %s.%s",
+ safe_strerror(errno), VTY_NEWLINE);
+ sigprocmask(SIG_SETMASK, &oldmask, NULL);
+ return CMD_WARNING;
+ }
+ if (child != 0) {
+ /* note: the VTY won't write a command return value to vtysh; the
+ * session temporarily enters an intentional "hang" state. This is
+ * to make sure latency in vtysh doing the config write (several
+ * seconds is not rare to see) does not interfere with watchquagga's
+ * supervisor job.
+ *
+ * The fd is duplicated here so we don't need to hold a vty pointer
+ * (which could become invalid in the meantime).
+ */
+ integrated_write_pid = child;
+ integrated_result_fd = dup(vty->wfd);
+ sigprocmask(SIG_SETMASK, &oldmask, NULL);
+ return CMD_SUSPEND;
+ }
+
+ /* redirect stdout/stderr to vty session. Note vty->wfd is marked
+ * CLOEXEC, but dup2 will clear that flag. */
+ dup2(vty->wfd, 1);
+ dup2(vty->wfd, 2);
+
+ /* don't allow the user to pass parameters, we're root here!
+ * should probably harden vtysh at some point too... */
+ execl(VTYSH_BIN_PATH, "vtysh", "-w", NULL);
+
+ /* unbuffered write; we just messed with stdout... */
+ char msg[512];
+ snprintf(msg, sizeof(msg), "error executing %s: %s\n",
+ VTYSH_BIN_PATH, safe_strerror(errno));
+ write(1, msg, strlen(msg));
+ exit(1);
+}
+
+void integrated_write_sigchld(int status)
+{
+ uint8_t reply[4] = { 0, 0, 0, CMD_WARNING };
+
+ if (WIFEXITED(status)) {
+ zlog_info("configuration write completed with exit code %d",
+ WEXITSTATUS(status));
+ reply[3] = WEXITSTATUS(status);
+ } else if (WIFSIGNALED(status)) {
+ zlog_warn("configuration write terminated by signal %d",
+ WTERMSIG(status));
+ } else {
+ zlog_warn("configuration write terminated");
+ }
+
+ /* don't care about failures here, if the connection is broken the
+ * return value will just be lost. */
+ write(integrated_result_fd, reply, sizeof(reply));
+ close(integrated_result_fd);
+
+ integrated_write_pid = -1;
+}
+
+void watchquagga_vty_init(void)
+{
+ integrated_write_pid = -1;
+ install_element(ENABLE_NODE, &config_write_integrated_cmd);
+}