diff options
37 files changed, 681 insertions, 72 deletions
diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am index 7f739f6e..0e549cc0 100644 --- a/bgpd/Makefile.am +++ b/bgpd/Makefile.am @@ -24,7 +24,7 @@ noinst_HEADERS = \ bgpd_SOURCES = \ bgp_main.c $(libbgp_a_SOURCES) -bgpd_LDADD = ../lib/libzebra.a +bgpd_LDADD = ../lib/libzebra.a @LIBCAP@ sysconf_DATA = bgpd.conf.sample bgpd.conf.sample2 diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 70377914..3e1d80f6 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -29,6 +29,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "memory.h" #include "prefix.h" #include "log.h" +#include "privs.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_attr.h" @@ -45,6 +46,7 @@ struct option longopts[] = { "vty_port", required_argument, NULL, 'P'}, { "retain", no_argument, NULL, 'r'}, { "no_kernel", no_argument, NULL, 'n'}, + { "user", required_argument, NULL, 'u'}, { "version", no_argument, NULL, 'v'}, { "help", no_argument, NULL, 'h'}, { 0 } @@ -70,6 +72,23 @@ char *pid_file = PATH_BGPD_PID; int vty_port = BGP_VTY_PORT; char *vty_addr = NULL; +/* privileges */ +zebra_capabilities_t _caps_p [] = +{ + ZCAP_BIND, +}; + +struct zebra_privs_t bgpd_privs = +{ +#if defined(ZEBRA_USER) && defined(ZEBRA_GROUP) + .user = ZEBRA_USER, + .group = ZEBRA_GROUP, +#endif + .caps_p = _caps_p, + .cap_num_p = sizeof(_caps_p)/sizeof(_caps_p[0]), + .cap_num_i = 0, +}; + /* Help information display. */ static void usage (char *progname, int status) @@ -89,6 +108,7 @@ redistribution between different routing protocols.\n\n\ -P, --vty_port Set vty's port number\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 and group to run as\n\ -v, --version Print program version\n\ -h, --help Display this help and exit\n\ \n\ @@ -197,7 +217,7 @@ main (int argc, char **argv) /* Command line argument treatment. */ while (1) { - opt = getopt_long (argc, argv, "df:hp:A:P:rnv", longopts, 0); + opt = getopt_long (argc, argv, "df:hp:A:P:rnu:v", longopts, 0); if (opt == EOF) break; @@ -238,6 +258,9 @@ main (int argc, char **argv) case 'n': bgp_option_set (BGP_OPT_NO_FIB); break; + case 'u': + bgpd_privs.user = bgpd_privs.group = optarg; + break; case 'v': print_version (progname); exit (0); @@ -257,6 +280,7 @@ main (int argc, char **argv) /* Initializations. */ srand (time (NULL)); signal_init (); + zprivs_init (&bgpd_privs); cmd_init (1); vty_init (); memory_init (); diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 40e9cdb3..019b78b7 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -27,12 +27,16 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "if.h" #include "prefix.h" #include "command.h" +#include "privs.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_fsm.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_network.h" + +extern struct zebra_privs_t bgpd_privs; + /* Accept bgp connection. */ static int @@ -153,9 +157,16 @@ bgp_bind_address (int sock, struct in_addr *addr) #endif /* HAVE_SIN_LEN */ memcpy (&local.sin_addr, addr, sizeof (struct in_addr)); + if ( bgpd_privs.change (ZPRIVS_RAISE) ) + zlog_err ("bgp_bind_address: could not raise privs"); + ret = bind (sock, (struct sockaddr *)&local, sizeof (struct sockaddr_in)); if (ret < 0) ; + + if (bgpd_privs.change (ZPRIVS_LOWER) ) + zlog_err ("bgp_bind_address: could not lower privs"); + return 0; } @@ -306,6 +317,9 @@ bgp_socket (struct bgp *bgp, unsigned short port) sockopt_reuseaddr (sock); sockopt_reuseport (sock); + + if (bgpd_privs.change (ZPRIVS_RAISE) ) + zlog_err ("bgp_socket: could not raise privs"); ret = bind (sock, ainfo->ai_addr, ainfo->ai_addrlen); if (ret < 0) @@ -314,6 +328,10 @@ bgp_socket (struct bgp *bgp, unsigned short port) close (sock); continue; } + + if (bgpd_privs.change (ZPRIVS_LOWER) ) + zlog_err ("bgp_bind_address: could not lower privs"); + ret = listen (sock, 3); if (ret < 0) { @@ -359,6 +377,9 @@ bgp_socket (struct bgp *bgp, unsigned short port) sin.sin_len = socklen; #endif /* HAVE_SIN_LEN */ + if ( bgpd_privs.change (ZPRIVS_RAISE) ) + zlog_err ("bgp_socket: could not raise privs"); + ret = bind (sock, (struct sockaddr *) &sin, socklen); if (ret < 0) { @@ -366,6 +387,10 @@ bgp_socket (struct bgp *bgp, unsigned short port) close (sock); return ret; } + + if (bgpd_privs.change (ZPRIVS_LOWER) ) + zlog_err ("bgp_socket: could not lower privs"); + ret = listen (sock, 3); if (ret < 0) { diff --git a/configure.ac b/configure.ac index ad58c3a8..290d8331 100755 --- a/configure.ac +++ b/configure.ac @@ -98,8 +98,15 @@ AC_ARG_ENABLE(ospf-te, [ --enable-ospf-te enable Traffic Engineering Extension to OSPF]) AC_ARG_ENABLE(multipath, [ --enable-multipath=ARG enable multipath function, ARG must be digit]) +AC_ARG_ENABLE(zebra_user, +[ --enable-user=ARG user to run zebra suite as (default zebra)]) +AC_ARG_ENABLE(zebra_group, +[ --enable-group=ARG group to run zebra suite as (default zebra)]) +AC_ARG_ENABLE(vty_group, +[ --enable-vty-group=ARG set vty sockets to have specified group as owner]) + AC_ARG_ENABLE(rtadv, -[ --enable-rtadv enable IPV6 router advertisment feature]) +[ --enable-rtadv enable IPV6 router advertisement feature]) if test "${enable_broken_aliases}" = "yes"; then if test "${enable_netlink}" = "yes" @@ -136,6 +143,32 @@ else AC_MSG_RESULT(no) fi +if test "${enable_user}" = "yes" ; then + enable_user="zebra" +elif test "${enable_user}" = "no"; then + enable_user="root" +fi +AC_DEFINE_UNQUOTED(ZEBRA_USER, "${enable_user}", Zebra User) + +if test "${enable_group}" = "yes" ; then + enable_group="zebra" +elif test "${enable_group}" = "no"; then + enable_group="root" +fi +AC_DEFINE_UNQUOTED(ZEBRA_GROUP, "${enable_group}", Zebra Group) + +if test x"${enable_vty_group}" = x"yes" ; then + AC_MSG_ERROR([--enable-vty-group requires a group as argument]) +fi +if test "${enable_vty_group}" = ""; then + AC_MSG_ERROR([--enable-vty-group requires a group as argument]) +fi +if test x"${enable_vty_group}" != x"no"; then + if test "${enable_vty_group}" != ""; then + AC_DEFINE_UNQUOTED(VTY_GROUP, "${enable_vty_group}", VTY Sockets Group) + fi +fi + changequote(, )dnl MULTIPATH_NUM=1 @@ -864,6 +897,28 @@ AC_TRY_COMPILE([#include <sys/resource.h> AC_DEFINE(HAVE_RUSAGE,,rusage)], AC_MSG_RESULT(no)) +dnl ------------------- +dnl capabilities checks +dnl ------------------- +AC_MSG_CHECKING(whether prctl PR_SET_KEEPCAPS is available) +AC_TRY_COMPILE([#include <sys/prctl.h>],[prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);], + [AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_PR_SET_KEEPCAPS,,prctl) + zebra_ac_keepcaps="yes"], + AC_MSG_RESULT(no) +) +if test x"${zebra_ac_keepcaps}" = x"yes"; then + AC_CHECK_HEADERS(sys/capability.h) +fi +if test x"${ac_cv_header_sys_capability_h}" = x"yes"; then + AC_CHECK_LIB(cap, cap_init, + [AC_DEFINE(HAVE_LCAPS,1,Capabilities) + LIBCAP="-lcap" + ] + ) +fi +AC_SUBST(LIBCAP) + dnl --------------------------- dnl check for glibc 'backtrace' dnl --------------------------- @@ -968,5 +1023,4 @@ compiler : ${CC} compiler flags : ${CFLAGS} linker flags : ${LDFLAGS} ${LIBS} state file directory : ${zebra_statedir} -linker flags : ${LDFLAGS} ${LIBS} " diff --git a/lib/Makefile.am b/lib/Makefile.am index 02680603..d041770d 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -10,9 +10,9 @@ libzebra_a_SOURCES = \ print_version.c checksum.c vector.c linklist.c vty.c command.c \ sockunion.c prefix.c thread.c if.c memory.c buffer.c table.c hash.c \ filter.c routemap.c distribute.c stream.c str.c log.c plist.c \ - zclient.c sockopt.c smux.c md5.c if_rmap.c keychain.c + zclient.c sockopt.c smux.c md5.c if_rmap.c keychain.c privs.c debug.c -libzebra_a_DEPENDENCIES = @LIB_REGEX@ +libzebra_a_DEPENDENCIES = @LIB_REGEX@ @LIBCAP@ libzebra_a_LIBADD = @LIB_REGEX@ @@ -20,7 +20,8 @@ noinst_HEADERS = \ buffer.h command.h filter.h getopt.h hash.h if.h linklist.h log.h \ memory.h network.h prefix.h routemap.h distribute.h sockunion.h \ str.h stream.h table.h thread.h vector.h version.h vty.h zebra.h \ - plist.h zclient.h sockopt.h smux.h md5-gnu.h if_rmap.h keychain.h + plist.h zclient.h sockopt.h smux.h md5-gnu.h if_rmap.h keychain.h \ + privs.h debug.h EXTRA_DIST = regex.c regex-gnu.h diff --git a/lib/memory.h b/lib/memory.h index a38cda3f..925f6b65 100644 --- a/lib/memory.h +++ b/lib/memory.h @@ -189,6 +189,8 @@ enum MTYPE_VRF, MTYPE_VRF_NAME, + + MTYPE_PRIVS, MTYPE_MAX }; @@ -33,6 +33,7 @@ #include "log.h" #include "prefix.h" #include "filter.h" +#include "privs.h" /* Vty events */ enum event @@ -1851,7 +1852,8 @@ vty_serv_un (char *path) int sock, len; struct sockaddr_un serv; mode_t old_mask; - + struct zprivs_ids_t ids; + /* First of all, unlink existing socket */ unlink (path); @@ -1894,6 +1896,18 @@ vty_serv_un (char *path) umask (old_mask); + zprivs_get_ids(&ids); + + if (ids.gid_vty > 0) + { + /* set group of socket */ + if ( chown (path, -1, ids.gid_vty) ) + { + zlog_err ("vty_serv_un: could chown socket, %s", + strerror (errno) ); + } + } + vty_event (VTYSH_SERV, sock, NULL); } diff --git a/lib/zebra.h b/lib/zebra.h index 62566cf8..15608dbc 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -42,6 +42,8 @@ typedef int socklen_t; #include <fcntl.h> #include <signal.h> #include <string.h> +#include <pwd.h> +#include <grp.h> #ifdef HAVE_STROPTS_H #include <stropts.h> #endif /* HAVE_STROPTS_H */ @@ -70,6 +72,10 @@ typedef int socklen_t; #ifdef HAVE_RUSAGE #include <sys/resource.h> #endif /* HAVE_RUSAGE */ +#ifdef HAVE_LCAPS +#include <sys/capability.h> +#include <sys/prctl.h> +#endif /* HAVE_LCAPS */ /* machine dependent includes */ #ifdef SUNOS_5 diff --git a/ospf6d/Makefile.am b/ospf6d/Makefile.am index 680e89b8..e42814af 100644 --- a/ospf6d/Makefile.am +++ b/ospf6d/Makefile.am @@ -28,7 +28,7 @@ noinst_HEADERS = \ ospf6d_SOURCES = \ ospf6_main.c $(libospf6_a_SOURCES) -ospf6d_LDADD = -L../lib -lzebra +ospf6d_LDADD = -L../lib -lzebra @LIBCAP@ sysconf_DATA = ospf6d.conf.sample diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c index 10203bf8..e6cd6aaa 100644 --- a/ospf6d/ospf6_main.c +++ b/ospf6d/ospf6_main.c @@ -27,6 +27,7 @@ #include "command.h" #include "vty.h" #include "memory.h" +#include "privs.h" #include "ospf6d.h" #include "ospf6_network.h" @@ -43,6 +44,26 @@ extern int ospf6_sock; /* Default port values. */ #define OSPF6_VTY_PORT 2606 +/* ospf6d privileges */ +zebra_capabilities_t _caps_p [] = +{ + ZCAP_RAW, + ZCAP_BIND +}; + +struct zebra_privs_t ospf6d_privs = +{ +#if defined(ZEBRA_USER) + .user = ZEBRA_USER, +#endif +#if defined ZEBRA_GROUP + .group = ZEBRA_GROUP, +#endif + .caps_p = _caps_p, + .cap_num_p = 2, + .cap_num_i = 0 +}; + /* ospf6d options, we use GNU getopt library. */ struct option longopts[] = { @@ -51,6 +72,7 @@ struct option longopts[] = { "pid_file", required_argument, NULL, 'i'}, { "vty_addr", required_argument, NULL, 'A'}, { "vty_port", required_argument, NULL, 'P'}, + { "user", required_argument, NULL, 'u'}, { "version", no_argument, NULL, 'v'}, { "help", no_argument, NULL, 'h'}, { 0 } @@ -93,6 +115,7 @@ Daemon which manages OSPF version 3.\n\n\ -i, --pid_file Set process identifier file name\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ +-u, --user User and group to run as\n\ -v, --version Print program version\n\ -h, --help Display this help and exit\n\ \n\ @@ -231,7 +254,7 @@ main (int argc, char *argv[], char *envp[]) /* Command line argument treatment. */ while (1) { - opt = getopt_long (argc, argv, "df:hp:A:P:v", longopts, 0); + opt = getopt_long (argc, argv, "df:hp:A:P:u:v", longopts, 0); if (opt == EOF) break; @@ -263,6 +286,9 @@ main (int argc, char *argv[], char *envp[]) vty_port = atoi (optarg); vty_port = (vty_port ? vty_port : OSPF6_VTY_PORT); break; + case 'u': + ospf6d_privs.user = ospf6d_privs.group = optarg; + break; case 'v': print_version (progname); exit (0); @@ -288,6 +314,7 @@ main (int argc, char *argv[], char *envp[]) zlog_default = openzlog (progname, flag, ZLOG_OSPF6, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); + zprivs_init (&ospf6d_privs); signal_init (); cmd_init (1); vty_init (); diff --git a/ospf6d/ospf6_network.c b/ospf6d/ospf6_network.c index e90614e5..ece34135 100644 --- a/ospf6d/ospf6_network.c +++ b/ospf6d/ospf6_network.c @@ -23,6 +23,7 @@ #include "memory.h" #include "log.h" #include "sockunion.h" +#include "privs.h" #include "ospf6d.h" #include "ospf6_proto.h" @@ -32,6 +33,7 @@ extern struct sockaddr_in6 allspfrouters6; extern struct sockaddr_in6 alldrouters6; extern int ospf6_sock; extern struct thread_master *master; +extern struct zebra_privs_t ospf6d_privs; /* iovec functions */ void @@ -194,6 +196,10 @@ iov_copy_all (struct iovec *dst, struct iovec *src, size_t size) int ospf6_serv_sock () { + + if (ospf6d_privs.change (ZPRIVS_RAISE)) + zlog_err ("ospf6_serv_sock: could not raise privs"); + ospf6_sock = socket (AF_INET6, SOCK_RAW, IPPROTO_OSPFIGP); if (ospf6_sock < 0) { @@ -202,6 +208,9 @@ ospf6_serv_sock () } sockopt_reuseaddr (ospf6_sock); + if (ospf6d_privs.change (ZPRIVS_LOWER)) + zlog_err ("ospf_sock_init: could not lower privs"); + /* setup global sockaddr_in6, allspf6 & alldr6 for later use */ allspfrouters6.sin6_family = AF_INET6; alldrouters6.sin6_family = AF_INET6; diff --git a/ospfclient/Makefile.am b/ospfclient/Makefile.am index 95a74eec..fb041af9 100644 --- a/ospfclient/Makefile.am +++ b/ospfclient/Makefile.am @@ -16,6 +16,6 @@ ospfapiheader_HEADERS = \ ospfclient_SOURCES = \ ospfclient.c $(libospfapiclient_a_SOURCES) -ospfclient_LDADD = ../ospfd/libospf.a ../lib/libzebra.a +ospfclient_LDADD = ../ospfd/libospf.a ../lib/libzebra.a @LIBCAP@ diff --git a/ospfclient/ospfclient.c b/ospfclient/ospfclient.c index ec1aabcb..28010872 100644 --- a/ospfclient/ospfclient.c +++ b/ospfclient/ospfclient.c @@ -11,6 +11,8 @@ #include <zebra.h> #include "prefix.h" /* needed by ospf_asbr.h */ +#include "privs.h" + #include "ospfd/ospfd.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_lsa.h" @@ -18,6 +20,18 @@ #include "ospfd/ospf_api.h" #include "ospf_apiclient.h" +/* privileges struct. + * set cap_num_* and uid/gid to nothing to use NULL privs + * as ospfapiclient links in libospf.a which uses privs. + */ +struct zebra_privs_t ospfd_privs = +{ + .user = NULL, + .group = NULL, + .cap_num_p = 0, + .cap_num_i = 0 +}; + /* The following includes are specific to this application. For example it uses threads from libzebra, however your application is free to use any thread library (like pthreads). */ @@ -274,6 +288,7 @@ main (int argc, char *argv[]) } /* Initialization */ + zprivs_init (&ospfd_privs); master = thread_master_create (); /* Open connection to OSPF daemon */ diff --git a/ospfd/Makefile.am b/ospfd/Makefile.am index 81315dae..81f212c4 100644 --- a/ospfd/Makefile.am +++ b/ospfd/Makefile.am @@ -28,7 +28,7 @@ noinst_HEADERS = \ ospfd_SOURCES = \ ospf_main.c $(libospf_a_SOURCES) -ospfd_LDADD = -L../lib -lzebra +ospfd_LDADD = -L../lib -lzebra @LIBCAP@ sysconf_DATA = ospfd.conf.sample diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index 0ac82a68..b1d1fd4c 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -36,6 +36,8 @@ #include "stream.h" #include "log.h" #include "memory.h" +#include "privs.h" +#include "debug.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" @@ -47,6 +49,29 @@ #include "ospfd/ospf_zebra.h" #include "ospfd/ospf_vty.h" +/* ospfd privileges */ +zebra_capabilities_t _caps_p [] = +{ + ZCAP_RAW, + ZCAP_BIND, + ZCAP_BROADCAST, + ZCAP_ADMIN, +}; + +struct zebra_privs_t ospfd_privs = +{ +#if defined(ZEBRA_USER) && defined(ZEBRA_GROUP) + .user = ZEBRA_USER, + .group = ZEBRA_GROUP, +#endif +#if defined(VTY_GROUP) + .vty_group = VTY_GROUP, +#endif + .caps_p = _caps_p, + .cap_num_p = sizeof(_caps_p)/sizeof(_caps_p[0]), + .cap_num_i = 0 +}; + /* Configuration filename and directory. */ char config_current[] = OSPF_DEFAULT_CONFIG; char config_default[] = SYSCONFDIR OSPF_DEFAULT_CONFIG; @@ -61,6 +86,7 @@ struct option longopts[] = { "help", no_argument, NULL, 'h'}, { "vty_addr", required_argument, NULL, 'A'}, { "vty_port", required_argument, NULL, 'P'}, + { "user", required_argument, NULL, 'u'}, { "version", no_argument, NULL, 'v'}, { 0 } }; @@ -88,6 +114,7 @@ Daemon which manages OSPF.\n\n\ -i, --pid_file Set process identifier file name\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ +-u, --user User and group to run as\n\ -v, --version Print program version\n\ -h, --help Display this help and exit\n\ \n\ @@ -162,6 +189,11 @@ signal_init () signal_set (SIGTTOU, SIG_IGN); #endif signal_set (SIGUSR1, sigusr1); +#ifdef HAVE_GLIBC_BACKTRACE + signal_set (SIGBUS, debug_print_trace); + signal_set (SIGSEGV, debug_print_trace); + signal_set (SIGILL, debug_print_trace); +#endif /* HAVE_GLIBC_BACKTRACE */ } /* OSPFd main routine. */ @@ -200,7 +232,7 @@ main (int argc, char **argv) { int opt; - opt = getopt_long (argc, argv, "dlf:hA:P:v", longopts, 0); + opt = getopt_long (argc, argv, "dlf:hA:P:u:v", longopts, 0); if (opt == EOF) break; @@ -232,6 +264,9 @@ main (int argc, char **argv) vty_port = atoi (optarg); vty_port = (vty_port ? vty_port : OSPF_VTY_PORT); break; + case 'u': + ospfd_privs.group = ospfd_privs.user = optarg; + break; case 'v': print_version (progname); exit (0); @@ -249,6 +284,7 @@ main (int argc, char **argv) master = om->master; /* Library inits. */ + zprivs_init (&ospfd_privs); signal_init (); cmd_init (1); debug_init (); diff --git a/ospfd/ospf_network.c b/ospfd/ospf_network.c index 56ec8647..87aec1e5 100644 --- a/ospfd/ospf_network.c +++ b/ospfd/ospf_network.c @@ -29,6 +29,9 @@ #include "sockunion.h" #include "log.h" #include "sockopt.h" +#include "privs.h" + +extern struct zebra_privs_t ospfd_privs; #include "ospfd/ospfd.h" #include "ospfd/ospf_network.h" @@ -39,6 +42,8 @@ #include "ospfd/ospf_neighbor.h" #include "ospfd/ospf_packet.h" + + /* Join to the OSPF ALL SPF ROUTERS multicast group. */ int ospf_if_add_allspfrouters (struct ospf *top, struct prefix *p, @@ -151,12 +156,20 @@ ospf_sock_init (void) int ospf_sock; int ret, tos, hincl = 1; + if ( ospfd_privs.change (ZPRIVS_RAISE) ) + zlog_err ("ospf_sock_init: could not raise privs, %s", + strerror (errno) ); + ospf_sock = socket (AF_INET, SOCK_RAW, IPPROTO_OSPFIGP); if (ospf_sock < 0) { + if ( ospfd_privs.change (ZPRIVS_LOWER) ) + zlog_err ("ospf_sock_init: could not lower privs, %s", + strerror (errno) ); zlog_warn ("ospf_read_sock_init: socket: %s", strerror (errno)); return -1; } + /* Set precedence field. */ #ifdef IPTOS_PREC_INTERNETCONTROL @@ -165,6 +178,9 @@ ospf_sock_init (void) (char *) &tos, sizeof (int)); if (ret < 0) { + if ( ospfd_privs.change (ZPRIVS_LOWER) ) + zlog_err ("ospf_sock_init: could not lower privs, %s", + strerror (errno) ); zlog_warn ("can't set sockopt IP_TOS %d to socket %d", tos, ospf_sock); close (ospf_sock); /* Prevent sd leak. */ return ret; @@ -174,19 +190,40 @@ ospf_sock_init (void) /* we will include IP header with packet */ ret = setsockopt (ospf_sock, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof (hincl)); if (ret < 0) - zlog_warn ("Can't set IP_HDRINCL option"); + { + if ( ospfd_privs.change (ZPRIVS_LOWER) ) + zlog_err ("ospf_sock_init: could not lower privs, %s", + strerror (errno) ); + zlog_warn ("Can't set IP_HDRINCL option"); + } #if defined (IP_PKTINFO) ret = setsockopt (ospf_sock, IPPROTO_IP, IP_PKTINFO, &hincl, sizeof (hincl)); if (ret < 0) - zlog_warn ("Can't set IP_PKTINFO option"); + { + if ( ospfd_privs.change (ZPRIVS_LOWER) ) + zlog_err ("ospf_sock_init: could not lower privs, %s", + strerror (errno) ); + zlog_warn ("Can't set IP_PKTINFO option"); + } #elif defined (IP_RECVIF) ret = setsockopt (ospf_sock, IPPROTO_IP, IP_RECVIF, &hincl, sizeof (hincl)); if (ret < 0) - zlog_warn ("Can't set IP_RECVIF option"); + { + if ( ospfd_privs.change (ZPRIVS_LOWER) ) + zlog_err ("ospf_sock_init: could not lower privs, %s", + strerror (errno) ); + zlog_warn ("Can't set IP_RECVIF option"); + } #else #warning "cannot be able to receive link information on this OS" #endif + + if (ospfd_privs.change (ZPRIVS_LOWER)) + { + zlog_err ("ospf_sock_init: could not lower privs, %s", + strerror (errno) ); + } return ospf_sock; } diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index d8646f07..a12a0115 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -53,6 +53,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "ospfd/ospf_ase.h" + /* OSPF process wide configuration. */ static struct ospf_master ospf_master; diff --git a/redhat/zebra.pam b/redhat/zebra.pam index fb17f59e..1390edf4 100644 --- a/redhat/zebra.pam +++ b/redhat/zebra.pam @@ -1,10 +1,26 @@ #%PAM-1.0 # + +##### if running zebra as root: # Only allow root (and possibly wheel) to use this because enable access # is unrestricted. +# auth sufficient /lib/security/pam_rootok.so -auth sufficient /lib/security/pam_rootok.so # Uncomment the following line to implicitly trust users in the "wheel" group. #auth sufficient /lib/security/pam_wheel.so trust use_uid # Uncomment the following line to require a user to be in the "wheel" group. #auth required /lib/security/pam_wheel.so use_uid +########################################################### + +# If using zebra privileges and with a seperate group for vty access, then +# access can be controlled via the vty access group, and pam can simply +# check for valid user/password +# +# only allow local users. +auth required /lib/security/pam_securetty.so +auth required /lib/security/pam_stack.so service=system-auth +auth required /lib/security/pam_nologin.so +account required /lib/security/pam_stack.so service=system-auth +password required /lib/security/pam_stack.so service=system-auth +session required /lib/security/pam_stack.so service=system-auth +session optional /lib/security/pam_console.so diff --git a/redhat/zebra.spec.in b/redhat/zebra.spec.in index ce3a6fb4..85b3b318 100644 --- a/redhat/zebra.spec.in +++ b/redhat/zebra.spec.in @@ -1,4 +1,4 @@ -# conditionals +# configure options %define with_snmp 0 %define with_vtysh 1 %define with_ospf_te 1 @@ -11,6 +11,8 @@ %define with_ospfclient 1 %define with_ospfapi 1 %define with_multipath 64 +%define zebra_user zebra +%define vty_group zebravty # path defines %define _sysconfdir /etc/zebra @@ -22,12 +24,12 @@ %define _libexecdir %{_exec_prefix}/libexec/zebra %define _includedir %{_prefix}/include/zebra %define _libdir %{_exec_prefix}/%{_lib}/zebra -%define _localstatedir %{_prefix}/var/run +%define _localstatedir /var/run/zebra Summary: Routing daemon Name: zebra Version: @VERSION@ -Release: @CONFDATE@ +Release: @CONFDATE@01 License: GPL Group: System Environment/Daemons Source0: ftp://ftp.zebra.org/pub/zebra/%{name}-%{version}.tar.gz @@ -80,10 +82,7 @@ developing OSPF-API and zebra applications. %setup -q %build -./update-autotools %configure \ - --with-cflags="-O2" \ - --enable-netlink \ %if %with_ipv6 --enable-ipv6 \ %endif @@ -119,12 +118,17 @@ developing OSPF-API and zebra applications. --enable-ospfapi=no \ %endif %if %with_pam - --with-libpam + --with-libpam \ %endif - -pushd vtysh -make %{?_smp_mflags} rebuild -popd +%if %zebra_user + --enable-user=%zebra_user \ + --enable-group=%zebra_user \ +%endif +%if %vty_group + --enable-vty-group=%vty_group \ +%endif +--with-cflags="-O2" \ +--enable-netlink make %{?_smp_mflags} MAKEINFO="makeinfo --no-split" @@ -151,6 +155,18 @@ install %{zeb_rh_src}/ospfd.init $RPM_BUILD_ROOT/etc/rc.d/init.d/ospfd install %{zeb_rh_src}/ripd.init $RPM_BUILD_ROOT/etc/rc.d/init.d/ripd install -m644 %{zeb_rh_src}/zebra.pam $RPM_BUILD_ROOT/etc/pam.d/zebra install -m644 %{zeb_rh_src}/zebra.logrotate $RPM_BUILD_ROOT/etc/logrotate.d/zebra +install -d -m750 $RPM_BUILD_ROOT/var/run/zebra + +%pre +# add vty_group +%if %vty_group +groupadd -r %vty_group 2> /dev/null || : +%endif +# add zebra user and group +%if %zebra_user +/usr/sbin/useradd -M -r -s /bin/false -c "Zebra routing suite" \ + -d %_localstatedir %zebra_user 2> /dev/null || : +%endif %post # zebra_spec_add_service <service name> <port/proto> <comment> @@ -235,9 +251,19 @@ fi %doc doc/zebra.html %doc doc/mpls %doc ChangeLog INSTALL NEWS README REPORTING-BUGS SERVICES TODO +%if %zebra_user +%dir %attr(751,%zebra_user,%zebra_user) %{_sysconfdir} +%dir %attr(750,%zebra_user,%zebra_user) /var/log/zebra +%dir %attr(751,%zebra_user,%zebra_user) /var/run/zebra +%else %dir %attr(750,root,root) %{_sysconfdir} %dir %attr(750,root,root) /var/log/zebra %dir %attr(755,root,root) /usr/share/info +%dir %attr(750,root,root) /var/run/zebra +%endif +%if %vty_group +%attr(750,%zebra_user,%vty_group) %{_sysconfdir}/vtysh.conf.sample +%endif %{_infodir}/*info* %{_mandir}/man*/* %{_sbindir}/* @@ -262,6 +288,9 @@ fi %endif %changelog +* Tue Mar 20 2003 Paul Jakma <paul@dishone.st> +- zebra privileges support + * Mon Mar 18 2003 Paul Jakma <paul@dishone.st> - Fix mem leak in 'show thread cpu' - Ralph Keller's OSPF-API diff --git a/ripd/Makefile.am b/ripd/Makefile.am index df9a0af5..2c187e84 100644 --- a/ripd/Makefile.am +++ b/ripd/Makefile.am @@ -17,7 +17,7 @@ noinst_HEADERS = \ ripd_SOURCES = \ rip_main.c $(librip_a_SOURCES) -ripd_LDADD = -L../lib -lzebra +ripd_LDADD = -L../lib -lzebra @LIBCAP@ sysconf_DATA = ripd.conf.sample diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c index 8ec96ae1..c3889295 100644 --- a/ripd/rip_interface.c +++ b/ripd/rip_interface.c @@ -34,6 +34,7 @@ #include "zclient.h" #include "filter.h" #include "sockopt.h" +#include "privs.h" #include "zebra/connected.h" @@ -56,6 +57,8 @@ struct message ri_version_msg[] = {0, NULL} }; +extern struct zebra_privs_t ripd_privs; + /* RIP enabled network vector. */ vector rip_enable_interface; @@ -177,6 +180,9 @@ rip_interface_multicast_set (int sock, struct interface *ifp) from.sin_len = sizeof (struct sockaddr_in); #endif /* HAVE_SIN_LEN */ + if (ripd_privs.change (ZPRIVS_RAISE)) + zlog_err ("rip_interface_multicast_set: could not raise privs"); + ret = bind (sock, (struct sockaddr *) & from, sizeof (struct sockaddr_in)); if (ret < 0) @@ -185,6 +191,9 @@ rip_interface_multicast_set (int sock, struct interface *ifp) return; } + if (ripd_privs.change (ZPRIVS_LOWER)) + zlog_err ("rip_interface_multicast_set: could not lower privs"); + return; } diff --git a/ripd/rip_main.c b/ripd/rip_main.c index 5e560524..9526d7ae 100644 --- a/ripd/rip_main.c +++ b/ripd/rip_main.c @@ -30,6 +30,7 @@ #include "filter.h" #include "keychain.h" #include "log.h" +#include "privs.h" #include "ripd/ripd.h" @@ -43,10 +44,31 @@ static struct option longopts[] = { "vty_addr", required_argument, NULL, 'A'}, { "vty_port", required_argument, NULL, 'P'}, { "retain", no_argument, NULL, 'r'}, + { "user", required_argument, NULL, 'u'}, { "version", no_argument, NULL, 'v'}, { 0 } }; +/* ripd privileges */ +zebra_capabilities_t _caps_p [] = +{ + ZCAP_RAW, + ZCAP_BIND +}; + +struct zebra_privs_t ripd_privs = +{ +#if defined(ZEBRA_USER) + .user = ZEBRA_USER, +#endif +#if defined ZEBRA_GROUP + .group = ZEBRA_GROUP, +#endif + .caps_p = _caps_p, + .cap_num_p = 2, + .cap_num_i = 0 +}; + /* Configuration file and directory. */ char config_current[] = RIPD_DEFAULT_CONFIG; char config_default[] = SYSCONFDIR RIPD_DEFAULT_CONFIG; @@ -85,6 +107,7 @@ Daemon which manages RIP version 1 and 2.\n\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ -r, --retain When program terminates, retain added route by ripd.\n\ +-u, --user User and group to run as\n\ -v, --version Print program version\n\ -h, --help Display this help and exit\n\ \n\ @@ -189,7 +212,7 @@ main (int argc, char **argv) { int opt; - opt = getopt_long (argc, argv, "df:hA:P:rv", longopts, 0); + opt = getopt_long (argc, argv, "df:hA:P:u:rv", longopts, 0); if (opt == EOF) break; @@ -224,6 +247,9 @@ main (int argc, char **argv) case 'r': retain_mode = 1; break; + case 'u': + ripd_privs.group = ripd_privs.user = optarg; + break; case 'v': print_version (progname); exit (0); @@ -241,6 +267,7 @@ main (int argc, char **argv) master = thread_master_create (); /* Library initialization. */ + zprivs_init (&ripd_privs); signal_init (); cmd_init (1); vty_init (); diff --git a/ripd/ripd.c b/ripd/ripd.c index c5d45536..a58406b4 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -37,10 +37,13 @@ #include "distribute.h" #include "md5-gnu.h" #include "keychain.h" +#include "privs.h" #include "ripd/ripd.h" #include "ripd/rip_debug.h" +extern struct zebra_privs_t ripd_privs; + /* RIP Structure. */ struct rip *rip = NULL; @@ -1884,13 +1887,17 @@ rip_create_socket () setsockopt_pktinfo (sock); #endif /* RIP_RECVMSG */ + if (ripd_privs.change (ZPRIVS_RAISE)) + zlog_err ("rip_create_socket: could not raise privs"); ret = bind (sock, (struct sockaddr *) & addr, sizeof (addr)); if (ret < 0) { perror ("bind"); return ret; } - + if (ripd_privs.change (ZPRIVS_LOWER)) + zlog_err ("rip_create_socket: could not lower privs"); + return sock; } diff --git a/ripngd/Makefile.am b/ripngd/Makefile.am index a6810649..d9db576e 100644 --- a/ripngd/Makefile.am +++ b/ripngd/Makefile.am @@ -17,7 +17,7 @@ noinst_HEADERS = \ ripngd_SOURCES = \ ripng_main.c $(libripng_a_SOURCES) -ripngd_LDADD = -L../lib -lzebra +ripngd_LDADD = -L../lib -lzebra @LIBCAP@ sysconf_DATA = ripngd.conf.sample diff --git a/ripngd/ripng_main.c b/ripngd/ripng_main.c index 44c38762..bd1972a1 100644 --- a/ripngd/ripng_main.c +++ b/ripngd/ripng_main.c @@ -32,6 +32,7 @@ #include "log.h" #include "prefix.h" #include "if.h" +#include "privs.h" #include "ripngd/ripngd.h" @@ -51,10 +52,32 @@ struct option longopts[] = { "vty_addr", required_argument, NULL, 'A'}, { "vty_port", required_argument, NULL, 'P'}, { "retain", no_argument, NULL, 'r'}, + { "user", required_argument, NULL, 'u'}, { "version", no_argument, NULL, 'v'}, { 0 } }; +/* ripngd privileges */ +zebra_capabilities_t _caps_p [] = +{ + ZCAP_RAW, + ZCAP_BIND +}; + +struct zebra_privs_t ripngd_privs = +{ +#if defined(ZEBRA_USER) + .user = ZEBRA_USER, +#endif +#if defined ZEBRA_GROUP + .group = ZEBRA_GROUP, +#endif + .caps_p = _caps_p, + .cap_num_p = 2, + .cap_num_i = 0 +}; + + /* RIPngd program name */ /* Route retain mode flag. */ @@ -89,6 +112,7 @@ Daemon which manages RIPng.\n\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ -r, --retain When program terminates, retain added route by ripngd.\n\ +-u, --user User and group to run as\n\ -v, --version Print program version\n\ -h, --help Display this help and exit\n\ \n\ @@ -190,7 +214,7 @@ main (int argc, char **argv) { int opt; - opt = getopt_long (argc, argv, "dlf:hA:P:v", longopts, 0); + opt = getopt_long (argc, argv, "dlf:hA:P:u:v", longopts, 0); if (opt == EOF) break; @@ -228,6 +252,9 @@ main (int argc, char **argv) case 'r': retain_mode = 1; break; + case 'u': + ripngd_privs.group = ripngd_privs.user = optarg; + break; case 'v': print_version (progname); exit (0); @@ -244,6 +271,7 @@ main (int argc, char **argv) master = thread_master_create (); /* Library inits. */ + zprivs_init (&ripngd_privs); signal_init (); cmd_init (1); vty_init (); diff --git a/vtysh/Makefile.am b/vtysh/Makefile.am index 89156f90..7a21409f 100644 --- a/vtysh/Makefile.am +++ b/vtysh/Makefile.am @@ -9,7 +9,7 @@ bin_PROGRAMS = vtysh vtysh_SOURCES = vtysh_main.c vtysh.c vtysh_cmd.c vtysh_user.c vtysh_config.c noinst_HEADERS = vtysh.h vtysh_user.h -vtysh_LDADD = ../lib/libzebra.a +vtysh_LDADD = ../lib/libzebra.a @LIBCAP@ sysconf_DATA = vtysh.conf.sample diff --git a/zebra/Makefile.am b/zebra/Makefile.am index 6214767d..ce564672 100644 --- a/zebra/Makefile.am +++ b/zebra/Makefile.am @@ -13,9 +13,10 @@ rt_method = @RT_METHOD@ rtread_method = @RTREAD_METHOD@ kernel_method = @KERNEL_METHOD@ other_method = @OTHER_METHOD@ +libcap = @LIBCAP@ otherobj = $(ipforward) $(if_method) $(if_proc) $(rt_method) \ - $(rtread_method) $(kernel_method) $(other_method) + $(rtread_method) $(kernel_method) $(other_method) $(libcap) sbin_PROGRAMS = zebra @@ -25,7 +26,7 @@ zebra_SOURCES = \ noinst_HEADERS = \ connected.h ioctl.h rib.h rt.h zserv.h redistribute.h debug.h rtadv.h \ - interface.h ipforward.h irdp.h + interface.h ipforward.h zebra_LDADD = ../lib/libzebra.a $(otherobj) $(LIB_IPV6) @@ -38,7 +39,7 @@ EXTRA_DIST = $(sysconf_DATA) if_ioctl.c if_netlink.c if_proc.c if_sysctl.c \ ipforward_solaris.c ipforward_sysctl.c rt_ioctl.c rt_netlink.c \ rt_socket.c rtread_netlink.c rtread_proc.c rtread_sysctl.c \ rtread_getmsg.c kernel_socket.c kernel_netlink.c mtu_kvm.c \ - GNOME-SMI GNOME-PRODUCT-ZEBRA-MIB irdp.c + GNOME-SMI GNOME-PRODUCT-ZEBRA-MIB #client : client_main.o ../lib/libzebra.a # $(CC) -g -o client client_main.o ../lib/libzebra.a $(LIBS) $(LIB_IPV6) diff --git a/zebra/ioctl.c b/zebra/ioctl.c index 3e5d1d2f..f8e7f22b 100644 --- a/zebra/ioctl.c +++ b/zebra/ioctl.c @@ -27,10 +27,13 @@ #include "prefix.h" #include "ioctl.h" #include "log.h" +#include "privs.h" #include "zebra/rib.h" #include "zebra/rt.h" +extern struct zebra_privs_t zserv_privs; + /* clear and set interface name string */ void ifreq_set_name (struct ifreq *ifreq, struct interface *ifp) @@ -46,14 +49,19 @@ if_ioctl (u_long request, caddr_t buffer) int ret = 0; int err = 0; + if (zserv_privs.change(ZPRIVS_RAISE)) + zlog (NULL, LOG_ERR, "Can't raise privileges"); sock = socket (AF_INET, SOCK_DGRAM, 0); if (sock < 0) { + if (zserv_privs.change(ZPRIVS_LOWER)) + zlog (NULL, LOG_ERR, "Can't lower privileges"); perror ("socket"); exit (1); } - ret = ioctl (sock, request, buffer); + if (zserv_privs.change(ZPRIVS_LOWER)) + zlog (NULL, LOG_ERR, "Can't lower privileges"); if (ret < 0) { err = errno; @@ -76,14 +84,21 @@ if_ioctl_ipv6 (u_long request, caddr_t buffer) int ret = 0; int err = 0; + if (zserv_privs.change(ZPRIVS_RAISE)) + zlog (NULL, LOG_ERR, "Can't raise privileges"); sock = socket (AF_INET6, SOCK_DGRAM, 0); if (sock < 0) { + if (zserv_privs.change(ZPRIVS_LOWER)) + zlog (NULL, LOG_ERR, "Can't lower privileges"); perror ("socket"); exit (1); } ret = ioctl (sock, request, buffer); + if (zserv_privs.change(ZPRIVS_LOWER)) + zlog (NULL, LOG_ERR, "Can't lower privileges"); + if (ret < 0) { err = errno; diff --git a/zebra/ipforward_proc.c b/zebra/ipforward_proc.c index eb8cef01..a31ec84b 100644 --- a/zebra/ipforward_proc.c +++ b/zebra/ipforward_proc.c @@ -22,6 +22,11 @@ #include <zebra.h> +#include "log.h" +#include "privs.h" + +extern struct zebra_privs_t zserv_privs; + char proc_net_snmp[] = "/proc/net/snmp"; static void @@ -68,9 +73,15 @@ int ipforward_on () { FILE *fp; + + if ( zserv_privs.change(ZPRIVS_RAISE) ) + zlog_err ("Can't raise privileges, %s", strerror (errno) ); fp = fopen (proc_ipv4_forwarding, "w"); - + + if ( zserv_privs.change(ZPRIVS_LOWER) ) + zlog_err ("Can't lower privileges, %s", strerror (errno)); + if (fp == NULL) return -1; @@ -86,7 +97,14 @@ ipforward_off () { FILE *fp; + if ( zserv_privs.change(ZPRIVS_RAISE) ) + zlog_err ("Can't raise privileges, %s", strerror (errno)); + fp = fopen (proc_ipv4_forwarding, "w"); + + if ( zserv_privs.change(ZPRIVS_LOWER) ) + zlog_err ("Can't lower privileges, %s", strerror (errno)); + if (fp == NULL) return -1; @@ -124,7 +142,13 @@ ipforward_ipv6_on () { FILE *fp; + if ( zserv_privs.change(ZPRIVS_RAISE) ) + zlog_err ("Can't raise privileges, %s", strerror (errno)); + fp = fopen (proc_ipv6_forwarding, "w"); + + if ( zserv_privs.change(ZPRIVS_LOWER) ) + zlog_err ("Can't lower privileges, %s", strerror (errno)); if (fp == NULL) return -1; @@ -141,7 +165,13 @@ ipforward_ipv6_off () { FILE *fp; + if ( zserv_privs.change(ZPRIVS_RAISE) ) + zlog_err ("Can't raise privileges, %s", strerror (errno)); + fp = fopen (proc_ipv6_forwarding, "w"); + + if ( zserv_privs.change(ZPRIVS_LOWER) ) + zlog_err ("Can't lower privileges, %s", strerror (errno)); if (fp == NULL) return -1; diff --git a/zebra/ipforward_solaris.c b/zebra/ipforward_solaris.c index 63d1110c..fe06e74d 100644 --- a/zebra/ipforward_solaris.c +++ b/zebra/ipforward_solaris.c @@ -22,6 +22,7 @@ #include <zebra.h> #include "log.h" +#include "prefix.h" /* ** Solaris should define IP_DEV_NAME in <inet/ip.h>, but we'll save @@ -33,6 +34,9 @@ #define IP_DEV_NAME "/dev/ip" #endif /* + +extern struct zebra_privs_t zserv_privs; + ** This is a limited ndd style function that operates one integer ** value only. Errors return -1. ND_SET commands return 0 on ** success. ND_GET commands return the value on success (which could @@ -63,30 +67,48 @@ solaris_nd(const int cmd, const char* parameter, const int value) zlog_err("internal error - inappropriate command given to solaris_nd()%s:%d", __FILE__, __LINE__); return -1; } + strioctl.ic_cmd = cmd; strioctl.ic_timout = 0; strioctl.ic_len = ND_BUFFER_SIZE; strioctl.ic_dp = nd_buf; - if ((fd = open (device, O_RDWR)) < 0) { - zlog_warn("failed to open device %s - %s", device, strerror(errno)); - return -1; - } - if (ioctl (fd, I_STR, &strioctl) < 0) { - close (fd); - zlog_warn("ioctl I_STR failed on device %s - %s", device,strerror(errno)); - return -1; - } + + if ( zserv_privs.change (ZPRIVS_RAISE) ) + zlog_err ("solaris_nd: Can't raise privileges"); + if ((fd = open (device, O_RDWR)) < 0) + { + zlog_warn("failed to open device %s - %s", device, strerror(errno)); + if ( zserv_privs.change (ZPRIVS_LOWER) ) + zlog_err ("solaris_nd: Can't lower privileges"); + return -1; + } + if (ioctl (fd, I_STR, &strioctl) < 0) + { + if ( zserv_privs.change (ZPRIVS_LOWER) ) + zlog_err ("solaris_nd: Can't lower privileges"); + close (fd); + zlog_warn("ioctl I_STR failed on device %s - %s", device,strerror(errno)); + return -1; + } close(fd); - if (cmd == ND_GET) { - errno = 0; - retval = atoi(nd_buf); - if (errno) { - zlog_warn("failed to convert returned value to integer - %s",strerror(errno)); - retval = -1; + if ( zserv_privs.change (ZPRIVS_LOWER) ) + zlog_err ("solaris_nd: Can't lower privileges"); + + if (cmd == ND_GET) + { + errno = 0; + retval = atoi(nd_buf); + if (errno) + { + zlog_warn("failed to convert returned value to integer - %s", + strerror(errno)); + retval = -1; + } + } + else + { + retval = 0; } - } else { - retval = 0; - } return retval; } diff --git a/zebra/ipforward_sysctl.c b/zebra/ipforward_sysctl.c index 828eb865..53b6c6f0 100644 --- a/zebra/ipforward_sysctl.c +++ b/zebra/ipforward_sysctl.c @@ -20,6 +20,7 @@ */ #include <zebra.h> +#include "privs.h" #ifdef NRL #include <netinet6/in6.h> @@ -29,6 +30,8 @@ #define MIB_SIZ 4 +extern struct zebra_privs_t zserv_privs; + /* IPv4 forwarding control MIB. */ int mib[MIB_SIZ] = { @@ -60,11 +63,17 @@ ipforward_on () int ipforwarding = 1; len = sizeof ipforwarding; - if (sysctl (mib, MIB_SIZ, NULL, NULL, &ipforwarding, len) < 0) + if (zserv_privs.change(ZPRIVS_RAISE)) + zlog (NULL, LOG_ERR, "Can't raise privileges"); + if (sysctl (mib, MIB_SIZ, NULL, NULL, &ipforwarding, len) < 0) { + if (zserv_privs.change(ZPRIVS_LOWER)) + zlog (NULL, LOG_ERR, "Can't lower privileges"); zlog_warn ("Can't set ipforwarding on"); return -1; } + if (zserv_privs.change(ZPRIVS_LOWER)) + zlog (NULL, LOG_ERR, "Can't lower privileges"); return ipforwarding; } @@ -75,11 +84,17 @@ ipforward_off () int ipforwarding = 0; len = sizeof ipforwarding; - if (sysctl (mib, MIB_SIZ, NULL, NULL, &ipforwarding, len) < 0) + if (zserv_privs.change(ZPRIVS_RAISE)) + zlog (NULL, LOG_ERR, "Can't raise privileges"); + if (sysctl (mib, MIB_SIZ, NULL, NULL, &ipforwarding, len) < 0) { + if (zserv_privs.change(ZPRIVS_LOWER)) + zlog (NULL, LOG_ERR, "Can't lower privileges"); zlog_warn ("Can't set ipforwarding on"); return -1; } + if (zserv_privs.change(ZPRIVS_LOWER)) + zlog (NULL, LOG_ERR, "Can't lower privileges"); return ipforwarding; } @@ -106,11 +121,17 @@ ipforward_ipv6 () int ip6forwarding = 0; len = sizeof ip6forwarding; - if (sysctl (mib_ipv6, MIB_SIZ, &ip6forwarding, &len, 0, 0) < 0) + if (zserv_privs.change(ZPRIVS_RAISE)) + zlog (NULL, LOG_ERR, "Can't raise privileges"); + if (sysctl (mib_ipv6, MIB_SIZ, &ip6forwarding, &len, 0, 0) < 0) { + if (zserv_privs.change(ZPRIVS_LOWER)) + zlog (NULL, LOG_ERR, "Can't lower privileges"); zlog_warn ("can't get ip6forwarding value"); return -1; } + if (zserv_privs.change(ZPRIVS_LOWER)) + zlog (NULL, LOG_ERR, "Can't lower privileges"); return ip6forwarding; } @@ -121,11 +142,17 @@ ipforward_ipv6_on () int ip6forwarding = 1; len = sizeof ip6forwarding; - if (sysctl (mib_ipv6, MIB_SIZ, NULL, NULL, &ip6forwarding, len) < 0) + if (zserv_privs.change(ZPRIVS_RAISE)) + zlog (NULL, LOG_ERR, "Can't raise privileges"); + if (sysctl (mib_ipv6, MIB_SIZ, NULL, NULL, &ip6forwarding, len) < 0) { + if (zserv_privs.change(ZPRIVS_LOWER)) + zlog (NULL, LOG_ERR, "Can't lower privileges"); zlog_warn ("can't get ip6forwarding value"); return -1; } + if (zserv_privs.change(ZPRIVS_LOWER)) + zlog (NULL, LOG_ERR, "Can't lower privileges"); return ip6forwarding; } @@ -136,11 +163,17 @@ ipforward_ipv6_off () int ip6forwarding = 0; len = sizeof ip6forwarding; - if (sysctl (mib_ipv6, MIB_SIZ, NULL, NULL, &ip6forwarding, len) < 0) + if (zserv_privs.change(ZPRIVS_RAISE)) + zlog (NULL, LOG_ERR, "Can't raise privileges"); + if (sysctl (mib_ipv6, MIB_SIZ, NULL, NULL, &ip6forwarding, len) < 0) { + if (zserv_privs.change(ZPRIVS_LOWER)) + zlog (NULL, LOG_ERR, "Can't lower privileges"); zlog_warn ("can't get ip6forwarding value"); return -1; } + if (zserv_privs.change(ZPRIVS_LOWER)) + zlog (NULL, LOG_ERR, "Can't lower privileges"); return ip6forwarding; } #endif /* HAVE_IPV6 */ diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 17893a87..30e0fb1d 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -31,11 +31,14 @@ #include "str.h" #include "table.h" #include "rib.h" +#include "privs.h" #include "zebra/interface.h" #include "zebra/zserv.h" #include "zebra/debug.h" +extern struct zebra_privs_t zserv_privs; + /* Socket length roundup function. */ #define ROUNDUP(a) \ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) @@ -798,16 +801,23 @@ kernel_read (struct thread *thread) void routing_socket () { + if ( zserv_privs.change (ZPRIVS_RAISE) ) + zlog_err ("routing_socket: Can't raise privileges"); + routing_sock = socket (AF_ROUTE, SOCK_RAW, 0); if (routing_sock < 0) { + if ( zserv_privs.change (ZPRIVS_LOWER) ) + zlog_err ("routing_socket: Can't lower privileges"); zlog_warn ("Can't init kernel routing socket"); return; } if (fcntl (routing_sock, F_SETFL, O_NONBLOCK) < 0) zlog_warn ("Can't set O_NONBLOCK to routing socket"); + if ( zserv_privs.change (ZPRIVS_LOWER) ) + zlog_err ("routing_socket: Can't lower privileges"); /* kernel_read needs rewrite. */ thread_add_read (master, kernel_read, NULL, routing_sock); diff --git a/zebra/main.c b/zebra/main.c index 66469a2f..72b1fc4e 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -1,5 +1,4 @@ -/* - * zebra daemon main routine. +/* zebra daemon main routine. * Copyright (C) 1997, 98 Kunihiro Ishiguro * * This file is part of GNU Zebra. @@ -30,6 +29,7 @@ #include "memory.h" #include "prefix.h" #include "log.h" +#include "privs.h" #include "zebra/rib.h" #include "zebra/zserv.h" @@ -62,10 +62,32 @@ struct option longopts[] = { "vty_addr", required_argument, NULL, 'A'}, { "vty_port", required_argument, NULL, 'P'}, { "retain", no_argument, NULL, 'r'}, + { "user", required_argument, NULL, 'u'}, { "version", no_argument, NULL, 'v'}, { 0 } }; +zebra_capabilities_t _caps_p [] = +{ + ZCAP_ADMIN, + ZCAP_SYS_ADMIN, +}; + +/* zebra privileges to run with */ +struct zebra_privs_t zserv_privs = +{ +#if defined(ZEBRA_USER) && defined(ZEBRA_GROUP) + .user = ZEBRA_USER, + .group = ZEBRA_GROUP, +#endif +#ifdef VTY_GROUP + .vty_group = VTY_GROUP, +#endif + .caps_p = _caps_p, + .cap_num_p = sizeof(_caps_p)/sizeof(_caps_p[0]), + .cap_num_i = 0 +}; + /* Default configuration file path. */ char config_current[] = DEFAULT_CONFIG_FILE; char config_default[] = SYSCONFDIR DEFAULT_CONFIG_FILE; @@ -93,6 +115,7 @@ redistribution between different routing protocols.\n\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ -r, --retain When program terminates, retain added route by zebra.\n\ +-u, --user User and group to run as\n\ -v, --version Print program version\n\ -h, --help Display this help and exit\n\ \n\ @@ -196,7 +219,7 @@ main (int argc, char **argv) { int opt; - opt = getopt_long (argc, argv, "bdklf:hA:P:rv", longopts, 0); + opt = getopt_long (argc, argv, "bdklf:hA:P:ru:v", longopts, 0); if (opt == EOF) break; @@ -239,6 +262,9 @@ main (int argc, char **argv) case 'r': retain_mode = 1; break; + case 'u': + zserv_privs.user = zserv_privs.group = optarg; + break; case 'v': print_version (progname); exit (0); @@ -255,6 +281,9 @@ main (int argc, char **argv) /* Make master thread emulator. */ master = thread_master_create (); + /* privs initialise */ + zprivs_init (&zserv_privs); + /* Vty related initialize. */ signal_init (); cmd_init (1); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 87062dc5..e1514623 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -34,6 +34,7 @@ #include "table.h" #include "rib.h" #include "thread.h" +#include "privs.h" #include "zebra/zserv.h" #include "zebra/redistribute.h" @@ -67,6 +68,8 @@ struct message nlmsg_str[] = extern int rtm_table_default; +extern struct zebra_privs_t zserv_privs; + /* Make socket for Linux netlink interface. */ static int netlink_socket (struct nlsock *nl, unsigned long groups) @@ -98,14 +101,25 @@ netlink_socket (struct nlsock *nl, unsigned long groups) snl.nl_groups = groups; /* Bind the socket to the netlink structure for anything. */ + if ( zserv_privs.change(ZPRIVS_RAISE) ) + { + zlog (NULL, LOG_ERR, "Can't raise privileges"); + return -1; + } + ret = bind (sock, (struct sockaddr *) &snl, sizeof snl); if (ret < 0) { + if ( zserv_privs.change(ZPRIVS_LOWER) ) + zlog (NULL, LOG_ERR, "Can't lower privileges"); zlog (NULL, LOG_ERR, "Can't bind %s socket to group 0x%x: %s", nl->name, snl.nl_groups, strerror (errno)); close (sock); return -1; } + + if ( zserv_privs.change(ZPRIVS_LOWER) ) + zlog (NULL, LOG_ERR, "Can't lower privileges"); /* multiple netlink sockets will have different nl_pid */ namelen = sizeof snl; @@ -186,14 +200,28 @@ netlink_request (int family, int type, struct nlsock *nl) req.nlh.nlmsg_pid = 0; req.nlh.nlmsg_seq = ++nl->seq; req.g.rtgen_family = family; + + /* linux appears to check capabilities on every message + * have to raise caps for every message sent + */ + if ( zserv_privs.change(ZPRIVS_RAISE) ) + { + zlog (NULL, LOG_ERR, "Can't raise privileges"); + return -1; + } ret = sendto (nl->sock, (void*) &req, sizeof req, 0, (struct sockaddr*) &snl, sizeof snl); + + if ( zserv_privs.change(ZPRIVS_LOWER) ) + zlog (NULL, LOG_ERR, "Can't lower privileges"); + if (ret < 0) - { + { zlog (NULL, LOG_ERR, "%s sendto failed: %s", nl->name, strerror (errno)); return -1; } + return 0; } @@ -215,7 +243,13 @@ netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *), struct msghdr msg = { (void*)&snl, sizeof snl, &iov, 1, NULL, 0, 0}; struct nlmsghdr *h; + if ( zserv_privs.change(ZPRIVS_RAISE) ) + zlog (NULL, LOG_ERR, "Can't raise privileges"); + status = recvmsg (nl->sock, &msg, 0); + + if ( zserv_privs.change(ZPRIVS_LOWER) ) + zlog (NULL, LOG_ERR, "Can't lower privileges"); if (status < 0) { @@ -1104,7 +1138,12 @@ netlink_talk (struct nlmsghdr *n, struct nlsock *nl) n->nlmsg_seq); /* Send message to netlink interface. */ + if ( zserv_privs.change(ZPRIVS_RAISE) ) + zlog (NULL, LOG_ERR, "Can't raise privileges"); status = sendmsg (nl->sock, &msg, 0); + if ( zserv_privs.change(ZPRIVS_LOWER) ) + zlog (NULL, LOG_ERR, "Can't lower privileges"); + if (status < 0) { zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s", diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index 19b2fc2f..d603c60d 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -27,10 +27,13 @@ #include "sockunion.h" #include "log.h" #include "str.h" +#include "privs.h" #include "zebra/debug.h" #include "zebra/rib.h" +extern struct zebra_privs_t zserv_privs; + int rtm_write (int message, union sockunion *dest, @@ -187,13 +190,29 @@ kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib, int family) int kernel_add_ipv4 (struct prefix *p, struct rib *rib) { - return kernel_rtm_ipv4 (RTM_ADD, p, rib, AF_INET); + int route; + + if (zserv_privs.change(ZPRIVS_RAISE)) + zlog (NULL, LOG_ERR, "Can't raise privileges"); + route = kernel_rtm_ipv4 (RTM_ADD, p, rib, AF_INET); + if (zserv_privs.change(ZPRIVS_LOWER)) + zlog (NULL, LOG_ERR, "Can't lower privileges"); + + return route; } int kernel_delete_ipv4 (struct prefix *p, struct rib *rib) { - return kernel_rtm_ipv4 (RTM_DELETE, p, rib, AF_INET); + int route; + + if (zserv_privs.change(ZPRIVS_RAISE)) + zlog (NULL, LOG_ERR, "Can't raise privileges"); + route = kernel_rtm_ipv4 (RTM_DELETE, p, rib, AF_INET); + if (zserv_privs.change(ZPRIVS_LOWER)) + zlog (NULL, LOG_ERR, "Can't lower privileges"); + + return route; } #ifdef HAVE_IPV6 @@ -421,13 +440,29 @@ kernel_rtm_ipv6_multipath (int cmd, struct prefix *p, struct rib *rib, int kernel_add_ipv6 (struct prefix *p, struct rib *rib) { - return kernel_rtm_ipv6_multipath (RTM_ADD, p, rib, AF_INET6); + int route; + + if (zserv_privs.change(ZPRIVS_RAISE)) + zlog (NULL, LOG_ERR, "Can't raise privileges"); + route = kernel_rtm_ipv6_multipath (RTM_ADD, p, rib, AF_INET6); + if (zserv_privs.change(ZPRIVS_LOWER)) + zlog (NULL, LOG_ERR, "Can't lower privileges"); + + return route; } int kernel_delete_ipv6 (struct prefix *p, struct rib *rib) { - return kernel_rtm_ipv6_multipath (RTM_DELETE, p, rib, AF_INET6); + int route; + + if (zserv_privs.change(ZPRIVS_RAISE)) + zlog (NULL, LOG_ERR, "Can't raise privileges"); + route = kernel_rtm_ipv6_multipath (RTM_DELETE, p, rib, AF_INET6); + if (zserv_privs.change(ZPRIVS_LOWER)) + zlog (NULL, LOG_ERR, "Can't lower privileges"); + + return route; } /* Delete IPv6 route from the kernel. */ @@ -435,6 +470,14 @@ int kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate, int index, int flags, int table) { - return kernel_rtm_ipv6 (RTM_DELETE, dest, gate, index, flags); + int route; + + if (zserv_privs.change(ZPRIVS_RAISE)) + zlog (NULL, LOG_ERR, "Can't raise privileges"); + route = kernel_rtm_ipv6 (RTM_DELETE, dest, gate, index, flags); + if (zserv_privs.change(ZPRIVS_LOWER)) + zlog (NULL, LOG_ERR, "Can't lower privileges"); + + return route; } #endif /* HAVE_IPV6 */ diff --git a/zebra/rtadv.c b/zebra/rtadv.c index 8f4b3778..9dcee8ea 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -29,11 +29,14 @@ #include "prefix.h" #include "linklist.h" #include "command.h" +#include "privs.h" #include "zebra/interface.h" #include "zebra/rtadv.h" #include "zebra/debug.h" +extern struct zebra_privs_t zserv_privs; + #if defined (HAVE_IPV6) && defined (RTADV) /* If RFC2133 definition is used. */ @@ -143,7 +146,7 @@ rtadv_send_packet (int sock, struct interface *ifp) struct cmsghdr *cmsgptr; struct in6_pktinfo *pkt; struct sockaddr_in6 addr; -#if HAVE_SOCKADDR_DL +#ifdef HAVE_SOCKADDR_DL struct sockaddr_dl *sdl; #endif /* HAVE_SOCKADDR_DL */ char adata [sizeof (struct cmsghdr) + sizeof (struct in6_pktinfo)]; @@ -409,8 +412,16 @@ rtadv_make_socket (void) int ret; struct icmp6_filter filter; + if ( zserv_privs.change (ZPRIVS_RAISE) ) + zlog_err ("rtadv_make_socket: could not raise privs, %s", + strerror (errno) ); + sock = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); + if ( zserv_privs.change (ZPRIVS_LOWER) ) + zlog_err ("rtadv_make_socket: could not lower privs, %s", + strerror (errno) ); + /* When we can't make ICMPV6 socket simply back. Router advertisement feature will not be supported. */ if (sock < 0) diff --git a/zebra/zserv.c b/zebra/zserv.c index 70e7672d..975574af 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -33,6 +33,7 @@ #include "sockunion.h" #include "log.h" #include "zclient.h" +#include "privs.h" #include "zebra/zserv.h" #include "zebra/redistribute.h" @@ -50,6 +51,8 @@ int rtm_table_default = 0; void zebra_event (enum event event, int sock, struct zserv *client); +extern struct zebra_privs_t zserv_privs; + extern struct thread_master *master; /* For logging of zebra meesages. */ @@ -1638,6 +1641,9 @@ zebra_serv () sockopt_reuseaddr (accept_sock); sockopt_reuseport (accept_sock); + if ( zserv_privs.change(ZPRIVS_RAISE) ) + zlog (NULL, LOG_ERR, "Can't raise privileges"); + ret = bind (accept_sock, (struct sockaddr *)&addr, sizeof (struct sockaddr_in)); if (ret < 0) @@ -1647,6 +1653,9 @@ zebra_serv () close (accept_sock); /* Avoid sd leak. */ return; } + + if ( zserv_privs.change(ZPRIVS_LOWER) ) + zlog (NULL, LOG_ERR, "Can't lower privileges"); ret = listen (accept_sock, 1); if (ret < 0) |