diff options
author | David Lamparter <equinox@opensourcerouting.org> | 2016-11-09 14:15:34 +0100 |
---|---|---|
committer | David Lamparter <equinox@opensourcerouting.org> | 2016-11-09 14:29:39 +0100 |
commit | 95c4aff294f6c1bf1450cbebc4133cad3560dfc9 (patch) | |
tree | 38656626e6a4b3ff2d7edb80cffe31162fa6d3d9 /watchquagga | |
parent | watchquagga: add ZLOG_WATCHQUAGGA (diff) | |
download | frr-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.am | 4 | ||||
-rw-r--r-- | watchquagga/watchquagga.c | 29 | ||||
-rw-r--r-- | watchquagga/watchquagga.h | 29 | ||||
-rw-r--r-- | watchquagga/watchquagga_vty.c | 128 |
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); +} |