diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 33191f0a98..e6f5cdcb67 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -59,6 +59,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #endif /* bgpd options, we use GNU getopt library. */ +#define OPTION_VTYSOCK 1000 static const struct option longopts[] = { { "daemon", no_argument, NULL, 'd'}, @@ -69,6 +70,7 @@ static const struct option longopts[] = { "listenon", required_argument, NULL, 'l'}, { "vty_addr", required_argument, NULL, 'A'}, { "vty_port", required_argument, NULL, 'P'}, + { "vty_socket", required_argument, NULL, OPTION_VTYSOCK }, { "retain", no_argument, NULL, 'r'}, { "no_kernel", no_argument, NULL, 'n'}, { "user", required_argument, NULL, 'u'}, @@ -111,6 +113,9 @@ static struct quagga_signal_t bgp_signals[] = /* Configuration file and directory. */ char config_default[] = SYSCONFDIR BGP_DEFAULT_CONFIG; +/* VTY Socket prefix */ +char vty_sock_path[MAXPATHLEN] = BGP_VTYSH_PATH; + /* Route retain mode flag. */ static int retain_mode = 0; @@ -123,6 +128,7 @@ static const char *pid_file = PATH_BGPD_PID; /* VTY port number and address. */ int vty_port = BGP_VTY_PORT; char *vty_addr = NULL; +char *vty_sock_name; /* privileges */ static zebra_capabilities_t _caps_p [] = @@ -165,6 +171,7 @@ redistribution between different routing protocols.\n\n\ -l, --listenon Listen on specified address (implies -n)\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ + --vty_socket Override vty socket path\n\ -r, --retain When program terminates, retain added route by bgpd.\n\ -n, --no_kernel Do not install route to kernel.\n\ -u, --user User to run as\n\ @@ -195,7 +202,7 @@ sighup (void) vty_read_config (config_file, config_default); /* Create VTY's socket */ - vty_serv_sock (vty_addr, vty_port, BGP_VTYSH_PATH); + vty_serv_sock (vty_addr, vty_port, vty_sock_path); /* Try to return to normal operation. */ } @@ -469,6 +476,9 @@ main (int argc, char **argv) if (vty_port <= 0 || vty_port > 0xffff) vty_port = BGP_VTY_PORT; break; + case OPTION_VTYSOCK: + set_socket_path(vty_sock_path, BGP_VTYSH_PATH, optarg, sizeof (vty_sock_path)); + break; case 'r': retain_mode = 1; break; @@ -544,7 +554,7 @@ main (int argc, char **argv) pid_output (pid_file); /* Make bgp vty socket. */ - vty_serv_sock (vty_addr, vty_port, BGP_VTYSH_PATH); + vty_serv_sock (vty_addr, vty_port, vty_sock_path); /* Print banner. */ zlog_notice ("BGPd %s starting: vty@%d, bgp@%s:%d", FRR_COPYRIGHT, diff --git a/isisd/isis_main.c b/isisd/isis_main.c index f34be99eca..865f5c5f94 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -81,6 +81,7 @@ struct zebra_privs_t isisd_privs = { }; /* isisd options */ +#define OPTION_VTYSOCK 1000 struct option longopts[] = { {"daemon", no_argument, NULL, 'd'}, {"config_file", required_argument, NULL, 'f'}, @@ -88,6 +89,7 @@ struct option longopts[] = { {"socket", required_argument, NULL, 'z'}, {"vty_addr", required_argument, NULL, 'A'}, {"vty_port", required_argument, NULL, 'P'}, + {"vty_socket", required_argument, NULL, OPTION_VTYSOCK}, {"user", required_argument, NULL, 'u'}, {"group", required_argument, NULL, 'g'}, {"version", no_argument, NULL, 'v'}, @@ -103,6 +105,9 @@ char *config_file = NULL; /* isisd program name. */ char *progname; +/* VTY Socket prefix */ +char vty_sock_path[MAXPATHLEN] = ISIS_VTYSH_PATH; + int daemon_mode = 0; /* Master of threads. */ @@ -144,6 +149,7 @@ Daemon which manages IS-IS routing\n\n\ -z, --socket Set path of zebra socket\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ + --vty_socket Override vty socket path\n\ -u, --user User to run as\n\ -g, --group Group to run as\n\ -v, --version Print program version\n\ @@ -240,6 +246,7 @@ main (int argc, char **argv, char **envp) struct thread thread; char *config_file = NULL; char *vty_addr = NULL; + char *vty_sock_name; int dryrun = 0; /* Get the programname without the preceding path. */ @@ -305,6 +312,9 @@ main (int argc, char **argv, char **envp) vty_port = atoi (optarg); vty_port = (vty_port ? vty_port : ISISD_VTY_PORT); break; + case OPTION_VTYSOCK: + set_socket_path(vty_sock_path, ISIS_VTYSH_PATH, optarg, sizeof (vty_sock_path)); + break; case 'u': isisd_privs.user = optarg; break; @@ -379,7 +389,7 @@ main (int argc, char **argv, char **envp) pid_output (pid_file); /* Make isis vty socket. */ - vty_serv_sock (vty_addr, vty_port, ISIS_VTYSH_PATH); + vty_serv_sock (vty_addr, vty_port, vty_sock_path); /* Print banner. */ zlog_notice ("Quagga-ISISd %s starting: vty@%d", FRR_VERSION, vty_port); diff --git a/ldpd/control.c b/ldpd/control.c index ba303cc12c..8a2280be07 100644 --- a/ldpd/control.c +++ b/ldpd/control.c @@ -51,28 +51,28 @@ control_init(void) memset(&s_un, 0, sizeof(s_un)); s_un.sun_family = AF_UNIX; - strlcpy(s_un.sun_path, LDPD_SOCKET, sizeof(s_un.sun_path)); + strlcpy(s_un.sun_path, ctl_sock_path, sizeof(s_un.sun_path)); - if (unlink(LDPD_SOCKET) == -1) + if (unlink(ctl_sock_path) == -1) if (errno != ENOENT) { - log_warn("%s: unlink %s", __func__, LDPD_SOCKET); + log_warn("%s: unlink %s", __func__, ctl_sock_path); close(fd); return (-1); } old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); if (bind(fd, (struct sockaddr *)&s_un, sizeof(s_un)) == -1) { - log_warn("%s: bind: %s", __func__, LDPD_SOCKET); + log_warn("%s: bind: %s", __func__, ctl_sock_path); close(fd); umask(old_umask); return (-1); } umask(old_umask); - if (chmod(LDPD_SOCKET, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) { + if (chmod(ctl_sock_path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) { log_warn("%s: chmod", __func__); close(fd); - (void)unlink(LDPD_SOCKET); + (void)unlink(ctl_sock_path); return (-1); } @@ -97,7 +97,7 @@ control_cleanup(void) { accept_del(control_fd); close(control_fd); - unlink(LDPD_SOCKET); + unlink(ctl_sock_path); } /* ARGSUSED */ diff --git a/ldpd/ldp_vty_exec.c b/ldpd/ldp_vty_exec.c index a57cf3c3f6..a9138be2f2 100644 --- a/ldpd/ldp_vty_exec.c +++ b/ldpd/ldp_vty_exec.c @@ -405,9 +405,9 @@ ldp_vty_connect(struct imsgbuf *ibuf) memset(&s_un, 0, sizeof(s_un)); s_un.sun_family = AF_UNIX; - strlcpy(s_un.sun_path, LDPD_SOCKET, sizeof(s_un.sun_path)); + strlcpy(s_un.sun_path, ctl_sock_path, sizeof(s_un.sun_path)); if (connect(ctl_sock, (struct sockaddr *)&s_un, sizeof(s_un)) == -1) { - log_warn("%s: connect: %s", __func__, LDPD_SOCKET); + log_warn("%s: connect: %s", __func__, ctl_sock_path); close(ctl_sock); return (-1); } diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c index 8a9847bdfd..40726ba0bb 100644 --- a/ldpd/ldpd.c +++ b/ldpd/ldpd.c @@ -43,7 +43,7 @@ static void ldpd_shutdown(void); static pid_t start_child(enum ldpd_process, char *, int, - const char *, const char *); + const char *, const char *, const char *); static int main_dispatch_ldpe(struct thread *); static int main_dispatch_lde(struct thread *); static int main_imsg_send_ipc_sockets(struct imsgbuf *, @@ -115,7 +115,15 @@ struct zebra_privs_t ldpd_privs = .cap_num_i = 0 }; +/* VTY Socket prefix */ +char vty_sock_path[MAXPATHLEN] = LDP_VTYSH_PATH; + +/* CTL Socket path */ +char ctl_sock_path[MAXPATHLEN] = LDPD_SOCKET; + /* LDPd options. */ +#define OPTION_VTYSOCK 1000 +#define OPTION_CTLSOCK 1001 static struct option longopts[] = { { "daemon", no_argument, NULL, 'd'}, @@ -126,6 +134,8 @@ static struct option longopts[] = { "help", no_argument, NULL, 'h'}, { "vty_addr", required_argument, NULL, 'A'}, { "vty_port", required_argument, NULL, 'P'}, + { "vty_socket", required_argument, NULL, OPTION_VTYSOCK}, + { "ctl_socket", required_argument, NULL, OPTION_CTLSOCK}, { "user", required_argument, NULL, 'u'}, { "group", required_argument, NULL, 'g'}, { "version", no_argument, NULL, 'v'}, @@ -148,6 +158,8 @@ Daemon which manages LDP.\n\n\ -z, --socket Set path of zebra socket\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ + --vty_socket Override vty socket path\n\ + --ctl_socket Override ctl socket path\n\ -u, --user User to run as\n\ -g, --group Group to run as\n\ -v, --version Print program version\n\ @@ -212,6 +224,9 @@ main(int argc, char *argv[]) char *p; char *vty_addr = NULL; int vty_port = LDP_VTY_PORT; + char *vty_sock_name; + char *ctl_sock_custom_path = NULL; + char *ctl_sock_name; int daemon_mode = 0; const char *user = NULL; const char *group = NULL; @@ -272,6 +287,28 @@ main(int argc, char *argv[]) if (vty_port <= 0 || vty_port > 0xffff) vty_port = LDP_VTY_PORT; break; + case OPTION_VTYSOCK: + set_socket_path(vty_sock_path, LDP_VTYSH_PATH, optarg, sizeof (vty_sock_path)); + break; + case OPTION_CTLSOCK: + ctl_sock_name = strrchr(LDPD_SOCKET, '/'); + if (ctl_sock_name) + /* skip '/' */ + ctl_sock_name++; + else + /* + * LDPD_SOCKET configured as relative path + * during config? Should really never happen for + * sensible config + */ + ctl_sock_name = (char *)LDPD_SOCKET; + ctl_sock_custom_path = optarg; + strlcpy(ctl_sock_path, ctl_sock_custom_path, + sizeof(ctl_sock_path)); + strlcat(ctl_sock_path, "/", sizeof(ctl_sock_path)); + strlcat(ctl_sock_path, ctl_sock_name, + sizeof(ctl_sock_path)); + break; case 'u': user = optarg; break; @@ -318,7 +355,7 @@ main(int argc, char *argv[]) if (lflag) lde(user, group); else if (eflag) - ldpe(user, group); + ldpe(user, group, ctl_sock_path); master = thread_master_create(); @@ -360,9 +397,9 @@ main(int argc, char *argv[]) /* start children */ lde_pid = start_child(PROC_LDE_ENGINE, saved_argv0, - pipe_parent2lde[1], user, group); + pipe_parent2lde[1], user, group, ctl_sock_custom_path); ldpe_pid = start_child(PROC_LDP_ENGINE, saved_argv0, - pipe_parent2ldpe[1], user, group); + pipe_parent2ldpe[1], user, group, ctl_sock_custom_path); /* drop privileges */ if (user) @@ -410,7 +447,7 @@ main(int argc, char *argv[]) pid_output(pid_file); /* Create VTY socket */ - vty_serv_sock(vty_addr, vty_port, LDP_VTYSH_PATH); + vty_serv_sock(vty_addr, vty_port, vty_sock_path); /* Print banner. */ log_notice("LDPd %s starting: vty@%d", FRR_VERSION, vty_port); @@ -458,9 +495,9 @@ ldpd_shutdown(void) static pid_t start_child(enum ldpd_process p, char *argv0, int fd, const char *user, - const char *group) + const char *group, const char *ctl_sock_custom_path) { - char *argv[7]; + char *argv[9]; int argc = 0; pid_t pid; @@ -496,6 +533,10 @@ start_child(enum ldpd_process p, char *argv0, int fd, const char *user, argv[argc++] = (char *)"-g"; argv[argc++] = (char *)group; } + if (ctl_sock_custom_path) { + argv[argc++] = (char *)"--ctl_socket"; + argv[argc++] = (char *)ctl_sock_custom_path; + } argv[argc++] = NULL; execvp(argv0, argv); diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h index 630b192489..e58d8e4852 100644 --- a/ldpd/ldpd.h +++ b/ldpd/ldpd.h @@ -672,6 +672,7 @@ int sock_set_ipv6_mcast_loop(int); /* quagga */ extern struct thread_master *master; +extern char ctl_sock_path[MAXPATHLEN]; /* ldp_zebra.c */ void ldp_zebra_init(struct thread_master *); diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c index 37a3d79a28..0d0fe5c9e9 100644 --- a/ldpd/ldpe.c +++ b/ldpd/ldpe.c @@ -99,7 +99,7 @@ static struct quagga_signal_t ldpe_signals[] = /* label distribution protocol engine */ void -ldpe(const char *user, const char *group) +ldpe(const char *user, const char *group, const char *ctl_path) { struct thread thread; @@ -128,6 +128,7 @@ ldpe(const char *user, const char *group) ldpe_privs.group = group; zprivs_init(&ldpe_privs); + strlcpy(ctl_sock_path, ctl_path, sizeof(ctl_sock_path)); if (control_init() == -1) fatalx("control socket setup failed"); diff --git a/ldpd/ldpe.h b/ldpd/ldpe.h index aab1a7fd9b..da90c7cad7 100644 --- a/ldpd/ldpe.h +++ b/ldpd/ldpe.h @@ -183,7 +183,7 @@ int tlv_decode_fec_elm(struct nbr *, struct ldp_msg *, char *, uint16_t, struct map *); /* ldpe.c */ -void ldpe(const char *, const char *); +void ldpe(const char *, const char *, const char *); int ldpe_imsg_compose_parent(int, pid_t, void *, uint16_t); int ldpe_imsg_compose_lde(int, uint32_t, pid_t, void *, diff --git a/lib/privs.c b/lib/privs.c index ac2a8454c5..376d6f3365 100644 --- a/lib/privs.c +++ b/lib/privs.c @@ -251,7 +251,8 @@ zprivs_caps_init (struct zebra_privs_t *zprivs) } /* we have caps, we have no need to ever change back the original user */ - if (zprivs_state.zuid) + /* only change uid if we don't have the correct one */ + if ((zprivs_state.zuid) && (zprivs_state.zsuid != zprivs_state.zuid)) { if ( setreuid (zprivs_state.zuid, zprivs_state.zuid) ) { @@ -531,7 +532,8 @@ zprivs_caps_init (struct zebra_privs_t *zprivs) /* we have caps, we have no need to ever change back the original user * change real, effective and saved to the specified user. */ - if (zprivs_state.zuid) + /* only change uid if we don't have the correct one */ + if ((zprivs_state.zuid) && (zprivs_state.zsuid != zprivs_state.zuid)) { if ( setreuid (zprivs_state.zuid, zprivs_state.zuid) ) { @@ -602,7 +604,8 @@ zprivs_caps_terminate (void) int zprivs_change_uid (zebra_privs_ops_t op) { - + if (zprivs_state.zsuid == zprivs_state.zuid) + return 0; if (op == ZPRIVS_RAISE) return seteuid (zprivs_state.zsuid); else if (op == ZPRIVS_LOWER) @@ -766,7 +769,8 @@ zprivs_init(struct zebra_privs_t *zprivs) } } - if (ngroups) + /* add groups only if we changed uid - otherwise skip */ + if ((ngroups) && (zprivs_state.zsuid != zprivs_state.zuid)) { if ( setgroups (ngroups, groups) ) { @@ -776,7 +780,8 @@ zprivs_init(struct zebra_privs_t *zprivs) } } - if (zprivs_state.zgid) + /* change gid only if we changed uid - otherwise skip */ + if ((zprivs_state.zgid) && (zprivs_state.zsuid != zprivs_state.zuid)) { /* change group now, forever. uid we do later */ if ( setregid (zprivs_state.zgid, zprivs_state.zgid) ) @@ -797,7 +802,8 @@ zprivs_init(struct zebra_privs_t *zprivs) * This is not worth that much security wise, but all we can do. */ zprivs_state.zsuid = geteuid(); - if ( zprivs_state.zuid ) + /* only change uid if we don't have the correct one */ + if (( zprivs_state.zuid ) && (zprivs_state.zsuid != zprivs_state.zuid)) { if ( setreuid (-1, zprivs_state.zuid) ) { @@ -824,7 +830,8 @@ zprivs_terminate (struct zebra_privs_t *zprivs) #ifdef HAVE_CAPABILITIES zprivs_caps_terminate(); #else /* !HAVE_CAPABILITIES */ - if (zprivs_state.zuid) + /* only change uid if we don't have the correct one */ + if ((zprivs_state.zuid) && (zprivs_state.zsuid != zprivs_state.zuid)) { if ( setreuid (zprivs_state.zuid, zprivs_state.zuid) ) { diff --git a/lib/sockopt.c b/lib/sockopt.c index 461e1f7f54..570b575a7a 100644 --- a/lib/sockopt.c +++ b/lib/sockopt.c @@ -29,6 +29,29 @@ #include "sockopt.h" #include "sockunion.h" +/* Replace the path of given defaultpath with newpath, but keep filename */ +void +set_socket_path (char *path, char *defaultpath, char *newpath, int maxsize) +{ + char *sock_name; + + sock_name = strrchr(defaultpath, '/'); + if (sock_name) + /* skip '/' */ + sock_name++; + else + /* + * VTYSH_PATH configured as relative path + * during config? Should really never happen for + * sensible config + */ + sock_name = defaultpath; + + strlcpy (path, newpath, maxsize); + strlcat (path, "/", maxsize); + strlcat (path, sock_name, maxsize); +} + void setsockopt_so_recvbuf (int sock, int size) { diff --git a/lib/sockopt.h b/lib/sockopt.h index b3ab57ab71..8e7895dd6f 100644 --- a/lib/sockopt.h +++ b/lib/sockopt.h @@ -24,6 +24,9 @@ #include "sockunion.h" +/* Override (vty) socket paths, but keep the filename */ +extern void set_socket_path (char *path, char *defaultpath, char *newpath, int maxsize); + extern void setsockopt_so_recvbuf (int sock, int size); extern void setsockopt_so_sendbuf (const int sock, int size); extern int getsockopt_so_sendbuf (const int sock); diff --git a/lib/vty.c b/lib/vty.c index adcfaca4f3..9594d68ebd 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -2091,8 +2091,11 @@ vty_serv_un (const char *path) umask (old_mask); zprivs_get_ids(&ids); - - if (ids.gid_vty > 0) + + /* Hack: ids.gid_vty is actually a uint, but we stored -1 in it + earlier for the case when we don't need to chown the file + type casting it here to make a compare */ + if ((int)ids.gid_vty > 0) { /* set group of socket */ if ( chown (path, -1, ids.gid_vty) ) diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c index bd3a2faa5d..68d2b6894d 100644 --- a/ospf6d/ospf6_main.c +++ b/ospf6d/ospf6_main.c @@ -51,6 +51,9 @@ /* Default configuration file name for ospf6d. */ #define OSPF6_DEFAULT_CONFIG "ospf6d.conf" +/* VTY Socket prefix */ +char vty_sock_path[MAXPATHLEN] = OSPF6_VTYSH_PATH; + /* Default port values. */ #define OSPF6_VTY_PORT 2606 @@ -78,6 +81,7 @@ struct zebra_privs_t ospf6d_privs = }; /* ospf6d options, we use GNU getopt library. */ +#define OPTION_VTYSOCK 1000 struct option longopts[] = { { "daemon", no_argument, NULL, 'd'}, @@ -86,6 +90,7 @@ struct option longopts[] = { "socket", required_argument, NULL, 'z'}, { "vty_addr", required_argument, NULL, 'A'}, { "vty_port", required_argument, NULL, 'P'}, + { "vty_socket", required_argument, NULL, OPTION_VTYSOCK}, { "user", required_argument, NULL, 'u'}, { "group", required_argument, NULL, 'g'}, { "version", no_argument, NULL, 'v'}, @@ -125,6 +130,7 @@ Daemon which manages OSPF version 3.\n\n\ -z, --socket Set path of zebra socket\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ + --vty_socket Override vty socket path\n\ -u, --user User to run as\n\ -g, --group Group to run as\n\ -v, --version Print program version\n\ @@ -233,6 +239,7 @@ main (int argc, char *argv[], char *envp[]) int opt; char *vty_addr = NULL; int vty_port = 0; + char *vty_sock_name; char *config_file = NULL; struct thread thread; int dryrun = 0; @@ -285,6 +292,9 @@ main (int argc, char *argv[], char *envp[]) if (vty_port <= 0 || vty_port > 0xffff) vty_port = OSPF6_VTY_PORT; break; + case OPTION_VTYSOCK: + set_socket_path(vty_sock_path, OSPF6_VTYSH_PATH, optarg, sizeof (vty_sock_path)); + break; case 'u': ospf6d_privs.user = optarg; break; @@ -357,7 +367,7 @@ main (int argc, char *argv[], char *envp[]) /* Make ospf6 vty socket. */ if (!vty_port) vty_port = OSPF6_VTY_PORT; - vty_serv_sock (vty_addr, vty_port, OSPF6_VTYSH_PATH); + vty_serv_sock (vty_addr, vty_port, vty_sock_path); /* Print start message */ zlog_notice ("OSPF6d (Quagga-%s ospf6d-%s) starts: vty@%d", diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index e0719b397a..6719eb2497 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -79,6 +79,7 @@ struct zebra_privs_t ospfd_privs = char config_default[100]; /* OSPFd options. */ +#define OPTION_VTYSOCK 1000 struct option longopts[] = { { "daemon", no_argument, NULL, 'd'}, @@ -90,6 +91,7 @@ struct option longopts[] = { "help", no_argument, NULL, 'h'}, { "vty_addr", required_argument, NULL, 'A'}, { "vty_port", required_argument, NULL, 'P'}, + { "vty_socket", required_argument, NULL, OPTION_VTYSOCK}, { "user", required_argument, NULL, 'u'}, { "group", required_argument, NULL, 'g'}, { "apiserver", no_argument, NULL, 'a'}, @@ -99,6 +101,9 @@ struct option longopts[] = /* OSPFd program name */ +/* VTY Socket prefix */ +char vty_sock_path[MAXPATHLEN] = OSPF_VTYSH_PATH; + /* Master of threads. */ struct thread_master *master; @@ -126,6 +131,7 @@ Daemon which manages OSPF.\n\n\ -z, --socket Set path of zebra socket\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ + --vty_socket Override vty socket path\n\ -u, --user User to run as\n\ -g, --group Group to run as\n\ -a. --apiserver Enable OSPF apiserver\n\ @@ -188,6 +194,7 @@ main (int argc, char **argv) char *vty_addr = NULL; int vty_port = OSPF_VTY_PORT; char vty_path[100]; + char *vty_sock_name; int daemon_mode = 0; char *config_file = NULL; char *progname; @@ -253,6 +260,9 @@ main (int argc, char **argv) if (vty_port <= 0 || vty_port > 0xffff) vty_port = OSPF_VTY_PORT; break; + case OPTION_VTYSOCK: + set_socket_path(vty_sock_path, OSPF_VTYSH_PATH, optarg, sizeof (vty_sock_path)); + break; case 'u': ospfd_privs.user = optarg; break; @@ -357,19 +367,48 @@ main (int argc, char **argv) exit (1); } - /* Create VTY socket */ + /* Create PID file */ if (instance) { - sprintf(pid_file, "%s/ospfd-%d.pid", DAEMON_VTY_DIR, instance); - sprintf(vty_path, "%s/ospfd-%d.vty", DAEMON_VTY_DIR, instance); - } - else - { - strcpy(vty_path, OSPF_VTYSH_PATH); + char pidfile_temp[100]; + + /* Override the single file with file including instance + number in case of multi-instance */ + if (strrchr(pid_file, '/') != NULL) + /* cut of pid_file at last / char * to get directory */ + *strrchr(pid_file, '/') = '\0'; + else + /* pid_file contains no directory - should never happen, but deal with it anyway */ + /* throw-away all pid_file and assume it's only the filename */ + pid_file[0] = '\0'; + + snprintf(pidfile_temp, sizeof(pidfile_temp), "%s/ospfd-%d.pid", pid_file, instance ); + strncpy(pid_file, pidfile_temp, sizeof(pid_file)); } /* Process id file create. */ pid_output (pid_file); + /* Create VTY socket */ + if (instance) + { + /* Multi-Instance. Use only path section of vty_sock_path with new file incl instance */ + if (strrchr(vty_sock_path, '/') != NULL) + { + /* cut of pid_file at last / char * to get directory */ + *strrchr(vty_sock_path, '/') = '\0'; + } + else + { + /* pid_file contains no directory - should never happen, but deal with it anyway */ + /* throw-away all pid_file and assume it's only the filename */ + vty_sock_path[0] = '\0'; + } + snprintf(vty_path, sizeof(vty_path), "%s/ospfd-%d.vty", vty_sock_path, instance ); + } + else + { + strcpy(vty_path, vty_sock_path); + } vty_serv_sock (vty_addr, vty_port, vty_path); /* Print banner. */ diff --git a/pimd/pim_main.c b/pimd/pim_main.c index 29432ea230..1a3c8165e4 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -52,18 +52,25 @@ extern struct host host; char config_default[] = SYSCONFDIR PIMD_DEFAULT_CONFIG; +/* pimd options */ +#define OPTION_VTYSOCK 1000 struct option longopts[] = { { "daemon", no_argument, NULL, 'd'}, { "config_file", required_argument, NULL, 'f'}, { "pid_file", required_argument, NULL, 'i'}, + { "socket", required_argument, NULL, 'z'}, { "vty_addr", required_argument, NULL, 'A'}, { "vty_port", required_argument, NULL, 'P'}, + { "vty_socket", required_argument, NULL, OPTION_VTYSOCK}, { "version", no_argument, NULL, 'v'}, { "debug_zclient", no_argument, NULL, 'Z'}, { "help", no_argument, NULL, 'h'}, { 0 } }; +/* VTY Socket prefix */ +char vty_sock_path[MAXPATHLEN] = PIM_VTYSH_PATH; + /* pimd privileges */ zebra_capabilities_t _caps_p [] = { @@ -103,6 +110,7 @@ Daemon which manages PIM.\n\n\ -z, --socket Set path of zebra socket\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ + --vty_socket Override vty socket path\n\ -v, --version Print program version\n\ " @@ -125,6 +133,7 @@ Report bugs to %s\n", progname, PIMD_BUG_ADDRESS); int main(int argc, char** argv, char** envp) { char *p; char *vty_addr = NULL; + char *vty_sock_name; int vty_port = -1; int daemon_mode = 0; char *config_file = NULL; @@ -172,6 +181,9 @@ int main(int argc, char** argv, char** envp) { case 'P': vty_port = atoi (optarg); break; + case OPTION_VTYSOCK: + set_socket_path(vty_sock_path, PIM_VTYSH_PATH, optarg, sizeof (vty_sock_path)); + break; case 'v': printf(PIMD_PROGNAME " version %s\n", PIMD_VERSION); print_version(progname); @@ -238,7 +250,7 @@ int main(int argc, char** argv, char** envp) { /* Create pimd VTY socket */ if (vty_port < 0) vty_port = PIMD_VTY_PORT; - vty_serv_sock(vty_addr, vty_port, PIM_VTYSH_PATH); + vty_serv_sock(vty_addr, vty_port, vty_sock_path); zlog_notice("Quagga %s " PIMD_PROGNAME " %s starting, VTY interface at port TCP %d", FRR_VERSION, PIMD_VERSION, vty_port); diff --git a/ripd/rip_main.c b/ripd/rip_main.c index cfcb60168a..e46f867952 100644 --- a/ripd/rip_main.c +++ b/ripd/rip_main.c @@ -39,6 +39,7 @@ #include "ripd/ripd.h" /* ripd options. */ +#define OPTION_VTYSOCK 1000 static struct option longopts[] = { { "daemon", no_argument, NULL, 'd'}, @@ -49,6 +50,7 @@ static struct option longopts[] = { "dryrun", no_argument, NULL, 'C'}, { "vty_addr", required_argument, NULL, 'A'}, { "vty_port", required_argument, NULL, 'P'}, + { "vty_socket", required_argument, NULL, OPTION_VTYSOCK}, { "retain", no_argument, NULL, 'r'}, { "user", required_argument, NULL, 'u'}, { "group", required_argument, NULL, 'g'}, @@ -85,6 +87,9 @@ char *config_file = NULL; /* ripd program name */ +/* VTY Socket prefix */ +char vty_sock_path[MAXPATHLEN] = RIP_VTYSH_PATH; + /* Route retain mode flag. */ int retain_mode = 0; @@ -116,6 +121,7 @@ Daemon which manages RIP version 1 and 2.\n\n\ -z, --socket Set path of zebra socket\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ + --vty_socket Override vty socket path\n\ -C, --dryrun Check configuration for validity and exit\n\ -r, --retain When program terminates, retain added route by ripd.\n\ -u, --user User to run as\n\ @@ -142,7 +148,7 @@ sighup (void) vty_read_config (config_file, config_default); /* Create VTY's socket */ - vty_serv_sock (vty_addr, vty_port, RIP_VTYSH_PATH); + vty_serv_sock (vty_addr, vty_port, vty_sock_path); /* Try to return to normal operation. */ } @@ -195,6 +201,7 @@ main (int argc, char **argv) int dryrun = 0; char *progname; struct thread thread; + char *vty_sock_name; /* Set umask before anything for security */ umask (0027); @@ -251,6 +258,9 @@ main (int argc, char **argv) if (vty_port <= 0 || vty_port > 0xffff) vty_port = RIP_VTY_PORT; break; + case OPTION_VTYSOCK: + set_socket_path(vty_sock_path, RIP_VTYSH_PATH, optarg, sizeof (vty_sock_path)); + break; case 'r': retain_mode = 1; break; @@ -311,7 +321,7 @@ main (int argc, char **argv) pid_output (pid_file); /* Create VTY's socket */ - vty_serv_sock (vty_addr, vty_port, RIP_VTYSH_PATH); + vty_serv_sock (vty_addr, vty_port, vty_sock_path); /* Print banner. */ zlog_notice ("RIPd %s starting: vty@%d", FRR_VERSION, vty_port); diff --git a/ripngd/ripng_main.c b/ripngd/ripng_main.c index 14711a1a65..1677996eaa 100644 --- a/ripngd/ripng_main.c +++ b/ripngd/ripng_main.c @@ -44,6 +44,7 @@ char config_default[] = SYSCONFDIR RIPNG_DEFAULT_CONFIG; char *config_file = NULL; /* RIPngd options. */ +#define OPTION_VTYSOCK 1000 struct option longopts[] = { { "daemon", no_argument, NULL, 'd'}, @@ -54,6 +55,7 @@ struct option longopts[] = { "help", no_argument, NULL, 'h'}, { "vty_addr", required_argument, NULL, 'A'}, { "vty_port", required_argument, NULL, 'P'}, + { "vty_socket", required_argument, NULL, OPTION_VTYSOCK}, { "retain", no_argument, NULL, 'r'}, { "user", required_argument, NULL, 'u'}, { "group", required_argument, NULL, 'g'}, @@ -87,6 +89,9 @@ struct zebra_privs_t ripngd_privs = /* RIPngd program name */ +/* VTY Socket prefix */ +char vty_sock_path[MAXPATHLEN] = RIPNG_VTYSH_PATH; + /* Route retain mode flag. */ int retain_mode = 0; @@ -118,6 +123,7 @@ Daemon which manages RIPng.\n\n\ -z, --socket Set path of zebra socket\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ + --vty_socket Override vty socket path\n\ -r, --retain When program terminates, retain added route by ripngd.\n\ -u, --user User to run as\n\ -g, --group Group to run as\n\ @@ -141,7 +147,7 @@ sighup (void) /* Reload config file. */ vty_read_config (config_file, config_default); /* Create VTY's socket */ - vty_serv_sock (vty_addr, vty_port, RIPNG_VTYSH_PATH); + vty_serv_sock (vty_addr, vty_port, vty_sock_path); /* Try to return to normal operation. */ } @@ -195,6 +201,7 @@ main (int argc, char **argv) char *progname; struct thread thread; int dryrun = 0; + char *vty_sock_name; /* Set umask before anything for security */ umask (0027); @@ -249,6 +256,9 @@ main (int argc, char **argv) if (vty_port <= 0 || vty_port > 0xffff) vty_port = RIPNG_VTY_PORT; break; + case OPTION_VTYSOCK: + set_socket_path(vty_sock_path, RIPNG_VTYSH_PATH, optarg, sizeof (vty_sock_path)); + break; case 'r': retain_mode = 1; break; @@ -303,7 +313,7 @@ main (int argc, char **argv) } /* Create VTY socket */ - vty_serv_sock (vty_addr, vty_port, RIPNG_VTYSH_PATH); + vty_serv_sock (vty_addr, vty_port, vty_sock_path); /* Process id file create. */ pid_output (pid_file); diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 6d6fe61306..17f6bfa5a5 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -2898,13 +2898,34 @@ vtysh_connect (struct vtysh_client *vclient) int sock, len; struct sockaddr_un addr; struct stat s_stat; + char path[MAXPATHLEN]; + + if (vty_sock_path == NULL) + strlcpy (path, vclient->path, sizeof (path)); + else { + /* Different path for VTY Socket specified + overriding the default path, but keep the filename */ + strlcpy (path, vty_sock_path, sizeof (path)); + + if (strrchr (vclient->path, '/') != NULL) + strlcat (path, strrchr (vclient->path, '/'), sizeof (path)); + else { + /* + * vclient->path configured as relative path during config? Should + * really never happen for sensible config + */ + strlcat (path, "/", sizeof (path)); + strlcat (path, vclient->path, sizeof (path)); + } + } + path[sizeof(path)-1] = '\0'; /* Stat socket to see if we have permission to access it. */ - ret = stat (vclient->path, &s_stat); + ret = stat (path, &s_stat); if (ret < 0 && errno != ENOENT) { fprintf (stderr, "vtysh_connect(%s): stat = %s\n", - vclient->path, safe_strerror(errno)); + path, safe_strerror(errno)); exit(1); } @@ -2913,7 +2934,7 @@ vtysh_connect (struct vtysh_client *vclient) if (! S_ISSOCK(s_stat.st_mode)) { fprintf (stderr, "vtysh_connect(%s): Not a socket\n", - vclient->path); + path); exit (1); } @@ -2923,7 +2944,7 @@ vtysh_connect (struct vtysh_client *vclient) if (sock < 0) { #ifdef DEBUG - fprintf(stderr, "vtysh_connect(%s): socket = %s\n", vclient->path, + fprintf(stderr, "vtysh_connect(%s): socket = %s\n", path, safe_strerror(errno)); #endif /* DEBUG */ return -1; @@ -2931,7 +2952,7 @@ vtysh_connect (struct vtysh_client *vclient) memset (&addr, 0, sizeof (struct sockaddr_un)); addr.sun_family = AF_UNIX; - strncpy (addr.sun_path, vclient->path, strlen (vclient->path)); + strncpy (addr.sun_path, path, strlen (path)); #ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN len = addr.sun_len = SUN_LEN(&addr); #else @@ -2942,7 +2963,7 @@ vtysh_connect (struct vtysh_client *vclient) if (ret < 0) { #ifdef DEBUG - fprintf(stderr, "vtysh_connect(%s): connect = %s\n", vclient->path, + fprintf(stderr, "vtysh_connect(%s): connect = %s\n", path, safe_strerror(errno)); #endif /* DEBUG */ close (sock); @@ -2993,14 +3014,23 @@ vtysh_update_all_insances(struct vtysh_client * head_client) { struct vtysh_client *client; char *ptr; + char vty_dir[MAXPATHLEN]; DIR *dir; struct dirent *file; int n = 0; if (head_client->flag != VTYSH_OSPFD) return; - /* ls DAEMON_VTY_DIR and look for all files ending in .vty */ - dir = opendir(DAEMON_VTY_DIR "/"); + if (vty_sock_path == NULL) + /* ls DAEMON_VTY_DIR and look for all files ending in .vty */ + strlcpy(vty_dir, DAEMON_VTY_DIR "/", MAXPATHLEN); + else + { + /* ls vty_sock_dir and look for all files ending in .vty */ + strlcpy(vty_dir, vty_sock_path, MAXPATHLEN); + strlcat(vty_dir, "/", MAXPATHLEN); + } + dir = opendir(vty_dir); if (dir) { while ((file = readdir(dir)) != NULL) @@ -3010,8 +3040,8 @@ vtysh_update_all_insances(struct vtysh_client * head_client) if (n == MAXIMUM_INSTANCES) { fprintf(stderr, - "Parsing %s/, client limit(%d) reached!\n", - DAEMON_VTY_DIR, n); + "Parsing %s, client limit(%d) reached!\n", + vty_dir, n); break; } client = (struct vtysh_client *) malloc(sizeof(struct vtysh_client)); @@ -3019,7 +3049,7 @@ vtysh_update_all_insances(struct vtysh_client * head_client) client->name = "ospfd"; client->flag = VTYSH_OSPFD; ptr = (char *) malloc(100); - sprintf(ptr, "%s/%s", DAEMON_VTY_DIR, file->d_name); + sprintf(ptr, "%s%s", vty_dir, file->d_name); client->path = (const char *)ptr; client->next = NULL; vtysh_client_sorted_insert(head_client, client); diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h index 46ed001919..537f944a7a 100644 --- a/vtysh/vtysh.h +++ b/vtysh/vtysh.h @@ -96,4 +96,6 @@ extern int execute_flag; extern struct vty *vty; +extern char * vty_sock_path; + #endif /* VTYSH_H */ diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c index 6b33fca39b..bad21ae661 100644 --- a/vtysh/vtysh_main.c +++ b/vtysh/vtysh_main.c @@ -45,14 +45,17 @@ char *progname; /* Configuration file name and directory. */ -static char vtysh_config_always[] = SYSCONFDIR VTYSH_DEFAULT_CONFIG; -static char quagga_config_default[] = SYSCONFDIR QUAGGA_DEFAULT_CONFIG; +static char vtysh_config_always[MAXPATHLEN] = SYSCONFDIR VTYSH_DEFAULT_CONFIG; +static char quagga_config_default[MAXPATHLEN] = SYSCONFDIR QUAGGA_DEFAULT_CONFIG; char *quagga_config = quagga_config_default; char history_file[MAXPATHLEN]; /* Flag for indicate executing child command. */ int execute_flag = 0; +/* VTY Socket prefix */ +char * vty_sock_path = NULL; + /* For sigsetjmp() & siglongjmp(). */ static sigjmp_buf jmpbuf; @@ -144,8 +147,11 @@ usage (int status) "-f, --inputfile Execute commands from specific file and exit\n" \ "-E, --echo Echo prompt and command in -c mode\n" \ "-C, --dryrun Check configuration for validity and exit\n" \ - "-m, --markfile Mark input file with context end\n" - "-w, --writeconfig Write integrated config (Quagga.conf) and exit\n" + " --vty_socket Override vty socket path\n" \ + "-m, --markfile Mark input file with context end\n" \ + " --vty_socket Override vty socket path\n" \ + " --config_dir Override config directory path\n" \ + "-w, --writeconfig Write integrated config (Quagga.conf) and exit\n" \ "-h, --help Display this help and exit\n\n" \ "Note that multiple commands may be executed from the command\n" \ "line by passing multiple -c args, or by embedding linefeed\n" \ @@ -156,6 +162,8 @@ usage (int status) } /* VTY shell options, we use GNU getopt library. */ +#define OPTION_VTYSOCK 1000 +#define OPTION_CONFDIR 1001 struct option longopts[] = { { "boot", no_argument, NULL, 'b'}, @@ -163,6 +171,8 @@ struct option longopts[] = { "eval", required_argument, NULL, 'e'}, { "command", required_argument, NULL, 'c'}, { "daemon", required_argument, NULL, 'd'}, + { "vty_socket", required_argument, NULL, OPTION_VTYSOCK}, + { "config_dir", required_argument, NULL, OPTION_CONFDIR}, { "inputfile", required_argument, NULL, 'f'}, { "echo", no_argument, NULL, 'E'}, { "dryrun", no_argument, NULL, 'C'}, @@ -262,6 +272,7 @@ main (int argc, char **argv, char **env) int boot_flag = 0; const char *daemon_name = NULL; const char *inputfile = NULL; + char *vtysh_configfile_name; struct cmd_rec { const char *line; struct cmd_rec *next; @@ -274,6 +285,9 @@ main (int argc, char **argv, char **env) int ret = 0; char *homedir = NULL; + /* check for restricted functionality if vtysh is run setuid */ + int restricted = (getuid() != geteuid()) || (getgid() != getegid()); + /* Preserve name of myself. */ progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); @@ -310,6 +324,55 @@ main (int argc, char **argv, char **env) tail = cr; } break; + case OPTION_VTYSOCK: + vty_sock_path = optarg; + break; + case OPTION_CONFDIR: + /* + * Skip option for Config Directory if setuid + */ + if (restricted) + { + fprintf (stderr, "Overriding of Config Directory blocked for vtysh with setuid"); + return 1; + } + /* + * Overwrite location for vtysh.conf + */ + vtysh_configfile_name = strrchr(VTYSH_DEFAULT_CONFIG, '/'); + if (vtysh_configfile_name) + /* skip '/' */ + vtysh_configfile_name++; + else + /* + * VTYSH_DEFAULT_CONFIG configured with relative path + * during config? Should really never happen for + * sensible config + */ + vtysh_configfile_name = (char *) VTYSH_DEFAULT_CONFIG; + strlcpy(vtysh_config_always, optarg, sizeof(vtysh_config_always)); + strlcat(vtysh_config_always, "/", sizeof(vtysh_config_always)); + strlcat(vtysh_config_always, vtysh_configfile_name, + sizeof(vtysh_config_always)); + /* + * Overwrite location for Quagga.conf + */ + vtysh_configfile_name = strrchr(QUAGGA_DEFAULT_CONFIG, '/'); + if (vtysh_configfile_name) + /* skip '/' */ + vtysh_configfile_name++; + else + /* + * QUAGGA_DEFAULT_CONFIG configured with relative path + * during config? Should really never happen for + * sensible config + */ + vtysh_configfile_name = (char *) QUAGGA_DEFAULT_CONFIG; + strlcpy(quagga_config_default, optarg, sizeof(vtysh_config_always)); + strlcat(quagga_config_default, "/", sizeof(vtysh_config_always)); + strlcat(quagga_config_default, vtysh_configfile_name, + sizeof(quagga_config_default)); + break; case 'd': daemon_name = optarg; break; diff --git a/vtysh/vtysh_user.c b/vtysh/vtysh_user.c index 3a64ae0a96..73f7c1be98 100644 --- a/vtysh/vtysh_user.c +++ b/vtysh/vtysh_user.c @@ -218,7 +218,12 @@ char * vtysh_get_home (void) { struct passwd *passwd; + char * homedir; + if ((homedir = getenv("HOME")) != 0) + return homedir; + + /* Fallback if HOME is undefined */ passwd = getpwuid (getuid ()); return passwd ? passwd->pw_dir : NULL; diff --git a/zebra/main.c b/zebra/main.c index 9abc8f87ff..aa1cbc3b26 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -59,6 +59,9 @@ struct zebra_t zebrad = /* process id. */ pid_t pid; +/* VTY Socket prefix */ +char vty_sock_path[MAXPATHLEN] = ZEBRA_VTYSH_PATH; + /* Pacify zclient.o in libzebra, which expects this variable. */ struct thread_master *master; @@ -77,6 +80,7 @@ u_int32_t nl_rcvbufsize = 4194304; #endif /* HAVE_NETLINK */ /* Command line options. */ +#define OPTION_VTYSOCK 1000 struct option longopts[] = { { "batch", no_argument, NULL, 'b'}, @@ -90,6 +94,7 @@ struct option longopts[] = { "help", no_argument, NULL, 'h'}, { "vty_addr", required_argument, NULL, 'A'}, { "vty_port", required_argument, NULL, 'P'}, + { "vty_socket", required_argument, NULL, OPTION_VTYSOCK }, { "retain", no_argument, NULL, 'r'}, { "dryrun", no_argument, NULL, 'C'}, #ifdef HAVE_NETLINK @@ -152,6 +157,7 @@ usage (char *progname, int status) "-C, --dryrun Check configuration for validity and exit\n"\ "-A, --vty_addr Set vty's bind address\n"\ "-P, --vty_port Set vty's port number\n"\ + " --vty_socket Override vty socket path\n"\ "-r, --retain When program terminates, retain added route "\ "by zebra.\n"\ "-u, --user User to run as\n"\ @@ -259,6 +265,7 @@ main (int argc, char **argv) char *p; char *vty_addr = NULL; int vty_port = ZEBRA_VTY_PORT; + char *vty_sock_name; int dryrun = 0; int batch_mode = 0; int daemon_mode = 0; @@ -339,6 +346,9 @@ main (int argc, char **argv) if (vty_port <= 0 || vty_port > 0xffff) vty_port = ZEBRA_VTY_PORT; break; + case OPTION_VTYSOCK: + set_socket_path(vty_sock_path, ZEBRA_VTYSH_PATH, optarg, sizeof (vty_sock_path)); + break; case 'r': retain_mode = 1; break; @@ -463,7 +473,7 @@ main (int argc, char **argv) zebra_zserv_socket_init (zserv_path); /* Make vty server socket. */ - vty_serv_sock (vty_addr, vty_port, ZEBRA_VTYSH_PATH); + vty_serv_sock (vty_addr, vty_port, vty_sock_path); /* Print banner. */ zlog_notice ("Zebra %s starting: vty@%d", FRR_VERSION, vty_port);