mirror of
https://github.com/FRRouting/frr.git
synced 2025-04-30 13:37:17 +02:00
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>
This commit is contained in:
parent
46d5d8ec82
commit
95c4aff294
11
configure.ac
11
configure.ac
|
@ -1737,6 +1737,17 @@ AC_DEFINE_UNQUOTED(ISIS_VTYSH_PATH, "$quagga_statedir/isisd.vty",isisd vty socke
|
|||
AC_DEFINE_UNQUOTED(PIM_VTYSH_PATH, "$quagga_statedir/pimd.vty",pimd vty socket)
|
||||
AC_DEFINE_UNQUOTED(DAEMON_VTY_DIR, "$quagga_statedir",daemon vty directory)
|
||||
|
||||
dnl autoconf does this, but it does it too late...
|
||||
test "x$prefix" = xNONE && prefix=$ac_default_prefix
|
||||
test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
|
||||
|
||||
dnl get the full path, recursing through variables...
|
||||
vtysh_bin="$bindir/vtysh"
|
||||
for I in 1 2 3 4 5 6 7 8 9 10; do
|
||||
eval vtysh_bin="\"$vtysh_bin\""
|
||||
done
|
||||
AC_DEFINE_UNQUOTED(VTYSH_BIN_PATH, "$vtysh_bin",path to vtysh binary)
|
||||
|
||||
dnl -------------------------------
|
||||
dnl Quagga sources should always be
|
||||
dnl current wrt interfaces. Dont
|
||||
|
|
|
@ -226,6 +226,7 @@ struct cmd_token
|
|||
#define CMD_COMPLETE_LIST_MATCH 9
|
||||
#define CMD_SUCCESS_DAEMON 10
|
||||
#define CMD_ERR_NO_FILE 11
|
||||
#define CMD_SUSPEND 12
|
||||
|
||||
/* Argc max counts. */
|
||||
#define CMD_ARGC_MAX 25
|
||||
|
|
|
@ -2235,6 +2235,13 @@ vtysh_read (struct thread *thread)
|
|||
printf ("vtysh node: %d\n", vty->node);
|
||||
#endif /* VTYSH_DEBUG */
|
||||
|
||||
/* hack for asynchronous "write integrated"
|
||||
* - other commands in "buf" will be ditched
|
||||
* - input during pending config-write is "unsupported" */
|
||||
if (ret == CMD_SUSPEND)
|
||||
break;
|
||||
|
||||
/* warning: watchquagga hardcodes this result write */
|
||||
header[3] = ret;
|
||||
buffer_put(vty->obuf, header, 4);
|
||||
|
||||
|
|
|
@ -86,6 +86,7 @@ vtysh_cmd_FILES = $(vtysh_scan) \
|
|||
$(top_srcdir)/zebra/zebra_fpm.c \
|
||||
$(top_srcdir)/zebra/zebra_ptm.c \
|
||||
$(top_srcdir)/zebra/zebra_mpls_vty.c \
|
||||
$(top_srcdir)/watchquagga/watchquagga_vty.c \
|
||||
$(BGP_VNC_RFAPI_SRC) $(BGP_VNC_RFP_SRC)
|
||||
|
||||
vtysh_cmd.c: $(vtysh_cmd_FILES) extract.pl
|
||||
|
|
|
@ -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@
|
||||
|
|
|
@ -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));
|
||||
|
|
29
watchquagga/watchquagga.h
Normal file
29
watchquagga/watchquagga.h
Normal file
|
@ -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 */
|
128
watchquagga/watchquagga_vty.c
Normal file
128
watchquagga/watchquagga_vty.c
Normal file
|
@ -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);
|
||||
}
|
Loading…
Reference in a new issue