diff options
40 files changed, 2547 insertions, 476 deletions
diff --git a/Makefile.am b/Makefile.am index 72a09dcf..0c7b1fbf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,16 +1,19 @@ ## Process this file with automake to produce Makefile.in. -SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @VTYSH@ doc +SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ \ + @VTYSH@ @OSPFCLIENT@ doc + +DIST_SUBDIRS = lib zebra bgpd ripd ripngd ospfd ospf6d vtysh \ + ospfclient doc EXTRA_DIST = aclocal.m4 SERVICES TODO REPORTING-BUGS vtysh/Makefile.in \ - vtysh/Makefile.am update-autotools + vtysh/Makefile.am update-autotools doc/mpls dist-hook: mkdir $(distdir)/tools cp -p $(srcdir)/tools/*.pl $(distdir)/tools cp -p $(srcdir)/tools/*.el $(distdir)/tools cp -p $(srcdir)/tools/*.cgi $(distdir)/tools - mkdir $(distdir)/init - mkdir $(distdir)/init/redhat - cp -p $(srcdir)/init/redhat/*.init $(distdir)/init/redhat - cp -p $(srcdir)/init/redhat/zebra.* $(distdir)/init/redhat + cp -p $(srcdir)/redhat/*.init $(distdir)/redhat + cp -p $(srcdir)/redhat/zebra.* $(distdir)/redhat + rm -rf `find $(distdir)/doc -type d -name CVS` 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 7fc68fa7..60a7ee76 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,21 @@ char *pid_file = PATH_BGPD_PID; int vty_port = BGP_VTY_PORT; char *vty_addr = NULL; +/* privileges */ +struct zebra_privs_t bgpd_privs = +{ + .caps_p = + { + ZCAP_BIND + }, + .cap_num_p = 1, + .cap_num_i = 0, +#if defined(ZEBRA_USER) && defined(ZEBRA_GROUP) + .user = ZEBRA_USER, + .group = ZEBRA_GROUP +#endif +}; + /* Help information display. */ static void usage (char *progname, int status) @@ -89,6 +106,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\ @@ -113,7 +131,7 @@ sighup (int sig) vty_read_config (config_file, config_current, config_default); /* Create VTY's socket */ - vty_serv_sock (vty_addr, vty_port ? vty_port : BGP_VTY_PORT, BGP_VTYSH_PATH); + vty_serv_sock (vty_addr, vty_port, BGP_VTYSH_PATH); /* Try to return to normal operation. */ } @@ -197,7 +215,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; @@ -222,7 +240,15 @@ main (int argc, char **argv) vty_addr = optarg; break; case 'P': - vty_port = atoi (optarg); + /* Deal with atoi() returning 0 on failure, and bgpd not + listening on bgp port... */ + if (strcmp(optarg, "0") == 0) + { + vty_port = 0; + break; + } + vty_port = atoi (optarg); + vty_port = (vty_port ? vty_port : BGP_VTY_PORT); break; case 'r': retain_mode = 1; @@ -230,6 +256,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); @@ -249,6 +278,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 1adc8a7f..fd264b7a 100755 --- a/configure.ac +++ b/configure.ac @@ -4,7 +4,7 @@ ## ## Copyright (c) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro <kunihiro@zebra.org> ## -AC_PREREQ(2.53) +AC_PREREQ(2.13) AC_INIT(lib/zebra.h) AM_INIT_AUTOMAKE(zebra, 0.94) @@ -87,11 +87,23 @@ dnl Temporary option until OSPF NSSA implementation complete AC_ARG_ENABLE(nssa, [ --enable-nssa enable OSPF NSSA option]) AC_ARG_ENABLE(opaque-lsa, -[ --enable-opaque-lsa enable OSPF Opaque-LSA support (RFC2370)]) +[ --enable-opaque-lsa enable OSPF Opaque-LSA with OSPFAPI support (RFC2370)]) +AC_ARG_ENABLE(ospfapi, +[ --disable-ospfapi do not build OSPFAPI to access the OSPF LSA Database, + (this is the default if --enable-opaque-lsa is not set)]) +AC_ARG_ENABLE(ospfclient, +[ --disable-ospfclient do not build OSPFAPI client for OSPFAPI, + (this is the default if --disable-ospfapi is set)]) 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]) dnl AC_ARG_ENABLE(rtadv, dnl [ --enable-rtadv enable IPV6 router advertisment option]) @@ -127,6 +139,27 @@ dnl if test "${enable_rtadv}" = "yes"; then dnl AC_DEFINE(HAVE_RTADV) dnl 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 x"${enable_vty_group}" != x"no"; then + AC_DEFINE_UNQUOTED(VTY_GROUP, "${enable_vty_group}", VTY Sockets Group) +fi + changequote(, )dnl MULTIPATH_NUM=1 @@ -209,7 +242,11 @@ case "${enable_vtysh}" in if test $ac_cv_header_readline_history_h = no;then AC_MSG_ERROR([readline is too old to have readline/history.h, please update to the latest readline library.]) fi - ;; + AC_CHECK_LIB(readline, rl_completion_matches) + if test $ac_cv_lib_readline_rl_completion_matches = no; then + AC_DEFINE(rl_completion_matches,completion_matches,Old readline) + fi + ;; "no" ) VTYSH="";; * ) ;; esac @@ -218,6 +255,25 @@ dnl ---------- dnl PAM module dnl ---------- if test "$with_libpam" = "yes"; then + AC_CHECK_HEADER(security/pam_misc.h) + if test "$ac_cv_header_security_pam_misc_h" = yes; then + AC_DEFINE(HAVE_PAM_MISC_H,,Have pam_misc.h) + AC_DEFINE(PAM_CONV_FUNC,misc_conv,Have misc_conv) + pam_conv_func="misc_conv" + fi + AC_CHECK_HEADER(security/openpam.h) + if test "$ac_cv_header_security_openpam_h" = yes; then + AC_DEFINE(HAVE_OPENPAM_H,,Have openpam.h) + AC_DEFINE(PAM_CONV_FUNC,openpam_ttyconv,Have openpam_ttyconv) + pam_conv_func="openpam_ttyconv" + fi + if test -z "$ac_cv_header_security_pam_misc_h$ac_cv_header_security_openpam_h" ; then + AC_MSG_WARN([*** pam support will not be built ***]) + with_libpam="no" + fi +fi + +if test "$with_libpam" = "yes"; then dnl took this test from proftpd's configure.in and suited to our needs dnl ------------------------------------------------------------------------- dnl @@ -226,7 +282,7 @@ dnl of the PAM library. Prior to 0.72 release, the Linux PAM shared library dnl omitted requiring libdl linking information. PAM-0.72 or better ships dnl with RedHat 6.2 and Debian 2.2 or better. AC_CHECK_LIB(pam, pam_start, - [AC_CHECK_LIB(pam, misc_conv, + [AC_CHECK_LIB(pam, $pam_conv_func, [AC_DEFINE(USE_PAM,,Use PAM for authentication) LIBPAM="-lpam"], [AC_DEFINE(USE_PAM,,Use PAM for authentication) @@ -235,7 +291,7 @@ AC_CHECK_LIB(pam, pam_start, ], [AC_CHECK_LIB(pam, pam_end, - [AC_CHECK_LIB(pam, misc_conv, + [AC_CHECK_LIB(pam, $pam_conv_func, [AC_DEFINE(USE_PAM) LIBPAM="-lpam -ldl"], [AC_DEFINE(USE_PAM) @@ -534,6 +590,18 @@ else OSPFD="ospfd" fi +OSPFCLIENT="" +if test "${enable_opaque_lsa}" = "yes"; then + if test "${enable_ospfapi}" != "no";then + AC_DEFINE(SUPPORT_OSPF_API,,OSPFAPI) + + if test "${enable_ospfclient}" != "no";then + OSPFCLIENT="ospfclient" + fi + fi + +fi + case "${enable_ripngd}" in "yes") RIPNGD="ripngd";; "no" ) RIPNGD="";; @@ -559,6 +627,8 @@ AC_SUBST(OSPF6D) AC_SUBST(VTYSH) AC_SUBST(INCLUDES) AC_SUBST(CURSES) +AC_SUBST(OSPFCLIENT) +AC_SUBST(OSPFAPI) AC_CHECK_LIB(c, inet_ntop, [AC_DEFINE(HAVE_INET_NTOP,,inet_ntop)]) AC_CHECK_LIB(c, inet_pton, [AC_DEFINE(HAVE_INET_PTON,,inet_pton)]) AC_CHECK_LIB(crypt, crypt) @@ -587,33 +657,66 @@ dnl check SNMP library dnl ------------------ if test "${enable_snmp}" = "yes";then dnl AC_CHECK_LIB(snmp, asn_parse_int, HAVE_SNMP=yes) - old_libs="${LIBS}" - LIBS="-L/usr/local/lib" - unset ac_cv_lib_snmp_asn_parse_int - AC_CHECK_LIB(snmp, asn_parse_int, HAVE_SNMP=yes, ) if test "${HAVE_SNMP}" = ""; then + old_libs="${LIBS}" + LIBS="-L/usr/lib" unset ac_cv_lib_snmp_asn_parse_int - AC_CHECK_LIB(crypto, main, [NEED_CRYPTO=yes ], ) - if test "${NEED_CRYPTO}" = ""; then - AC_CHECK_LIB(snmp, asn_parse_int, [HAVE_SNMP=yes; NEED_CRYPTO=yes ],) - else - AC_CHECK_LIB(snmp, asn_parse_int, [HAVE_SNMP=yes; NEED_CRYPTO=yes;LIBS="$LIBS -lcrypto" ],,"-lcrypto") - fi + AC_CHECK_LIB(crypto, main, NEED_CRYPTO=yes, ) + if test "${NEED_CRYPTO}" = ""; then + AC_CHECK_LIB(netsnmp, asn_parse_int, [HAVE_NETSNMP=yes; HAVE_SNMP=yes ]) + else + AC_CHECK_LIB(netsnmp, asn_parse_int, [HAVE_NETSNMP=yes; HAVE_SNMP=yes; NEED_CRYPTO=yes;LIBS="$LIBS -lcrypto" ],,"-lcrypto") + fi + LIBS="${old_libs}" + fi + if test "${HAVE_SNMP}" = ""; then + old_libs="${LIBS}" + LIBS="-L/usr/lib" + unset ac_cv_lib_snmp_asn_parse_int + AC_CHECK_LIB(snmp, asn_parse_int, HAVE_SNMP=yes, ) + if test "${HAVE_SNMP}" = ""; then + unset ac_cv_lib_snmp_asn_parse_int + AC_CHECK_LIB(crypto, main, NEED_CRYPTO=yes, ) + if test "${NEED_CRYPTO}" = "yes"; then + AC_CHECK_LIB(snmp, asn_parse_int, [HAVE_SNMP=yes; NEED_CRYPTO=yes; LIBS="$LIBS -lcrypto" ],,"-lcrypto") + fi + fi + LIBS="${old_libs}" fi - LIBS="${old_libs}" if test "${HAVE_SNMP}" = ""; then - old_libs="${LIBS}" - LIBS="-L/usr/local/lib" - AC_CHECK_LIB(snmp, asn_parse_int, HAVE_SNMP=yes) - LIBS="${old_libs}" + old_libs="${LIBS}" + LIBS="-L/usr/local/lib" + unset ac_cv_lib_snmp_asn_parse_int + AC_CHECK_LIB(snmp, asn_parse_int, HAVE_SNMP=yes) + if test "${HAVE_SNMP}" = ""; then + unset ac_cv_lib_snmp_asn_parse_int + AC_CHECK_LIB(crypto, main, NEED_CRYPTO=yes, ) + if test "${NEED_CRYPTO}" = "yes"; then + AC_CHECK_LIB(snmp, asn_parse_int, [HAVE_SNMP=yes; NEED_CRYPTO=yes; LIBS="$LIBS -lcrypto" ],,"-lcrypto") + fi + fi + LIBS="${old_libs}" fi + if test "${HAVE_SNMP}" = "yes"; then - for ac_snmp in /usr/include/ucd-snmp/asn1.h /usr/local/include/ucd-snmp/asn1.h /dev/null + for ac_snmp in /usr/include/net-snmp/library/asn1.h /usr/include/ucd-snmp/asn1.h /usr/local/include/ucd-snmp/asn1.h /dev/null do test -f "${ac_snmp}" && break done + case ${ac_snmp} in + /usr/include/net-snmp/*) + AC_DEFINE(HAVE_SNMP,,SNMP) + AC_DEFINE(HAVE_NETSNMP,,SNMP) + AC_DEFINE(UCD_COMPATIBLE,,SNMP) + CFLAGS="${CFLAGS} -I/usr/include/net-snmp -I/usr/include/net-snmp/library" + if test "${HAVE_NETSNMP}" = "yes"; then + LIBS="${LIBS} -lnetsnmp" + else + LIBS="${LIBS} -lsnmp" + fi + ;; /usr/include/ucd-snmp/*) AC_DEFINE(HAVE_SNMP,,SNMP) CFLAGS="${CFLAGS} -I/usr/include/ucd-snmp" @@ -749,6 +852,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 version dnl ------------- @@ -756,28 +881,55 @@ file="${srcdir}/lib/version.h" VERSION=`sed -ne 's/^#.*ZEBRA_VERSION.*\"\([^\"]*\)\"$/\1/p' $file` AC_SUBST(VERSION) +dnl ---------- +dnl configure date +dnl ---------- +CONFDATE=`date '+%Y%m%d'` +AC_SUBST(CONFDATE) + dnl ------------------------------ -dnl set paths for process id files +dnl set paths for state directory dnl ------------------------------ -AC_CACHE_CHECK(pid file directory,ac_piddir, -[for ZEBRA_PID_DIR in /var/run dnl - /var/adm dnl - /etc dnl - /dev/null; -do - test -d $ZEBRA_PID_DIR && break -done -ac_piddir=$ZEBRA_PID_DIR -if test $ZEBRA_PID_DIR = "/dev/null"; then - echo "PID DIRECTORY NOT FOUND!" -fi]) -AC_DEFINE_UNQUOTED(PATH_ZEBRA_PID, "$ac_piddir/zebra.pid",zebra PID) -AC_DEFINE_UNQUOTED(PATH_RIPD_PID, "$ac_piddir/ripd.pid",ripd PID) -AC_DEFINE_UNQUOTED(PATH_RIPNGD_PID, "$ac_piddir/ripngd.pid",ripngd PID) -AC_DEFINE_UNQUOTED(PATH_BGPD_PID, "$ac_piddir/bgpd.pid",bgpd PID) -AC_DEFINE_UNQUOTED(PATH_OSPFD_PID, "$ac_piddir/ospfd.pid",ospfd PID) -AC_DEFINE_UNQUOTED(PATH_OSPF6D_PID, "$ac_piddir/ospf6d.pid",ospf6d PID) +if test "${prefix}" = "NONE"; then + zebra_statedir_prefix=""; +else + zebra_statedir_prefix=${prefix} +fi +if test "${localstatedir}" = '${prefix}/var'; then + AC_CACHE_CHECK(state directory,ac_statedir, + [for ZEBRA_STATE_DIR in ${zebra_statedir_prefix}/var/run dnl + ${zebra_statedir_prefix}/var/adm dnl + ${zebra_statedir_prefix}/etc dnl + /var/run dnl + /var/adm dnl + /etc dnl + /dev/null; + do + test -d $ZEBRA_STATE_DIR && break + done + zebra_statedir=$ZEBRA_STATE_DIR]) +else + zebra_statedir=${localstatedir} + AC_MSG_CHECKING(directory to use for state file) + AC_MSG_RESULT(${zebra_statedir}) +fi +if test $zebra_statedir = "/dev/null"; then + echo "STATE DIRECTORY NOT FOUND!" +fi +AC_DEFINE_UNQUOTED(PATH_ZEBRA_PID, "$zebra_statedir/zebra.pid",zebra PID) +AC_DEFINE_UNQUOTED(PATH_RIPD_PID, "$zebra_statedir/ripd.pid",ripd PID) +AC_DEFINE_UNQUOTED(PATH_RIPNGD_PID, "$zebra_statedir/ripngd.pid",ripngd PID) +AC_DEFINE_UNQUOTED(PATH_BGPD_PID, "$zebra_statedir/bgpd.pid",bgpd PID) +AC_DEFINE_UNQUOTED(PATH_OSPFD_PID, "$zebra_statedir/ospfd.pid",ospfd PID) +AC_DEFINE_UNQUOTED(PATH_OSPF6D_PID, "$zebra_statedir/ospf6d.pid",ospf6d PID) +AC_DEFINE_UNQUOTED(ZEBRA_SERV_PATH, "$zebra_statedir/zserv.api",zebra api socket) +AC_DEFINE_UNQUOTED(ZEBRA_VTYSH_PATH, "$zebra_statedir/zebra.vty",zebra vty socket) +AC_DEFINE_UNQUOTED(RIP_VTYSH_PATH, "$zebra_statedir/ripd.vty",rip vty socket) +AC_DEFINE_UNQUOTED(RIPNG_VTYSH_PATH, "$zebra_statedir/ripngd.vty",ripng vty socket) +AC_DEFINE_UNQUOTED(BGP_VTYSH_PATH, "$zebra_statedir/bgpd.vty",bgpd vty socket) +AC_DEFINE_UNQUOTED(OSPF_VTYSH_PATH, "$zebra_statedir/ospfd.vty",ospfd vty socket) +AC_DEFINE_UNQUOTED(OSPF6_VTYSH_PATH, "$zebra_statedir/ospf6d.vty",ospf6d vty socket) dnl --------------------------- dnl Check htonl works correctly @@ -798,7 +950,11 @@ ac_cv_htonl_works=yes, ac_cv_htonl_works=no)]) AC_MSG_RESULT($ac_cv_htonl_works) -AC_OUTPUT(Makefile lib/Makefile zebra/Makefile ripd/Makefile ripngd/Makefile bgpd/Makefile ospfd/Makefile ospf6d/Makefile vtysh/Makefile doc/Makefile) +AC_OUTPUT(Makefile lib/Makefile zebra/Makefile ripd/Makefile + ripngd/Makefile bgpd/Makefile ospfd/Makefile + ospf6d/Makefile vtysh/Makefile doc/Makefile + ospfclient/Makefile + redhat/zebra.spec) echo " zebra configuration @@ -808,5 +964,5 @@ host operationg system : ${host_os} source code location : ${srcdir} compiler : ${CC} compiler flags : ${CFLAGS} -directory for pid files : ${ac_piddir} -" +directory for state files : ${zebra_statedir} +"
\ No newline at end of file diff --git a/configure.in b/configure.in index 5c9cb547..fd264b7a 100755 --- a/configure.in +++ b/configure.in @@ -7,7 +7,7 @@ AC_PREREQ(2.13) AC_INIT(lib/zebra.h) -AM_INIT_AUTOMAKE(zebra, 0.93) +AM_INIT_AUTOMAKE(zebra, 0.94) AM_CONFIG_HEADER(config.h) dnl ----------------------------------- @@ -87,11 +87,23 @@ dnl Temporary option until OSPF NSSA implementation complete AC_ARG_ENABLE(nssa, [ --enable-nssa enable OSPF NSSA option]) AC_ARG_ENABLE(opaque-lsa, -[ --enable-opaque-lsa enable OSPF Opaque-LSA support (RFC2370)]) +[ --enable-opaque-lsa enable OSPF Opaque-LSA with OSPFAPI support (RFC2370)]) +AC_ARG_ENABLE(ospfapi, +[ --disable-ospfapi do not build OSPFAPI to access the OSPF LSA Database, + (this is the default if --enable-opaque-lsa is not set)]) +AC_ARG_ENABLE(ospfclient, +[ --disable-ospfclient do not build OSPFAPI client for OSPFAPI, + (this is the default if --disable-ospfapi is set)]) 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]) dnl AC_ARG_ENABLE(rtadv, dnl [ --enable-rtadv enable IPV6 router advertisment option]) @@ -102,31 +114,52 @@ if test "${enable_broken_aliases}" = "yes"; then echo "Sorry, you can't use netlink with broken aliases" exit 1 fi - AC_DEFINE(HAVE_BROKEN_ALIASES) + AC_DEFINE(HAVE_BROKEN_ALIASES,,Broken Alias) enable_netlink=no fi if test "${enable_tcp_zebra}" = "yes"; then - AC_DEFINE(HAVE_TCP_ZEBRA) + AC_DEFINE(HAVE_TCP_ZEBRA,,Use TCP for zebra communication) fi if test "${enable_nssa}" = "yes"; then - AC_DEFINE(HAVE_NSSA) + AC_DEFINE(HAVE_NSSA,,OSPF NSSA) fi if test "${enable_opaque_lsa}" = "yes"; then - AC_DEFINE(HAVE_OPAQUE_LSA) + AC_DEFINE(HAVE_OPAQUE_LSA,,OSPF Opaque LSA) fi if test "${enable_ospf_te}" = "yes"; then - AC_DEFINE(HAVE_OPAQUE_LSA) - AC_DEFINE(HAVE_OSPF_TE) + AC_DEFINE(HAVE_OPAQUE_LSA,,OSPF Opaque LSA) + AC_DEFINE(HAVE_OSPF_TE,,OSPF TE) fi dnl if test "${enable_rtadv}" = "yes"; then dnl AC_DEFINE(HAVE_RTADV) dnl 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 x"${enable_vty_group}" != x"no"; then + AC_DEFINE_UNQUOTED(VTY_GROUP, "${enable_vty_group}", VTY Sockets Group) +fi + changequote(, )dnl MULTIPATH_NUM=1 @@ -162,30 +195,30 @@ dnl Some systems (Solaris 2.x) require libnsl (Network Services Library) case "$host" in *-sunos5.6* | *-solaris2.6*) opsys=sol2-6 - AC_DEFINE(SUNOS_5) + AC_DEFINE(SUNOS_5,,SunOS 5) AC_CHECK_LIB(xnet, main) CURSES=-lcurses ;; *-sunos5* | *-solaris2*) - AC_DEFINE(SUNOS_5) + AC_DEFINE(SUNOS_5,,SunOS 5) AC_CHECK_LIB(socket, main) AC_CHECK_LIB(nsl, main) CURSES=-lcurses ;; *-linux-*) opsys=gnu-linux - AC_DEFINE(GNU_LINUX) + AC_DEFINE(GNU_LINUX,,GNU Linux) ;; *-nec-sysv4*) AC_CHECK_LIB(nsl, gethostbyname) AC_CHECK_LIB(socket, socket) ;; *-freebsd3.2) - AC_DEFINE(FREEBSD_32) + AC_DEFINE(FREEBSD_32,,FreeBSD 3.2) ;; *-openbsd*) opsys=openbsd - AC_DEFINE(OPEN_BSD) + AC_DEFINE(OPEN_BSD,,OpenBSD) ;; *-bsdi*) opsys=bsdi @@ -194,18 +227,12 @@ case "$host" in ;; esac -case "${host_cpu}-${host_os}" in - i?86-solaris*) - AC_DEFINE(SOLARIS_X86) - ;; -esac - dnl --------------------- dnl Integrated VTY option dnl --------------------- case "${enable_vtysh}" in "yes") VTYSH="vtysh"; - AC_DEFINE(VTYSH) + AC_DEFINE(VTYSH,,VTY shell) AC_CHECK_LIB(tinfo, tputs, , AC_CHECK_LIB(ncurses, tputs)) AC_CHECK_LIB(readline, main) if test $ac_cv_lib_readline_main = no; then @@ -215,7 +242,11 @@ case "${enable_vtysh}" in if test $ac_cv_header_readline_history_h = no;then AC_MSG_ERROR([readline is too old to have readline/history.h, please update to the latest readline library.]) fi - ;; + AC_CHECK_LIB(readline, rl_completion_matches) + if test $ac_cv_lib_readline_rl_completion_matches = no; then + AC_DEFINE(rl_completion_matches,completion_matches,Old readline) + fi + ;; "no" ) VTYSH="";; * ) ;; esac @@ -224,6 +255,25 @@ dnl ---------- dnl PAM module dnl ---------- if test "$with_libpam" = "yes"; then + AC_CHECK_HEADER(security/pam_misc.h) + if test "$ac_cv_header_security_pam_misc_h" = yes; then + AC_DEFINE(HAVE_PAM_MISC_H,,Have pam_misc.h) + AC_DEFINE(PAM_CONV_FUNC,misc_conv,Have misc_conv) + pam_conv_func="misc_conv" + fi + AC_CHECK_HEADER(security/openpam.h) + if test "$ac_cv_header_security_openpam_h" = yes; then + AC_DEFINE(HAVE_OPENPAM_H,,Have openpam.h) + AC_DEFINE(PAM_CONV_FUNC,openpam_ttyconv,Have openpam_ttyconv) + pam_conv_func="openpam_ttyconv" + fi + if test -z "$ac_cv_header_security_pam_misc_h$ac_cv_header_security_openpam_h" ; then + AC_MSG_WARN([*** pam support will not be built ***]) + with_libpam="no" + fi +fi + +if test "$with_libpam" = "yes"; then dnl took this test from proftpd's configure.in and suited to our needs dnl ------------------------------------------------------------------------- dnl @@ -232,16 +282,16 @@ dnl of the PAM library. Prior to 0.72 release, the Linux PAM shared library dnl omitted requiring libdl linking information. PAM-0.72 or better ships dnl with RedHat 6.2 and Debian 2.2 or better. AC_CHECK_LIB(pam, pam_start, - [AC_CHECK_LIB(pam, misc_conv, - [AC_DEFINE(USE_PAM) + [AC_CHECK_LIB(pam, $pam_conv_func, + [AC_DEFINE(USE_PAM,,Use PAM for authentication) LIBPAM="-lpam"], - [AC_DEFINE(USE_PAM) + [AC_DEFINE(USE_PAM,,Use PAM for authentication) LIBPAM="-lpam -lpam_misc"] ) ], [AC_CHECK_LIB(pam, pam_end, - [AC_CHECK_LIB(pam, misc_conv, + [AC_CHECK_LIB(pam, $pam_conv_func, [AC_DEFINE(USE_PAM) LIBPAM="-lpam -ldl"], [AC_DEFINE(USE_PAM) @@ -257,36 +307,7 @@ AC_SUBST(LIBPAM) dnl ------------------------------- dnl Endian-ness check dnl ------------------------------- -AC_DEFUN(ZEBRA_AC_C_BIGENDIAN, -[AC_CACHE_CHECK(whether byte ordering is bigendian, ac_cv_c_bigendian, -[ac_cv_c_bigendian=unknown -# See if sys/param.h defines the BYTE_ORDER macro. -AC_TRY_COMPILE([#include <sys/types.h> -#include <sys/param.h>], [ -#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN - bogus endian macros -#endif], [# It does; now see whether it defined to BIG_ENDIAN or not. -AC_TRY_COMPILE([#include <sys/types.h> -#include <sys/param.h>], [ -#if BYTE_ORDER != BIG_ENDIAN - not big endian -#endif], ac_cv_c_bigendian=yes, ac_cv_c_bigendian=no)]) -if test $ac_cv_c_bigendian = unknown; then -AC_TRY_RUN([main () { - /* Are we little or big endian? From Harbison&Steele. */ - union - { - long l; - char c[sizeof (long)]; - } u; - u.l = 1; - exit (u.c[sizeof (long) - 1] == 1); -}], ac_cv_c_bigendian=no, ac_cv_c_bigendian=yes, ac_cv_c_bigendian=no) -fi]) -if test $ac_cv_c_bigendian = yes; then - AC_DEFINE(WORDS_BIGENDIAN,1,Big endian words) -fi -]) +AC_WORDS_BIGENDIAN dnl ------------------------------- dnl check the size in byte of the C @@ -310,7 +331,7 @@ if test x"$opsys" = x"gnu-linux"; then if test "${enable_netlink}" = "yes";then AC_MSG_RESULT(netlink) RT_METHOD=rt_netlink.o - AC_DEFINE(HAVE_NETLINK) + AC_DEFINE(HAVE_NETLINK,,netlink) netlink=yes elif test "${enable_netlink}" = "no"; then AC_MSG_RESULT(ioctl) @@ -319,7 +340,7 @@ if test x"$opsys" = x"gnu-linux"; then else AC_MSG_RESULT(netlink) RT_METHOD=rt_netlink.o - AC_DEFINE(HAVE_NETLINK) + AC_DEFINE(HAVE_NETLINK,,netlink) netlink=yes fi else @@ -341,8 +362,7 @@ main () exit (1); exit (0); }], - [AC_DEFINE(HAVE_AF_ROUTE) - KERNEL_METHOD=kernel_socket.o + [KERNEL_METHOD=kernel_socket.o RT_METHOD=rt_socket.o AC_MSG_RESULT(socket)], [RT_METHOD=rt_ioctl.o @@ -396,7 +416,7 @@ else elif grep NET_RT_IFLIST /usr/include/sys/socket.h >/dev/null 2>&1; then AC_MSG_RESULT(sysctl) IF_METHOD=if_sysctl.o - AC_DEFINE(HAVE_NET_RT_IFLIST) + AC_DEFINE(HAVE_NET_RT_IFLIST,,NET_RT_IFLIST) else AC_MSG_RESULT(ioctl) IF_METHOD=if_ioctl.o @@ -408,12 +428,12 @@ dnl ----------------------- dnl check proc file system. dnl ----------------------- if test -r /proc/net/dev; then - AC_DEFINE(HAVE_PROC_NET_DEV) + AC_DEFINE(HAVE_PROC_NET_DEV,,/proc/net/dev) IF_PROC=if_proc.o fi if test -r /proc/net/if_inet6; then - AC_DEFINE(HAVE_PROC_NET_IF_INET6) + AC_DEFINE(HAVE_PROC_NET_IF_INET6,,/proc/net/if_inet6) IF_PROC=if_proc.o fi AC_SUBST(IF_PROC) @@ -455,8 +475,8 @@ dnl INRIA IPv6 dnl ---------- if grep IPV6_INRIA_VERSION /usr/include/netinet/in.h >/dev/null 2>&1; then zebra_cv_ipv6=yes - AC_DEFINE(HAVE_IPV6) - AC_DEFINE(INRIA_IPV6) + AC_DEFINE(HAVE_IPV6,,IPv6) + AC_DEFINE(INRIA_IPV6,,Inria IPv6) RIPNGD="ripngd" OSPF6D="ospf6d" LIB_IPV6="" @@ -467,8 +487,8 @@ dnl KAME IPv6 dnl --------- if grep WIDE /usr/include/netinet6/in6.h >/dev/null 2>&1; then zebra_cv_ipv6=yes - AC_DEFINE(HAVE_IPV6) - AC_DEFINE(KAME) + AC_DEFINE(HAVE_IPV6,,IPv6) + AC_DEFINE(KAME,,KAME IPv6) RIPNGD="ripngd" OSPF6D="ospf6d" if test -d /usr/local/v6/lib -a -f /usr/local/v6/lib/libinet6.a; then @@ -481,12 +501,12 @@ dnl NRL check dnl --------- if grep NRL /usr/include/netinet6/in6.h >/dev/null 2>&1; then zebra_cv_ipv6=yes - AC_DEFINE(HAVE_IPV6) - AC_DEFINE(NRL) + AC_DEFINE(HAVE_IPV6,,IPv6) + AC_DEFINE(NRL,,NRL) RIPNGD="ripngd" OSPF6D="ospf6d" if test x"$opsys" = x"bsdi";then - AC_DEFINE(BSDI_NRL) + AC_DEFINE(BSDI_NRL,,BSDI) AC_MSG_RESULT(BSDI_NRL) else AC_MSG_RESULT(NRL) @@ -521,7 +541,7 @@ if test "$zebra_cv_linux_ipv6" = "yes";then #if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1 yes #endif], [glibc=yes; AC_MSG_RESULT(yes)], AC_MSG_RESULT(no)) - AC_DEFINE(LINUX_IPV6) + AC_DEFINE(LINUX_IPV6,,Linux IPv6) RIPNGD="ripngd" OSPF6D="ospf6d" if test "$glibc" != "yes"; then @@ -570,6 +590,18 @@ else OSPFD="ospfd" fi +OSPFCLIENT="" +if test "${enable_opaque_lsa}" = "yes"; then + if test "${enable_ospfapi}" != "no";then + AC_DEFINE(SUPPORT_OSPF_API,,OSPFAPI) + + if test "${enable_ospfclient}" != "no";then + OSPFCLIENT="ospfclient" + fi + fi + +fi + case "${enable_ripngd}" in "yes") RIPNGD="ripngd";; "no" ) RIPNGD="";; @@ -583,7 +615,7 @@ case "${enable_ospf6d}" in esac if test "${enable_bgp_announce}" = "no";then - AC_DEFINE(DISABLE_BGP_ANNOUNCE) + AC_DEFINE(DISABLE_BGP_ANNOUNCE,,Disable BGP installation to zebra) fi AC_SUBST(ZEBRA) @@ -595,8 +627,10 @@ AC_SUBST(OSPF6D) AC_SUBST(VTYSH) AC_SUBST(INCLUDES) AC_SUBST(CURSES) -AC_CHECK_LIB(c, inet_ntop, [AC_DEFINE(HAVE_INET_NTOP)]) -AC_CHECK_LIB(c, inet_pton, [AC_DEFINE(HAVE_INET_PTON)]) +AC_SUBST(OSPFCLIENT) +AC_SUBST(OSPFAPI) +AC_CHECK_LIB(c, inet_ntop, [AC_DEFINE(HAVE_INET_NTOP,,inet_ntop)]) +AC_CHECK_LIB(c, inet_pton, [AC_DEFINE(HAVE_INET_PTON,,inet_pton)]) AC_CHECK_LIB(crypt, crypt) AC_CHECK_LIB(resolv, res_init) AC_CHECK_LIB(m, main) @@ -613,61 +647,83 @@ dnl check system has GNU regexp dnl --------------------------- dnl AC_MSG_CHECKING(whether system has GNU regex) AC_CHECK_LIB(c, regexec, -[AC_DEFINE(HAVE_GNU_REGEX) +[AC_DEFINE(HAVE_GNU_REGEX,,GNU regexp library) LIB_REGEX=""], [LIB_REGEX="regex.o"]) AC_SUBST(LIB_REGEX) -dnl AC_MSG_CHECKING(whether system has GNU regex) -dnl if grep RE_NO_GNU_OPS /usr/include/regex.h >/dev/null 2>&1; then -dnl AC_MSG_RESULT(yes) -dnl AC_DEFINE(HAVE_GNU_REGEX) -dnl LIB_REGEX="" -dnl else -dnl AC_MSG_RESULT(no) -dnl LIB_REGEX="regex.o" -dnl fi -dnl AC_SUBST(LIB_REGEX) - dnl ------------------ dnl check SNMP library dnl ------------------ if test "${enable_snmp}" = "yes";then dnl AC_CHECK_LIB(snmp, asn_parse_int, HAVE_SNMP=yes) - old_libs="${LIBS}" - LIBS="-L/usr/local/lib" - unset ac_cv_lib_snmp_asn_parse_int - AC_CHECK_LIB(snmp, asn_parse_int, HAVE_SNMP=yes, ) if test "${HAVE_SNMP}" = ""; then + old_libs="${LIBS}" + LIBS="-L/usr/lib" + unset ac_cv_lib_snmp_asn_parse_int + AC_CHECK_LIB(crypto, main, NEED_CRYPTO=yes, ) + if test "${NEED_CRYPTO}" = ""; then + AC_CHECK_LIB(netsnmp, asn_parse_int, [HAVE_NETSNMP=yes; HAVE_SNMP=yes ]) + else + AC_CHECK_LIB(netsnmp, asn_parse_int, [HAVE_NETSNMP=yes; HAVE_SNMP=yes; NEED_CRYPTO=yes;LIBS="$LIBS -lcrypto" ],,"-lcrypto") + fi + LIBS="${old_libs}" + fi + if test "${HAVE_SNMP}" = ""; then + old_libs="${LIBS}" + LIBS="-L/usr/lib" unset ac_cv_lib_snmp_asn_parse_int - AC_CHECK_LIB(crypto, main, [NEED_CRYPTO=yes ], ) - if test "${NEED_CRYPTO}" = ""; then - AC_CHECK_LIB(snmp, asn_parse_int, [HAVE_SNMP=yes; NEED_CRYPTO=yes ],) - else - AC_CHECK_LIB(snmp, asn_parse_int, [HAVE_SNMP=yes; NEED_CRYPTO=yes;LIBS="$LIBS -lcrypto" ],,"-lcrypto") - fi + AC_CHECK_LIB(snmp, asn_parse_int, HAVE_SNMP=yes, ) + if test "${HAVE_SNMP}" = ""; then + unset ac_cv_lib_snmp_asn_parse_int + AC_CHECK_LIB(crypto, main, NEED_CRYPTO=yes, ) + if test "${NEED_CRYPTO}" = "yes"; then + AC_CHECK_LIB(snmp, asn_parse_int, [HAVE_SNMP=yes; NEED_CRYPTO=yes; LIBS="$LIBS -lcrypto" ],,"-lcrypto") + fi + fi + LIBS="${old_libs}" fi - LIBS="${old_libs}" if test "${HAVE_SNMP}" = ""; then - old_libs="${LIBS}" - LIBS="-L/usr/local/lib" - AC_CHECK_LIB(snmp, asn_parse_int, HAVE_SNMP=yes) - LIBS="${old_libs}" + old_libs="${LIBS}" + LIBS="-L/usr/local/lib" + unset ac_cv_lib_snmp_asn_parse_int + AC_CHECK_LIB(snmp, asn_parse_int, HAVE_SNMP=yes) + if test "${HAVE_SNMP}" = ""; then + unset ac_cv_lib_snmp_asn_parse_int + AC_CHECK_LIB(crypto, main, NEED_CRYPTO=yes, ) + if test "${NEED_CRYPTO}" = "yes"; then + AC_CHECK_LIB(snmp, asn_parse_int, [HAVE_SNMP=yes; NEED_CRYPTO=yes; LIBS="$LIBS -lcrypto" ],,"-lcrypto") + fi + fi + LIBS="${old_libs}" fi + if test "${HAVE_SNMP}" = "yes"; then - for ac_snmp in /usr/include/ucd-snmp/asn1.h /usr/local/include/ucd-snmp/asn1.h /dev/null + for ac_snmp in /usr/include/net-snmp/library/asn1.h /usr/include/ucd-snmp/asn1.h /usr/local/include/ucd-snmp/asn1.h /dev/null do test -f "${ac_snmp}" && break done + case ${ac_snmp} in + /usr/include/net-snmp/*) + AC_DEFINE(HAVE_SNMP,,SNMP) + AC_DEFINE(HAVE_NETSNMP,,SNMP) + AC_DEFINE(UCD_COMPATIBLE,,SNMP) + CFLAGS="${CFLAGS} -I/usr/include/net-snmp -I/usr/include/net-snmp/library" + if test "${HAVE_NETSNMP}" = "yes"; then + LIBS="${LIBS} -lnetsnmp" + else + LIBS="${LIBS} -lsnmp" + fi + ;; /usr/include/ucd-snmp/*) - AC_DEFINE(HAVE_SNMP) + AC_DEFINE(HAVE_SNMP,,SNMP) CFLAGS="${CFLAGS} -I/usr/include/ucd-snmp" LIBS="${LIBS} -lsnmp" ;; /usr/local/include/ucd-snmp/*) - AC_DEFINE(HAVE_SNMP) + AC_DEFINE(HAVE_SNMP,,SNMP) CFLAGS="${CFLAGS} -I/usr/local/include/ucd-snmp" LIBS="${LIBS} -L/usr/local/lib -lsnmp" ;; @@ -686,7 +742,7 @@ AC_TRY_COMPILE([#include <sys/types.h> #include <sys/socket.h> ],[static struct sockaddr ac_i;int ac_j = sizeof (ac_i.sa_len);], [AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_SA_LEN)], + AC_DEFINE(HAVE_SA_LEN,,sa_len)], AC_MSG_RESULT(no)) dnl ---------------------------- @@ -697,7 +753,7 @@ AC_TRY_COMPILE([#include <sys/types.h> #include <netinet/in.h> ],[static struct sockaddr_in ac_i;int ac_j = sizeof (ac_i.sin_len);], [AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_SIN_LEN)], + AC_DEFINE(HAVE_SIN_LEN,,sin_len)], AC_MSG_RESULT(no)) dnl ---------------------------- @@ -708,7 +764,7 @@ AC_TRY_COMPILE([#include <sys/types.h> #include <sys/un.h> ],[static struct sockaddr_un ac_i;int ac_j = sizeof (ac_i.sun_len);], [AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_SUN_LEN)], + AC_DEFINE(HAVE_SUN_LEN,,sun_len)], AC_MSG_RESULT(no)) dnl ----------------------------------- @@ -720,7 +776,7 @@ if test "$zebra_cv_ipv6" = yes; then #include <netinet/in.h> ],[static struct sockaddr_in6 ac_i;int ac_j = sizeof (ac_i.sin6_scope_id);], [AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_SIN6_SCOPE_ID)], + AC_DEFINE(HAVE_SIN6_SCOPE_ID,,scope id)], AC_MSG_RESULT(no)) fi @@ -733,7 +789,7 @@ AC_TRY_COMPILE([#include <sys/types.h> #include <netinet/in.h> ],[socklen_t ac_x;], [AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_SOCKLEN_T)], + AC_DEFINE(HAVE_SOCKLEN_T,,socklen_t)], AC_MSG_RESULT(no)) dnl ------------------------ @@ -743,7 +799,7 @@ AC_MSG_CHECKING(whether struct sockaddr_dl exist) AC_EGREP_HEADER(sockaddr_dl, net/if_dl.h, [AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_SOCKADDR_DL)], + AC_DEFINE(HAVE_SOCKADDR_DL,,sockaddr_dl)], AC_MSG_RESULT(no)) dnl -------------------------- @@ -753,7 +809,7 @@ AC_MSG_CHECKING(whether struct ifaliasreq exist) AC_EGREP_HEADER(ifaliasreq, net/if.h, [AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_IFALIASREQ)], + AC_DEFINE(HAVE_IFALIASREQ,,ifaliasreq)], AC_MSG_RESULT(no)) dnl ---------------------------- @@ -763,7 +819,7 @@ AC_MSG_CHECKING(whether struct if6_aliasreq exist) AC_EGREP_HEADER(in6_aliasreq, netinet6/in6_var.h, [AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_IN6_ALIASREQ)], + AC_DEFINE(HAVE_IN6_ALIASREQ,,in6_aliasreq)], AC_MSG_RESULT(no)) dnl --------------------------- @@ -773,7 +829,7 @@ AC_MSG_CHECKING(whether struct rt_addrinfo exist) AC_EGREP_HEADER(rt_addrinfo, net/route.h, [AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_RT_ADDRINFO)], + AC_DEFINE(HAVE_RT_ADDRINFO,,rt_addrinfo)], AC_MSG_RESULT(no)) dnl -------------------------- @@ -783,7 +839,7 @@ AC_MSG_CHECKING(whether struct in_pktinfo exist) AC_TRY_COMPILE([#include <netinet/in.h> ],[struct in_pktinfo ac_x;], [AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_INPKTINFO)], + AC_DEFINE(HAVE_INPKTINFO,,in_pktinfo)], AC_MSG_RESULT(no)) dnl -------------------------------------- @@ -793,9 +849,31 @@ AC_MSG_CHECKING(whether getrusage is available) AC_TRY_COMPILE([#include <sys/resource.h> ],[struct rusage ac_x; getrusage (RUSAGE_SELF, &ac_x);], [AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_RUSAGE)], + 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 version dnl ------------- @@ -803,28 +881,55 @@ file="${srcdir}/lib/version.h" VERSION=`sed -ne 's/^#.*ZEBRA_VERSION.*\"\([^\"]*\)\"$/\1/p' $file` AC_SUBST(VERSION) +dnl ---------- +dnl configure date +dnl ---------- +CONFDATE=`date '+%Y%m%d'` +AC_SUBST(CONFDATE) + dnl ------------------------------ -dnl set paths for process id files +dnl set paths for state directory dnl ------------------------------ -AC_CACHE_CHECK(pid file directory,ac_piddir, -[for ZEBRA_PID_DIR in /var/run dnl - /var/adm dnl - /etc dnl - /dev/null; -do - test -d $ZEBRA_PID_DIR && break -done -ac_piddir=$ZEBRA_PID_DIR -if test $ZEBRA_PID_DIR = "/dev/null"; then - echo "PID DIRECTORY NOT FOUND!" -fi]) -AC_DEFINE_UNQUOTED(PATH_ZEBRA_PID, "$ac_piddir/zebra.pid") -AC_DEFINE_UNQUOTED(PATH_RIPD_PID, "$ac_piddir/ripd.pid") -AC_DEFINE_UNQUOTED(PATH_RIPNGD_PID, "$ac_piddir/ripngd.pid") -AC_DEFINE_UNQUOTED(PATH_BGPD_PID, "$ac_piddir/bgpd.pid") -AC_DEFINE_UNQUOTED(PATH_OSPFD_PID, "$ac_piddir/ospfd.pid") -AC_DEFINE_UNQUOTED(PATH_OSPF6D_PID, "$ac_piddir/ospf6d.pid") +if test "${prefix}" = "NONE"; then + zebra_statedir_prefix=""; +else + zebra_statedir_prefix=${prefix} +fi +if test "${localstatedir}" = '${prefix}/var'; then + AC_CACHE_CHECK(state directory,ac_statedir, + [for ZEBRA_STATE_DIR in ${zebra_statedir_prefix}/var/run dnl + ${zebra_statedir_prefix}/var/adm dnl + ${zebra_statedir_prefix}/etc dnl + /var/run dnl + /var/adm dnl + /etc dnl + /dev/null; + do + test -d $ZEBRA_STATE_DIR && break + done + zebra_statedir=$ZEBRA_STATE_DIR]) +else + zebra_statedir=${localstatedir} + AC_MSG_CHECKING(directory to use for state file) + AC_MSG_RESULT(${zebra_statedir}) +fi +if test $zebra_statedir = "/dev/null"; then + echo "STATE DIRECTORY NOT FOUND!" +fi +AC_DEFINE_UNQUOTED(PATH_ZEBRA_PID, "$zebra_statedir/zebra.pid",zebra PID) +AC_DEFINE_UNQUOTED(PATH_RIPD_PID, "$zebra_statedir/ripd.pid",ripd PID) +AC_DEFINE_UNQUOTED(PATH_RIPNGD_PID, "$zebra_statedir/ripngd.pid",ripngd PID) +AC_DEFINE_UNQUOTED(PATH_BGPD_PID, "$zebra_statedir/bgpd.pid",bgpd PID) +AC_DEFINE_UNQUOTED(PATH_OSPFD_PID, "$zebra_statedir/ospfd.pid",ospfd PID) +AC_DEFINE_UNQUOTED(PATH_OSPF6D_PID, "$zebra_statedir/ospf6d.pid",ospf6d PID) +AC_DEFINE_UNQUOTED(ZEBRA_SERV_PATH, "$zebra_statedir/zserv.api",zebra api socket) +AC_DEFINE_UNQUOTED(ZEBRA_VTYSH_PATH, "$zebra_statedir/zebra.vty",zebra vty socket) +AC_DEFINE_UNQUOTED(RIP_VTYSH_PATH, "$zebra_statedir/ripd.vty",rip vty socket) +AC_DEFINE_UNQUOTED(RIPNG_VTYSH_PATH, "$zebra_statedir/ripngd.vty",ripng vty socket) +AC_DEFINE_UNQUOTED(BGP_VTYSH_PATH, "$zebra_statedir/bgpd.vty",bgpd vty socket) +AC_DEFINE_UNQUOTED(OSPF_VTYSH_PATH, "$zebra_statedir/ospfd.vty",ospfd vty socket) +AC_DEFINE_UNQUOTED(OSPF6_VTYSH_PATH, "$zebra_statedir/ospf6d.vty",ospf6d vty socket) dnl --------------------------- dnl Check htonl works correctly @@ -845,7 +950,11 @@ ac_cv_htonl_works=yes, ac_cv_htonl_works=no)]) AC_MSG_RESULT($ac_cv_htonl_works) -AC_OUTPUT(Makefile lib/Makefile zebra/Makefile ripd/Makefile ripngd/Makefile bgpd/Makefile ospfd/Makefile ospf6d/Makefile vtysh/Makefile doc/Makefile) +AC_OUTPUT(Makefile lib/Makefile zebra/Makefile ripd/Makefile + ripngd/Makefile bgpd/Makefile ospfd/Makefile + ospf6d/Makefile vtysh/Makefile doc/Makefile + ospfclient/Makefile + redhat/zebra.spec) echo " zebra configuration @@ -855,5 +964,5 @@ host operationg system : ${host_os} source code location : ${srcdir} compiler : ${CC} compiler flags : ${CFLAGS} -directory for pid files : ${ac_piddir} -" +directory for state files : ${zebra_statedir} +"
\ No newline at end of file diff --git a/lib/Makefile.am b/lib/Makefile.am index 81f1e41e..dbd105aa 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -3,16 +3,16 @@ INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -noinst_LIBRARIES = libzebra.a +lib_LIBRARIES = libzebra.a libzebra_a_SOURCES = \ version.c network.c pid_output.c getopt.c getopt1.c daemon.c \ 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 keychain.c privs.c -libzebra_a_DEPENDENCIES = @LIB_REGEX@ +libzebra_a_DEPENDENCIES = @LIB_REGEX@ @LIBCAP@ libzebra_a_LIBADD = @LIB_REGEX@ @@ -20,7 +20,7 @@ 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 keychain.h privs.h EXTRA_DIST = regex.c regex-gnu.h diff --git a/lib/memory.h b/lib/memory.h index 52e3bc11..06681bd1 100644 --- a/lib/memory.h +++ b/lib/memory.h @@ -184,6 +184,8 @@ enum MTYPE_VRF, MTYPE_VRF_NAME, + + MTYPE_PRIVS, MTYPE_MAX }; diff --git a/lib/privs.c b/lib/privs.c new file mode 100644 index 00000000..8932eacc --- /dev/null +++ b/lib/privs.c @@ -0,0 +1,377 @@ +/* + * Zebra privileges. + * + * Copyright (C) 2003 Paul Jakma. + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> +#include "log.h" +#include "privs.h" +#include "memory.h" + + +/* internal privileges state */ +static struct _zprivs_t +{ +#ifdef HAVE_LCAPS + cap_t caps; /* caps storage */ + cap_value_t *syscaps_p; /* system permitted caps */ + cap_value_t *syscaps_i; /* system inheritable caps */ + int sys_num_p; /* number of syscaps_p */ + int sys_num_i; /* number of syscaps_i */ +#endif /* HAVE_LCAPS */ + uid_t zuid, /* uid to run as */ + zsuid; /* saved uid */ + gid_t zgid; /* gid to run as */ + gid_t vtygrp; /* gid for vty sockets */ +} zprivs_state; + +/* externally exported but not directly accessed functions */ +#ifdef HAVE_LCAPS +int zprivs_change_caps (zebra_privs_ops_t); +zebra_privs_current_t zprivs_state_caps (void); +#endif /* HAVE_LCAPS */ +int zprivs_change_uid (zebra_privs_ops_t); +zebra_privs_current_t zprivs_state_uid (void); +int zprivs_change_null (zebra_privs_ops_t); +zebra_privs_current_t zprivs_state_null (void); +void zprivs_terminate (void); + +#ifdef HAVE_LCAPS +static int +cap_map [ZCAP_MAX] = +{ + [ZCAP_SETGID] = CAP_SETGID, + [ZCAP_SETUID] = CAP_SETUID, + [ZCAP_BIND] = CAP_NET_BIND_SERVICE, + [ZCAP_BROADCAST] = CAP_NET_BROADCAST, + [ZCAP_ADMIN] = CAP_NET_ADMIN, + [ZCAP_RAW] = CAP_NET_RAW, + [ZCAP_CHROOT] = CAP_SYS_CHROOT, + [ZCAP_NICE] = CAP_SYS_NICE, + [ZCAP_PTRACE] = CAP_SYS_PTRACE, + [ZCAP_DAC_OVERRIDE] = CAP_DAC_OVERRIDE, + [ZCAP_READ_SEARCH] = CAP_DAC_READ_SEARCH, + [ZCAP_SYS_ADMIN] = CAP_SYS_ADMIN, + [ZCAP_FOWNER] = ZCAP_FOWNER +}; + +/* convert zebras privileges to system capabilities */ +static cap_value_t * +zcaps2sys (zebra_capabilities_t *zcaps, int num) +{ + cap_value_t *syscaps; + int i; + + if (!num) + return NULL; + + syscaps = (cap_value_t *) XCALLOC ( MTYPE_PRIVS, + (sizeof(cap_value_t) * num) ); + if (!syscaps) + { + zlog_err ("zcap2sys: could not XCALLOC!"); + return NULL; + } + + for (i=0; i < num; i++) + { + syscaps[i] = cap_map[zcaps[i]]; + } + + return syscaps; +} + +/* set or clear the effective capabilities to/from permitted */ +int +zprivs_change_caps (zebra_privs_ops_t op) +{ + cap_flag_value_t cflag; + + if (op == ZPRIVS_RAISE) + cflag = CAP_SET; + else if (op == ZPRIVS_LOWER) + cflag = CAP_CLEAR; + else + return -1; + + if ( !cap_set_flag (zprivs_state.caps, CAP_EFFECTIVE, + zprivs_state.sys_num_p, zprivs_state.syscaps_p, cflag)) + return cap_set_proc (zprivs_state.caps); + return -1; +} + +zebra_privs_current_t +zprivs_state_caps (void) +{ + int i; + cap_flag_value_t val; + + for (i=0; i < zprivs_state.sys_num_p; i++) + { + if ( cap_get_flag (zprivs_state.caps, zprivs_state.syscaps_p[i], + CAP_EFFECTIVE, &val) ) + zlog_warn ("zprivs_state_caps: could not cap_get_flag, %s", + strerror (errno) ); + if (val == CAP_SET) + return ZPRIVS_RAISED; + } + return ZPRIVS_LOWERED; +} + +#endif /* HAVE_LCAPS */ + +int +zprivs_change_uid (zebra_privs_ops_t op) +{ + + if (op == ZPRIVS_RAISE) + return seteuid (zprivs_state.zsuid); + else if (op == ZPRIVS_LOWER) + return seteuid (zprivs_state.zuid); + else + return -1; +} + +zebra_privs_current_t +zprivs_state_uid (void) +{ + return ( (zprivs_state.zuid == geteuid()) ? ZPRIVS_LOWERED : ZPRIVS_RAISED); +} + +int +zprivs_change_null (zebra_privs_ops_t op) +{ + return 0; +} + +zebra_privs_current_t +zprivs_state_null (void) +{ + return ZPRIVS_RAISED; +} + + +void +zprivs_init(struct zebra_privs_t *zprivs) +{ + struct passwd *pwentry = NULL; + struct group *grentry = NULL; + + /* NULL privs */ + if (! (zprivs->user || zprivs->group + || zprivs->cap_num_p || zprivs->cap_num_i) ) + { + zprivs->change = zprivs_change_null; + zprivs->current_state = zprivs_state_null; + return; + } + + if (zprivs->user) + { + if ( (pwentry = getpwnam (zprivs->user)) ) + { + zprivs_state.zuid = pwentry->pw_uid; + } + else + { + zlog_err ("privs_init: could not lookup supplied user"); + exit (1); + } + } + + +#ifdef VTY_GROUP + /* Add the VTY_GROUP to the supplementary groups so it can be chowned to */ + if ( (grentry = getgrnam (zprivs->vty_group)) ) + { + if ( setgroups (1, &grentry->gr_gid) ) + { + zlog_err ("privs_init: could not setgroups, %s", + strerror (errno) ); + exit (1); + } + zprivs_state.vtygrp = grentry->gr_gid; + } + else + { + zlog_err ("privs_init: could not lookup supplied user"); + exit (1); + } +#endif /* VTY_GROUP */ + + if (zprivs->group) + { + if ( (grentry = getgrnam (zprivs->user)) ) + { + zprivs_state.zgid = grentry->gr_gid; + } + else + { + zlog_err ("privs_init: could not lookup supplied user"); + exit (1); + } + + /* change group now, forever. uid we do later */ + if ( setregid (zprivs_state.zgid, zprivs_state.zgid) ) + { + zlog_err ("privs_init: could not setregid"); + exit (1); + } + } + +#ifdef HAVE_LCAPS + zprivs_state.syscaps_p = zcaps2sys (zprivs->caps_p, zprivs->cap_num_p); + zprivs_state.sys_num_p = zprivs->cap_num_p; + zprivs_state.syscaps_i = zcaps2sys (zprivs->caps_i, zprivs->cap_num_i); + zprivs_state.sys_num_i = zprivs->cap_num_i; + + /* Tell kernel we want caps maintained across uid changes */ + if ( prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1 ) + { + zlog_err("privs_init: could not set PR_SET_KEEPCAPS, %s", + strerror (errno) ); + exit(1); + } + + if ( !zprivs_state.syscaps_p ) + { + zlog_warn ("privs_init: capabilities enabled, but no capabilities supplied"); + } + + if ( !(zprivs_state.caps = cap_init()) ) + { + zlog_err ("privs_init: failed to cap_init, %s", strerror (errno) ); + exit (1); + } + + /* we have caps, we have no need to ever change back the original user */ + if (zprivs_state.zuid) + { + if ( setreuid (zprivs_state.zuid, zprivs_state.zuid) ) + { + zlog_err ("privs_init (cap): could not setreuid, %s", strerror (errno) ); + exit (1); + } + } + + if ( cap_clear (zprivs_state.caps) ) + { + zlog_err ("privs_init: failed to cap_clear, %s", strerror (errno)); + exit (1); + } + + /* set permitted caps */ + cap_set_flag(zprivs_state.caps, CAP_PERMITTED, + zprivs_state.sys_num_p, zprivs_state.syscaps_p, CAP_SET); + cap_set_flag(zprivs_state.caps, CAP_EFFECTIVE, + zprivs_state.sys_num_p, zprivs_state.syscaps_p, CAP_SET); + + /* set inheritable caps, if any */ + if (zprivs_state.sys_num_i) + { + cap_set_flag(zprivs_state.caps, CAP_INHERITABLE, + zprivs_state.sys_num_i, zprivs_state.syscaps_i, CAP_SET); + } + + /* apply caps. CAP_EFFECTIVE is cleared. we'll raise the caps as + * and when, and only when, they are needed. + */ + if ( cap_set_proc (zprivs_state.caps) ) + { + zlog_err ("privs_init: initial cap_set_proc failed"); + exit (1); + } + + /* set methods for the caller to use */ + zprivs->change = zprivs_change_caps; + zprivs->current_state = zprivs_state_caps; + +#elif !defined(HAVE_LCAPS) + /* we dont have caps. we'll need to maintain rid and saved uid + * and change euid back to saved uid (who we presume has all neccessary + * privileges) whenever we are asked to raise our privileges. + */ + zprivs_state.zsuid = geteuid(); + if ( zprivs_state.zuid ) + { + if ( setreuid (-1, zprivs_state.zuid) ) + { + zlog_err ("privs_init (uid): could not setreuid, %s", strerror (errno)); + exit (1); + } + } + + zprivs->change = zprivs_change_uid; + zprivs->current_state = zprivs_state_uid; +#endif /* HAVE_LCAPS */ +} + +void +zprivs_terminate (void) +{ + +#ifdef HAVE_LCAPS + + if (zprivs_state.caps) + cap_clear (zprivs_state.caps); + + if ( cap_set_proc (zprivs_state.caps) ) + { + zlog_err ("privs_terminate: cap_set_proc failed, %s", + strerror (errno) ); + exit (1); + } + + if (zprivs_state.sys_num_p) + XFREE (MTYPE_PRIVS, zprivs_state.syscaps_p); + + if (zprivs_state.sys_num_i) + XFREE (MTYPE_PRIVS, zprivs_state.syscaps_i); + + cap_free (zprivs_state.caps); +#else + if (zprivs_state.zuid) + { + if ( setreuid (zprivs_state.zuid, zprivs_state.zuid) ) + { + zlog_err ("privs_terminate: could not setreuid, %s", + strerror (errno) ); + exit (1); + } + } +#endif /* HAVE_LCAPS */ + return; +} + +void +zprivs_get_ids(struct zprivs_ids_t *ids) +{ + + ids->uid_priv = getuid(); + (zprivs_state.zuid) ? (ids->uid_normal = zprivs_state.zuid) + : (ids->uid_normal = -1); + (zprivs_state.zgid) ? (ids->gid_normal = zprivs_state.zgid) + : (ids->gid_normal = -1); + (zprivs_state.vtygrp) ? (ids->gid_vty = zprivs_state.vtygrp) + : (ids->gid_vty = -1); + + return; +} diff --git a/lib/privs.h b/lib/privs.h new file mode 100644 index 00000000..65c9f358 --- /dev/null +++ b/lib/privs.h @@ -0,0 +1,91 @@ +/* + * Zebra privileges header. + * + * Copyright (C) 2003 Paul Jakma. + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_PRIVS_H +#define _ZEBRA_PRIVS_H + +/* list of zebra capabilities */ +typedef enum +{ + ZCAP_SETGID, + ZCAP_SETUID, + ZCAP_BIND, + ZCAP_BROADCAST, + ZCAP_ADMIN, + ZCAP_SYS_ADMIN, + ZCAP_RAW, + ZCAP_CHROOT, + ZCAP_NICE, + ZCAP_PTRACE, + ZCAP_DAC_OVERRIDE, + ZCAP_READ_SEARCH, + ZCAP_FOWNER, + ZCAP_MAX +} zebra_capabilities_t; + +typedef enum +{ + ZPRIVS_LOWERED, + ZPRIVS_RAISED +} zebra_privs_current_t; + +typedef enum +{ + ZPRIVS_RAISE, + ZPRIVS_LOWER, +} zebra_privs_ops_t; + +struct zebra_privs_t +{ + zebra_capabilities_t *caps_p; /* caps required for operation */ + zebra_capabilities_t *caps_i; /* caps to allow inheritance of */ + int cap_num_p; /* number of caps in arrays */ + int cap_num_i; + char *user; /* user and group to run as */ + char *group; + char *vty_group; /* group to chown vty socket to */ + /* methods */ + int + (*change) (zebra_privs_ops_t); /* change privileges, 0 on success */ + zebra_privs_current_t + (*current_state) (void); /* current privilege state */ +}; + +struct zprivs_ids_t +{ + /* -1 is undefined */ + uid_t uid_priv; /* privileged uid */ + uid_t uid_normal; /* normal uid */ + gid_t gid_priv; /* privileged uid */ + gid_t gid_normal; /* normal uid */ + gid_t gid_vty; /* vty gid */ +}; + + /* initialise zebra privileges */ +void zprivs_init (struct zebra_privs_t *zprivs); + /* drop all and terminate privileges */ +void zprivs_terminate (void); + /* query for runtime uid's and gid's, eg vty needs this */ +void zprivs_get_ids(struct zprivs_ids_t *); + +#endif /* _ZEBRA_PRIVS_H */ @@ -33,6 +33,7 @@ #include "log.h" #include "prefix.h" #include "filter.h" +#include "privs.h" /* Vty events */ enum event @@ -1776,14 +1777,37 @@ vty_serv_sock_addrinfo (const char *hostname, unsigned short port) /* Make vty server socket. */ void -vty_serv_sock_family (unsigned short port, int family) +vty_serv_sock_family (const char* addr, unsigned short port, int family) { int ret; union sockunion su; int accept_sock; + void* naddr=NULL; memset (&su, 0, sizeof (union sockunion)); su.sa.sa_family = family; + if(addr) + switch(family) + { + case AF_INET: + naddr=&su.sin.sin_addr; +#ifdef HAVE_IPV6 + case AF_INET6: + naddr=&su.sin6.sin6_addr; +#endif + } + + if(naddr) + switch(inet_pton(family,addr,naddr)) + { + case -1: + zlog_err("bad address %s",addr); + naddr=NULL; + break; + case 0: + zlog_err("error translating address %s: %s",addr,strerror(errno)); + naddr=NULL; + } /* Make new socket. */ accept_sock = sockunion_stream_socket (&su); @@ -1795,9 +1819,10 @@ vty_serv_sock_family (unsigned short port, int family) sockopt_reuseport (accept_sock); /* Bind socket to universal address and given port. */ - ret = sockunion_bind (accept_sock, &su, port, NULL); + ret = sockunion_bind (accept_sock, &su, port, naddr); if (ret < 0) { + zlog_warn("can't bind socket"); close (accept_sock); /* Avoid sd leak. */ return; } @@ -1827,12 +1852,13 @@ 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); /* Set umask */ - old_mask = umask (0077); + old_mask = umask (0007); /* Make UNIX domain socket. */ sock = socket (AF_UNIX, SOCK_STREAM, 0); @@ -1870,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); } @@ -1966,7 +2004,7 @@ vtysh_read (struct thread *thread) /* Determine address family to bind. */ void -vty_serv_sock (const char *hostname, unsigned short port, char *path) +vty_serv_sock (const char *addr, unsigned short port, char *path) { /* If port is set to 0, do not listen on TCP/IP at all! */ if (port) @@ -1974,19 +2012,19 @@ vty_serv_sock (const char *hostname, unsigned short port, char *path) #ifdef HAVE_IPV6 #ifdef NRL - vty_serv_sock_family (port, AF_INET); - vty_serv_sock_family (port, AF_INET6); + vty_serv_sock_family (addr, port, AF_INET); + vty_serv_sock_family (addr, port, AF_INET6); #else /* ! NRL */ - vty_serv_sock_addrinfo (hostname, port); + vty_serv_sock_addrinfo (addr, port); #endif /* NRL*/ #else /* ! HAVE_IPV6 */ - vty_serv_sock_family (port, AF_INET); + vty_serv_sock_family (addr,port, AF_INET); #endif /* HAVE_IPV6 */ } #ifdef VTYSH vty_serv_un (path); -#endif /* VTYSH */ +#endif /* VTYSH */v } /* Close vty interface. */ diff --git a/lib/zebra.h b/lib/zebra.h index a34f5d4a..c9aaf70d 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -45,6 +45,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 */ @@ -73,6 +75,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 e1b78cbc..b13942be 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 = ../lib/libzebra.a +ospf6d_LDADD = ../lib/libzebra.a @LIBCAP@ sysconf_DATA = ospf6d.conf.sample diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c index 5ab517f3..7ed0030e 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\ @@ -206,7 +229,7 @@ main (int argc, char *argv[], char *envp[]) char *p; int opt; char *vty_addr = NULL; - int vty_port = 0; + int vty_port = OSPF6_VTY_PORT; char *config_file = NULL; char *progname; struct thread thread; @@ -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; @@ -253,7 +276,18 @@ main (int argc, char *argv[], char *envp[]) pid_file = optarg; break; case 'P': + /* Deal with atoi() returning 0 on failure, and ospf6d not + listening on ospf6d port... */ + if (strcmp(optarg, "0") == 0) + { + vty_port = 0; + break; + } 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); @@ -280,6 +314,7 @@ main (int argc, char *argv[], char *envp[]) zlog_default = openzlog (progname, flag, ZLOG_OSPF6, LOG_CONS|LOG_NDELAY|LOG_PERROR|LOG_PID, LOG_DAEMON); + zprivs_init (&ospf6d_privs); signal_init (); cmd_init (1); vty_init (); @@ -305,8 +340,7 @@ main (int argc, char *argv[], char *envp[]) thread_add_read (master, ospf6_receive, NULL, ospf6_sock); /* Make ospf vty socket. */ - vty_serv_sock (vty_addr, - vty_port ? vty_port : OSPF6_VTY_PORT, OSPF6_VTYSH_PATH); + vty_serv_sock (vty_addr, vty_port, OSPF6_VTYSH_PATH); /* Print start message */ zlog_notice ("OSPF6d (Zebra-%s ospf6d-%s) starts", diff --git a/ospf6d/ospf6_network.c b/ospf6d/ospf6_network.c index 041d829b..9b98f808 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 new file mode 100644 index 00000000..fb041af9 --- /dev/null +++ b/ospfclient/Makefile.am @@ -0,0 +1,21 @@ +## Automake.am for OSPF API client + +INCLUDES = -I../lib -I../ + +lib_LIBRARIES = libospfapiclient.a +sbin_PROGRAMS = ospfclient + +libospfapiclient_a_SOURCES = \ + ospf_apiclient.c + +ospfapiheaderdir = $(includedir)/ospfapi + +ospfapiheader_HEADERS = \ + ospf_apiclient.h + +ospfclient_SOURCES = \ + ospfclient.c $(libospfapiclient_a_SOURCES) + +ospfclient_LDADD = ../ospfd/libospf.a ../lib/libzebra.a @LIBCAP@ + + diff --git a/ospfclient/ospfclient.c b/ospfclient/ospfclient.c new file mode 100644 index 00000000..28010872 --- /dev/null +++ b/ospfclient/ospfclient.c @@ -0,0 +1,333 @@ +/* + * Simple program to demonstrate how OSPF API can be used. This + * application retrieves the LSDB from the OSPF daemon and then + * originates, updates and finally deletes an application-specific + * opaque LSA. You can use this application as a template when writing + * your own application. + */ + +/* The following includes are needed in all OSPF API client + applications. */ + +#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" +#include "ospfd/ospf_opaque.h" +#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). */ + +#include "ospfd/ospf_dump.h" /* for ospf_lsa_header_dump */ +#include "thread.h" +#include "log.h" + +/* Local portnumber for async channel. Note that OSPF API library will also + allocate a sync channel at ASYNCPORT+1. */ +#define ASYNCPORT 4000 + +/* Master thread */ +struct thread_master *master; + +/* Global variables */ +struct ospf_apiclient *oclient; +char **args; + +/* Our opaque LSAs have the following format. */ +struct my_opaque_lsa +{ + struct lsa_header hdr; /* include common LSA header */ + u_char data[4]; /* our own data format then follows here */ +}; + + +/* --------------------------------------------------------- + * Threads for asynchronous messages and LSA update/delete + * --------------------------------------------------------- + */ + +int +lsa_delete (struct thread *t) +{ + struct ospf_apiclient *oclient; + struct in_addr area_id; + int rc; + + oclient = THREAD_ARG (t); + + inet_aton (args[6], &area_id); + + printf ("Deleting LSA... "); + rc = ospf_apiclient_lsa_delete (oclient, + area_id, + atoi (args[2]), /* lsa type */ + atoi (args[3]), /* opaque type */ + atoi (args[4])); /* opaque ID */ + printf ("done, return code is = %d\n", rc); + return rc; +} + +int +lsa_inject (struct thread *t) +{ + struct ospf_apiclient *cl; + struct in_addr ifaddr; + struct in_addr area_id; + u_char lsa_type; + u_char opaque_type; + u_int32_t opaque_id; + void *opaquedata; + int opaquelen; + + static u_int32_t counter = 1; /* Incremented each time invoked */ + int rc; + + cl = THREAD_ARG (t); + + inet_aton (args[5], &ifaddr); + inet_aton (args[6], &area_id); + lsa_type = atoi (args[2]); + opaque_type = atoi (args[3]); + opaque_id = atoi (args[4]); + opaquedata = &counter; + opaquelen = sizeof (u_int32_t); + + printf ("Originating/updating LSA with counter=%d... ", counter); + rc = ospf_apiclient_lsa_originate(cl, ifaddr, area_id, + lsa_type, + opaque_type, opaque_id, + opaquedata, opaquelen); + + printf ("done, return code is %d\n", rc); + + counter++; + + return 0; +}; + + +/* This thread handles asynchronous messages coming in from the OSPF + API server */ +int +lsa_read (struct thread *thread) +{ + struct ospf_apiclient *oclient; + int fd; + int ret; + + printf ("lsa_read called\n"); + + oclient = THREAD_ARG (thread); + fd = THREAD_FD (thread); + + /* Handle asynchronous message */ + ret = ospf_apiclient_handle_async (oclient); + if (ret < 0) { + printf ("Connection closed, exiting..."); + exit(0); + } + + /* Reschedule read thread */ + thread_add_read (master, lsa_read, oclient, fd); + + return 0; +} + +/* --------------------------------------------------------- + * Callback functions for asynchronous events + * --------------------------------------------------------- + */ + +void +lsa_update_callback (struct in_addr ifaddr, struct in_addr area_id, + u_char is_self_originated, + struct lsa_header *lsa) +{ + printf ("lsa_update_callback: "); + printf ("ifaddr: %s ", inet_ntoa (ifaddr)); + printf ("area: %s\n", inet_ntoa (area_id)); + printf ("is_self_origin: %u\n", is_self_originated); + + /* It is important to note that lsa_header does indeed include the + header and the LSA payload. To access the payload, first check + the LSA type and then typecast lsa into the corresponding type, + e.g.: + + if (lsa->type == OSPF_ROUTER_LSA) { + struct router_lsa *rl = (struct router_lsa) lsa; + ... + u_int16_t links = rl->links; + ... + } + */ + + ospf_lsa_header_dump (lsa); +} + +void +lsa_delete_callback (struct in_addr ifaddr, struct in_addr area_id, + u_char is_self_originated, + struct lsa_header *lsa) +{ + printf ("lsa_delete_callback: "); + printf ("ifaddr: %s ", inet_ntoa (ifaddr)); + printf ("area: %s\n", inet_ntoa (area_id)); + printf ("is_self_origin: %u\n", is_self_originated); + + ospf_lsa_header_dump (lsa); +} + +void +ready_callback (u_char lsa_type, u_char opaque_type, struct in_addr addr) +{ + printf ("ready_callback: lsa_type: %d opaque_type: %d addr=%s\n", + lsa_type, opaque_type, inet_ntoa (addr)); + + /* Schedule opaque LSA originate in 5 secs */ + thread_add_timer (master, lsa_inject, oclient, 5); + + /* Schedule opaque LSA update with new value */ + thread_add_timer (master, lsa_inject, oclient, 10); + + /* Schedule delete */ + thread_add_timer (master, lsa_delete, oclient, 30); +} + +void +new_if_callback (struct in_addr ifaddr, struct in_addr area_id) +{ + printf ("new_if_callback: ifaddr: %s ", inet_ntoa (ifaddr)); + printf ("area_id: %s\n", inet_ntoa (area_id)); +} + +void +del_if_callback (struct in_addr ifaddr) +{ + printf ("new_if_callback: ifaddr: %s\n ", inet_ntoa (ifaddr)); +} + +void +ism_change_callback (struct in_addr ifaddr, struct in_addr area_id, + u_char state) +{ + printf ("ism_change: ifaddr: %s ", inet_ntoa (ifaddr)); + printf ("area_id: %s\n", inet_ntoa (area_id)); + printf ("state: %d [%s]\n", state, LOOKUP (ospf_ism_state_msg, state)); +} + +void +nsm_change_callback (struct in_addr ifaddr, struct in_addr nbraddr, + struct in_addr router_id, u_char state) +{ + printf ("nsm_change: ifaddr: %s ", inet_ntoa (ifaddr)); + printf ("nbraddr: %s\n", inet_ntoa (nbraddr)); + printf ("router_id: %s\n", inet_ntoa (router_id)); + printf ("state: %d [%s]\n", state, LOOKUP (ospf_nsm_state_msg, state)); +} + + +/* --------------------------------------------------------- + * Main program + * --------------------------------------------------------- + */ + +int usage() +{ + printf("Usage: ospfclient <ospfd> <lsatype> <opaquetype> <opaqueid> <ifaddr> <areaid>\n"); + printf("where ospfd : router where API-enabled OSPF daemon is running\n"); + printf(" lsatype : either 9, 10, or 11 depending on flooding scope\n"); + printf(" opaquetype: 0-255 (e.g., experimental applications use > 128)\n"); + printf(" opaqueid : arbitrary application instance (24 bits)\n"); + printf(" ifaddr : interface IP address (for type 9) otherwise ignored\n"); + printf(" areaid : area in IP address format (for type 10) otherwise ignored\n"); + + exit(1); +} + +int +main (int argc, char *argv[]) +{ + struct thread thread; + + args = argv; + + /* ospfclient should be started with the following arguments: + * + * (1) host (2) lsa_type (3) opaque_type (4) opaque_id (5) if_addr + * (6) area_id + * + * host: name or IP of host where ospfd is running + * lsa_type: 9, 10, or 11 + * opaque_type: 0-255 (e.g., experimental applications use > 128) + * opaque_id: arbitrary application instance (24 bits) + * if_addr: interface IP address (for type 9) otherwise ignored + * area_id: area in IP address format (for type 10) otherwise ignored + */ + + if (argc != 7) + { + usage(); + } + + /* Initialization */ + zprivs_init (&ospfd_privs); + master = thread_master_create (); + + /* Open connection to OSPF daemon */ + oclient = ospf_apiclient_connect (args[1], ASYNCPORT); + if (!oclient) + { + printf ("Connecting to OSPF daemon on %s failed!\n", + args[1]); + exit (1); + } + + /* Register callback functions. */ + ospf_apiclient_register_callback (oclient, + ready_callback, + new_if_callback, + del_if_callback, + ism_change_callback, + nsm_change_callback, + lsa_update_callback, + lsa_delete_callback); + + /* Register LSA type and opaque type. */ + ospf_apiclient_register_opaque_type (oclient, atoi (args[2]), + atoi (args[3])); + + /* Synchronize database with OSPF daemon. */ + ospf_apiclient_sync_lsdb (oclient); + + /* Schedule thread that handles asynchronous messages */ + thread_add_read (master, lsa_read, oclient, oclient->fd_async); + + /* Now connection is established, run loop */ + while (1) + { + thread_fetch (master, &thread); + thread_call (&thread); + } + + /* Never reached */ + return 0; +} + diff --git a/ospfd/Makefile.am b/ospfd/Makefile.am index 2b905804..dd0a0922 100644 --- a/ospfd/Makefile.am +++ b/ospfd/Makefile.am @@ -4,7 +4,7 @@ INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 -noinst_LIBRARIES = libospf.a +lib_LIBRARIES = libospf.a sbin_PROGRAMS = ospfd libospf_a_SOURCES = \ @@ -12,19 +12,23 @@ libospf_a_SOURCES = \ ospf_nsm.c ospf_dump.c ospf_network.c ospf_packet.c ospf_lsa.c \ ospf_spf.c ospf_route.c ospf_ase.c ospf_abr.c ospf_ia.c ospf_flood.c \ ospf_lsdb.c ospf_asbr.c ospf_routemap.c ospf_snmp.c \ - ospf_opaque.c ospf_te.c ospf_vty.c + ospf_opaque.c ospf_te.c ospf_vty.c ospf_api.c ospf_apiserver.c + +ospfdheaderdir = $(includedir)/ospfd + +ospfdheader_HEADERS = \ + ospf_api.h ospf_asbr.h ospf_dump.h ospf_lsa.h ospf_lsdb.h \ + ospf_nsm.h ospf_ism.h ospf_opaque.h ospfd.h noinst_HEADERS = \ - ospf_dump.h ospf_interface.h ospf_ism.h ospf_neighbor.h \ - ospf_network.h ospf_nsm.h ospf_packet.h ospf_zebra.h ospfd.h \ - ospf_lsa.h ospf_spf.h ospf_route.h ospf_ase.h ospf_abr.h ospf_ia.h \ - ospf_flood.h ospf_lsdb.h ospf_asbr.h ospf_snmp.h ospf_opaque.h \ - ospf_te.h ospf_vty.h + ospf_interface.h ospf_neighbor.h ospf_network.h ospf_packet.h \ + ospf_zebra.h ospf_spf.h ospf_route.h ospf_ase.h ospf_abr.h ospf_ia.h \ + ospf_flood.h ospf_snmp.h ospf_te.h ospf_vty.h ospf_apiserver.h ospfd_SOURCES = \ ospf_main.c $(libospf_a_SOURCES) -ospfd_LDADD = ../lib/libzebra.a +ospfd_LDADD = ../lib/libzebra.a @LIBCAP@ sysconf_DATA = ospfd.conf.sample diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index e649c17b..12415453 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -36,6 +36,7 @@ #include "stream.h" #include "log.h" #include "memory.h" +#include "privs.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" @@ -47,6 +48,28 @@ #include "ospfd/ospf_zebra.h" #include "ospfd/ospf_vty.h" +/* ospfd privileges */ +zebra_capabilities_t _caps_p [] = +{ + ZCAP_RAW, + ZCAP_BIND, + ZCAP_BROADCAST, + CAP_NET_ADMIN +}; + +struct zebra_privs_t ospfd_privs = +{ +#if defined(ZEBRA_USER) + .user = ZEBRA_USER, +#endif +#if defined ZEBRA_GROUP + .group = ZEBRA_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 +84,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 +112,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\ @@ -170,7 +195,7 @@ main (int argc, char **argv) { char *p; char *vty_addr = NULL; - int vty_port = 0; + int vty_port = OSPF_VTY_PORT; int daemon_mode = 0; char *config_file = NULL; char *progname; @@ -222,8 +247,19 @@ main (int argc, char **argv) pid_file = optarg; break; case 'P': - vty_port = atoi (optarg); - break; + /* Deal with atoi() returning 0 on failure, and ospfd not + listening on ospfd port... */ + if (strcmp(optarg, "0") == 0) + { + vty_port = 0; + break; + } + 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); @@ -241,6 +277,7 @@ main (int argc, char **argv) master = om->master; /* Library inits. */ + zprivs_init (&ospfd_privs); signal_init (); cmd_init (1); debug_init (); @@ -280,8 +317,7 @@ main (int argc, char **argv) pid_output (pid_file); /* Create VTY socket */ - vty_serv_sock (vty_addr, - vty_port ? vty_port : OSPF_VTY_PORT, OSPF_VTYSH_PATH); + vty_serv_sock (vty_addr, vty_port, OSPF_VTYSH_PATH); /* Print banner. */ zlog (NULL, LOG_INFO, "OSPFd (%s) starts", ZEBRA_VERSION); diff --git a/ospfd/ospf_network.c b/ospfd/ospf_network.c index 56ec8647..9d3bed11 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,16 @@ 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"); + ospf_sock = socket (AF_INET, SOCK_RAW, IPPROTO_OSPFIGP); if (ospf_sock < 0) { zlog_warn ("ospf_read_sock_init: socket: %s", strerror (errno)); return -1; } + /* Set precedence field. */ #ifdef IPTOS_PREC_INTERNETCONTROL @@ -187,6 +196,9 @@ ospf_sock_init (void) #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"); return ospf_sock; } diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 9b6b4877..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; @@ -516,9 +517,6 @@ ospf_area_free (struct ospf_area *area) ospf_lsdb_delete_all (area->lsdb); ospf_lsdb_free (area->lsdb); -#ifdef HAVE_OPAQUE_LSA - ospf_opaque_type10_lsa_term (area); -#endif /* HAVE_OPAQUE_LSA */ ospf_lsa_unlock (area->router_lsa_self); route_table_finish (area->ranges); @@ -637,7 +635,7 @@ ospf_network_set (struct ospf *ospf, struct prefix_ipv4 *p, struct ospf_area *area; struct route_node *rn; struct external_info *ei; - int ret = OSPF_AREA_ID_FORMAT_DECIMAL; + int ret = OSPF_AREA_ID_FORMAT_ADDRESS; rn = route_node_get (ospf->networks, (struct prefix *)p); if (rn->info) @@ -704,7 +702,25 @@ ospf_network_unset (struct ospf *ospf, struct prefix_ipv4 *p, return 1; } - +/* Check whether interface matches given network + * returns: 1, true. 0, false + */ +int +ospf_network_match_iface(struct connected *co, struct prefix *net) +{ + /* Behaviour to match both Cisco where: + * iface address lies within network specified -> ospf + * and zebra 0.9[2ish-3]: + * PtP special case: network specified == iface peer addr -> ospf + */ + return ( + ((ifc_pointopoint (co) && + IPV4_ADDR_SAME ( &(co->destination->u.prefix4), &(net->u.prefix4))) + || prefix_match (net, co->address)) + ? 1 : 0 + ); +} + void ospf_network_run (struct ospf *ospf, struct prefix *p, struct ospf_area *area) { @@ -736,19 +752,21 @@ ospf_network_run (struct ospf *ospf, struct prefix *p, struct ospf_area *area) { struct connected *co = getdata (cn); struct prefix *addr; + + if (CHECK_FLAG(co->flags,ZEBRA_IFA_SECONDARY)) + continue; - if (if_is_pointopoint (ifp)) + if (ifc_pointopoint (co)) addr = co->destination; else addr = co->address; - if (p->family == co->address->family && - ! ospf_if_is_configured (ospf, &(addr->u.prefix4))) - if ((if_is_pointopoint (ifp) && - IPV4_ADDR_SAME (&(addr->u.prefix4), &(p->u.prefix4))) || - prefix_match (p, addr)) + if (p->family == co->address->family + && ! ospf_if_is_configured (ospf, &(addr->u.prefix4)) + && ospf_network_match_iface(co,p)) { - struct ospf_interface *oi; + struct ospf_interface *oi; + assert(co); oi = ospf_if_new (ospf, ifp, co->address); oi->connected = co; @@ -799,7 +817,7 @@ ospf_network_run (struct ospf *ospf, struct prefix *p, struct ospf_area *area) ospf_area_add_if (oi->area, oi); - if (if_is_up (ifp)) + if (if_is_operative (ifp)) ospf_if_up (oi); break; @@ -873,10 +891,7 @@ ospf_if_update (struct ospf *ospf) if (rn->info == NULL) continue; - if ((oi->type == OSPF_IFTYPE_POINTOPOINT - && IPV4_ADDR_SAME (&(co->destination->u.prefix4), - &(rn->p.u.prefix4))) - || prefix_match (&(rn->p), co->address)) + if (ospf_network_match_iface(co,&rn->p)) { found = 1; route_unlock_node (rn); @@ -1032,7 +1047,7 @@ int ospf_area_stub_set (struct ospf *ospf, struct in_addr area_id) { struct ospf_area *area; - int format = OSPF_AREA_ID_FORMAT_DECIMAL; + int format = OSPF_AREA_ID_FORMAT_ADDRESS; area = ospf_area_get (ospf, area_id, format); if (ospf_area_vlink_count (ospf, area)) @@ -1065,7 +1080,7 @@ int ospf_area_no_summary_set (struct ospf *ospf, struct in_addr area_id) { struct ospf_area *area; - int format = OSPF_AREA_ID_FORMAT_DECIMAL; + int format = OSPF_AREA_ID_FORMAT_ADDRESS; area = ospf_area_get (ospf, area_id, format); area->no_summary = 1; @@ -1092,7 +1107,7 @@ int ospf_area_nssa_set (struct ospf *ospf, struct in_addr area_id) { struct ospf_area *area; - int format = OSPF_AREA_ID_FORMAT_DECIMAL; + int format = OSPF_AREA_ID_FORMAT_ADDRESS; area = ospf_area_get (ospf, area_id, format); if (ospf_area_vlink_count (ospf, area)) diff --git a/redhat/zebra.pam b/redhat/zebra.pam new file mode 100644 index 00000000..1390edf4 --- /dev/null +++ b/redhat/zebra.pam @@ -0,0 +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 + +# 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 new file mode 100644 index 00000000..c6e6cef9 --- /dev/null +++ b/redhat/zebra.spec.in @@ -0,0 +1,372 @@ +# configure options +%define with_snmp 0 +%define with_vtysh 1 +%define with_ospf_te 1 +%define with_nssa 1 +%define with_opaque_lsa 1 +%define with_tcp_zebra 0 +%define with_vtysh 1 +%define with_pam 1 +%define with_ipv6 1 +%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 +%define zeb_src %{_builddir}/%{name}-%{version} +%define zeb_rh_src %{zeb_src}/redhat +%define zeb_docs %{zeb_src}/doc + +# defines for configure +%define _libexecdir %{_exec_prefix}/libexec/zebra +%define _includedir %{_prefix}/include/zebra +%define _libdir %{_exec_prefix}/%{_lib}/zebra +%define _localstatedir /var/run/zebra + +Summary: Routing daemon +Name: zebra +Version: @VERSION@ +Release: @CONFDATE@01 +License: GPL +Group: System Environment/Daemons +Source0: ftp://ftp.zebra.org/pub/zebra/%{name}-%{version}.tar.gz +URL: http://www.zebra.org/ +%if %with_snmp +#BuildRequires: ucd-snmp-devel +Prereq: ucd-snmp +%endif +%if %with_vtysh +BuildRequires: readline readline-devel ncurses ncurses-devel +Prereq: readline ncurses +%endif +BuildRequires: texinfo tetex autoconf openssl-devel pam-devel patch +# Initscripts > 5.60 is required for IPv6 support +Prereq: initscripts >= 5.60 +Prereq: openssl ncurses readline pam +Prereq: /sbin/install-info +Provides: routingdaemon +BuildRoot: %{_tmppath}/%{name}-%{version}-root +Obsoletes: bird gated mrt + +%description +GNU Zebra is a free software that manages TCP/IP based routing +protocol. It takes multi-server and multi-thread approach to resolve +the current complexity of the Internet. + +GNU Zebra supports BGP4, BGP4+, OSPFv2, OSPFv3, RIPv1, RIPv2, and RIPng. + +GNU Zebra is intended to be used as a Route Server and a Route +Reflector. It is not a toolkit, it provides full routing power under +a new architecture. GNU Zebra is unique in design in that it has a +process for each protocol. + +%package contrib +Summary: contrib tools for zebra +Group: System Environment/Daemons + +%description contrib +Contributed/3rd party tools which may be of use with zebra. + +%package devel +Summary: Header and object files for zebra development +Group: System Environment/Daemons + +%description devel +The zebra-devel package contains the header and object files neccessary for +developing OSPF-API and zebra applications. + +%prep +%setup -q + +%build +%configure \ +%if %with_ipv6 + --enable-ipv6 \ +%endif +%if %with_snmp + --enable-snmp \ +%endif +%if %with_multipath + --enable-multipath=%with_multipath \ +%endif +%if %with_tcp_zebra + --enable-tcp-zebra \ +%endif +%if %with_nssa + --enable-nssa \ +%endif +%if %with_opaque_lsa + --enable-opaque-lsa \ +%endif +%if %with_ospf_te + --enable-ospf-te \ +%endif +%if %with_vtysh + --enable-vtysh \ +%endif +%if %with_ospfclient + --enable-ospfclient=yes \ +%else + --enable-ospfclient=no\ +%endif +%if %with_ospfapi + --enable-ospfapi=yes \ +%else + --enable-ospfapi=no \ +%endif +%if %with_pam + --with-libpam \ +%endif +%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" + +pushd doc +texi2html zebra.texi +popd + +%install +rm -rf $RPM_BUILD_ROOT + +install -d $RPM_BUILD_ROOT/etc/{rc.d/init.d,sysconfig,logrotate.d,pam.d} \ + $RPM_BUILD_ROOT/var/log/zebra $RPM_BUILD_ROOT%{_infodir} + +make install \ + DESTDIR=$RPM_BUILD_ROOT + +install %{zeb_rh_src}/zebra.init $RPM_BUILD_ROOT/etc/rc.d/init.d/zebra +install %{zeb_rh_src}/bgpd.init $RPM_BUILD_ROOT/etc/rc.d/init.d/bgpd +%if %with_ipv6 +install %{zeb_rh_src}/ospf6d.init $RPM_BUILD_ROOT/etc/rc.d/init.d/ospf6d +install %{zeb_rh_src}/ripngd.init $RPM_BUILD_ROOT/etc/rc.d/init.d/ripngd +%endif +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> +# e.g. zebra_spec_add_service zebrasrv 2600/tcp "zebra service" + +zebra_spec_add_service () +{ + # Add port /etc/services entry if it isn't already there + if [ -f /etc/services ] && ! grep -q "^$1[^a-zA-Z0-9]" /etc/services ; then + echo "$1 $2 # $3" >> /etc/services + fi +} + +zebra_spec_add_service zebrasrv 2600/tcp "zebra service" +zebra_spec_add_service zebra 2601/tcp "zebra vty" +zebra_spec_add_service ripd 2602/tcp "RIPd vty" +%if %with_ipv6 +zebra_spec_add_service ripngd 2603/tcp "RIPngd vty" +%endif +zebra_spec_add_service ospfd 2604/tcp "OSPFd vty" +zebra_spec_add_service bgpd 2605/tcp "BGPd vty" +%if %with_ipv6 +zebra_spec_add_service ospf6d 2606/tcp "OSPF6d vty" +%endif + +/sbin/chkconfig --add zebra +/sbin/chkconfig --add ripd +%if %with_ipv6 +/sbin/chkconfig --add ripngd +/sbin/chkconfig --add ospf6d +%endif +/sbin/chkconfig --add ospfd +/sbin/chkconfig --add bgpd + +/sbin/install-info %{_infodir}/zebra.info.gz %{_infodir}/dir + +# Create dummy files if they don't exist so basic functions can be used. +if [ ! -e %{_sysconfdir}/zebra.conf ]; then + echo "hostname `hostname`" > %{_sysconfdir}/zebra.conf + chmod 640 %{_sysconfdir}/zebra.conf +fi +if [ ! -e %{_sysconfdir}/vtysh.conf ]; then + touch %{_sysconfdir}/vtysh.conf + chmod 640 %{_sysconfdir}/vtysh.conf +fi + +%postun +if [ "$1" -ge "1" ]; then + /etc/rc.d/init.d/zebra condrestart >/dev/null 2>&1 + /etc/rc.d/init.d/ripd condrestart >/dev/null 2>&1 +%if %with_ipv6 + /etc/rc.d/init.d/ripngd condrestart >/dev/null 2>&1 +%endif + /etc/rc.d/init.d/ospfd condrestart >/dev/null 2>&1 +%if %with_ipv6 + /etc/rc.d/init.d/ospf6d condrestart >/dev/null 2>&1 +%endif + /etc/rc.d/init.d/bgpd condrestart >/dev/null 2>&1 +fi +/sbin/install-info --delete %{_infodir}/zebra.info.gz %{_infodir}/dir + +%preun +if [ "$1" = "0" ]; then + /sbin/chkconfig --del zebra + /sbin/chkconfig --del ripd +%if %with_ipv6 + /sbin/chkconfig --del ripngd +%endif + /sbin/chkconfig --del ospfd +%if %with_ipv6 + /sbin/chkconfig --del ospf6d +%endif + /sbin/chkconfig --del bgpd +fi + +%clean +#rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root) +%doc */*.sample* AUTHORS COPYING +%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 +%endif +%{_infodir}/*info* +%{_mandir}/man*/* +%{_sbindir}/* +%if %with_vtysh +%{_bindir}/* +%endif +%config /etc/zebra/*.conf +%config /etc/rc.d/init.d/* +%config(noreplace) /etc/pam.d/zebra +%config(noreplace) %attr(640,root,root) /etc/logrotate.d/* + +%files contrib +%defattr(-,root,root) +%doc tools + +%files devel +%defattr(-,root,root) +%dir %{_libdir}/* +%dir %{_includedir}/ospfd/* +%if %with_ospfapi +%dir %{_includedir}/ospfapi/* +%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 +- Amir: Fix configure.ac for net-snmp + +* Sat Mar 1 2003 Paul Jakma <paul@dishone.st> +- ospfd IOS prefix to interface matching for 'network' statement +- temporary fix for PtP and IPv6 +- sync to zebra.org CVS + +* Mon Jan 20 2003 Paul Jakma <paul@dishone.st> +- update to latest cvs +- Yon's "show thread cpu" patch - 17217 +- walk up tree - 17218 +- ospfd NSSA fixes - 16681 +- ospfd nsm fixes - 16824 +- ospfd OLSA fixes and new feature - 16823 +- KAME and ifindex fixes - 16525 +- spec file changes to allow redhat files to be in tree + +* Sat Dec 28 2002 Alexander Hoogerhuis <alexh@ihatent.com> +- Added conditionals for building with(out) IPv6, vtysh, RIP, BGP +- Fixed up some build requirements (patch) +- Added conditional build requirements for vtysh / snmp +- Added conditional to %files for %_bindir depending on vtysh + +* Mon Nov 11 2002 Paul Jakma <paulj@alphyra.ie> +- update to latest CVS +- add Greg Troxel's md5 buffer copy/dup fix +- add RIPv1 fix +- add Frank's multicast flag fix + +* Wed Oct 09 2002 Paul Jakma <paulj@alphyra.ie> +- update to latest CVS +- timestamped crypt_seqnum patch +- oi->on_write_q fix + +* Mon Sep 30 2002 Paul Jakma <paulj@alphyra.ie> +- update to latest CVS +- add vtysh 'write-config (integrated|daemon)' patch +- always 'make rebuild' in vtysh/ to catch new commands + +* Fri Sep 13 2002 Paul Jakma <paulj@alphyra.ie> +- update to 0.93b + +* Wed Sep 11 2002 Paul Jakma <paulj@alphyra.ie> +- update to latest CVS +- add "/sbin/ip route flush proto zebra" to zebra RH init on startup + +* Sat Aug 24 2002 Paul Jakma <paulj@alphyra.ie> +- update to current CVS +- add OSPF point to multipoint patch +- add OSPF bugfixes +- add BGP hash optimisation patch + +* Fri Jun 14 2002 Paul Jakma <paulj@alphyra.ie> +- update to 0.93-pre1 / CVS +- add link state detection support +- add generic PtP and RFC3021 support +- various bug fixes + +* Thu Aug 09 2001 Elliot Lee <sopwith@redhat.com> 0.91a-6 +- Fix bug #51336 + +* Wed Aug 1 2001 Trond Eivind Glomsrød <teg@redhat.com> 0.91a-5 +- Use generic initscript strings instead of initscript specific + ( "Starting foo: " -> "Starting $prog:" ) + +* Fri Jul 27 2001 Elliot Lee <sopwith@redhat.com> 0.91a-4 +- Bump the release when rebuilding into the dist. + +* Tue Feb 6 2001 Tim Powers <timp@redhat.com> +- built for Powertools + +* Sun Feb 4 2001 Pekka Savola <pekkas@netcore.fi> +- Hacked up from PLD Linux 0.90-1, Mandrake 0.90-1mdk and one from zebra.org. +- Update to 0.91a +- Very heavy modifications to init.d/*, .spec, pam, i18n, logrotate, etc. +- Should be quite Red Hat'isque now. diff --git a/ripd/Makefile.am b/ripd/Makefile.am index fd254851..138c3a51 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 = ../lib/libzebra.a +ripd_LDADD = ../lib/libzebra.a @LIBCAP@ sysconf_DATA = ripd.conf.sample diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c index 06d4416b..d7856341 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" @@ -52,6 +53,8 @@ struct message ri_version_msg[] = {0, NULL} }; +extern struct zebra_privs_t ripd_privs; + /* RIP enabled network vector. */ vector rip_enable_interface; @@ -173,6 +176,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) @@ -181,6 +187,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; } @@ -248,7 +257,7 @@ rip_request_interface (struct interface *ifp) return; /* If interface is down, don't send RIP packet. */ - if (! if_is_up (ifp)) + if (! if_is_operative (ifp)) return; /* Fetch RIP interface information. */ @@ -311,7 +320,7 @@ rip_multicast_join (struct interface *ifp, int sock) { listnode cnode; - if (if_is_up (ifp) && if_is_multicast (ifp)) + if (if_is_operative (ifp) && if_is_multicast (ifp)) { if (IS_RIP_DEBUG_EVENT) zlog_info ("multicast join at %s", ifp->name); @@ -391,106 +400,6 @@ rip_if_ipv4_address_check (struct interface *ifp) return count; } - - - - -/* Does this address belongs to me ? */ -int -if_check_address (struct in_addr addr) -{ - listnode node; - - for (node = listhead (iflist); node; nextnode (node)) - { - listnode cnode; - struct interface *ifp; - - ifp = getdata (node); - - for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) - { - struct connected *connected; - struct prefix_ipv4 *p; - - connected = getdata (cnode); - p = (struct prefix_ipv4 *) connected->address; - - if (p->family != AF_INET) - continue; - - if (IPV4_ADDR_CMP (&p->prefix, &addr) == 0) - return 1; - } - } - return 0; -} - -/* is this address from a valid neighbor? (RFC2453 - Sec. 3.9.2) */ -int -if_valid_neighbor (struct in_addr addr) -{ - listnode node; - struct connected *connected = NULL; - struct prefix_ipv4 *p; - - for (node = listhead (iflist); node; nextnode (node)) - { - listnode cnode; - struct interface *ifp; - - ifp = getdata (node); - - for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) - { - struct prefix *pxn = NULL; /* Prefix of the neighbor */ - struct prefix *pxc = NULL; /* Prefix of the connected network */ - - connected = getdata (cnode); - - if (if_is_pointopoint (ifp)) - { - p = (struct prefix_ipv4 *) connected->address; - - if (p && p->family == AF_INET) - { - if (IPV4_ADDR_SAME (&p->prefix, &addr)) - return 1; - - p = (struct prefix_ipv4 *) connected->destination; - if (p && IPV4_ADDR_SAME (&p->prefix, &addr)) - return 1; - } - } - else - { - p = (struct prefix_ipv4 *) connected->address; - - if (p->family != AF_INET) - continue; - - pxn = prefix_new(); - pxn->family = AF_INET; - pxn->prefixlen = 32; - pxn->u.prefix4 = addr; - - pxc = prefix_new(); - prefix_copy(pxc, (struct prefix *) p); - apply_mask(pxc); - - if (prefix_match (pxc, pxn)) - { - prefix_free (pxn); - prefix_free (pxc); - return 1; - } - prefix_free(pxc); - prefix_free(pxn); - } - } - } - return 0; -} /* Inteface link down message processing. */ int @@ -705,7 +614,7 @@ rip_if_down(struct interface *ifp) { /* All redistributed routes but static and system */ if ((rinfo->ifindex == ifp->ifindex) && - (rinfo->type != ZEBRA_ROUTE_STATIC) && + /* (rinfo->type != ZEBRA_ROUTE_STATIC) && */ (rinfo->type != ZEBRA_ROUTE_SYSTEM)) rip_redistribute_delete (rinfo->type,rinfo->sub_type, (struct prefix_ipv4 *)&rp->p, @@ -1008,7 +917,7 @@ rip_enable_apply (struct interface *ifp) if (if_is_loopback (ifp)) return; - if (! if_is_up (ifp)) + if (! if_is_operative (ifp)) return; ri = ifp->info; @@ -1961,6 +1870,7 @@ rip_if_init () /* Install commands. */ install_element (CONFIG_NODE, &interface_cmd); + install_element (CONFIG_NODE, &no_interface_cmd); install_default (INTERFACE_NODE); install_element (INTERFACE_NODE, &interface_desc_cmd); install_element (INTERFACE_NODE, &no_interface_desc_cmd); diff --git a/ripd/rip_main.c b/ripd/rip_main.c index 1070fb45..ef7e119a 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\ @@ -211,11 +234,22 @@ main (int argc, char **argv) pid_file = optarg; break; case 'P': - vty_port = atoi (optarg); + /* Deal with atoi() returning 0 on failure, and ripd not + listening on rip port... */ + if (strcmp(optarg, "0") == 0) + { + vty_port = 0; + break; + } + vty_port = atoi (optarg); + vty_port = (vty_port ? vty_port : RIP_VTY_PORT); break; case 'r': retain_mode = 1; break; + case 'u': + ripd_privs.group = ripd_privs.user = optarg; + break; case 'v': print_version (progname); exit (0); @@ -233,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 c017fe56..42974a72 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -36,10 +36,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; @@ -55,8 +58,8 @@ long rip_global_queries = 0; /* Prototypes. */ void rip_event (enum rip_event, int); -void rip_output_process (struct interface *, struct sockaddr_in *, - int, u_char); +void rip_output_process (struct interface *, struct prefix *, + struct sockaddr_in *, int, u_char); /* RIP output routes type. */ enum @@ -955,7 +958,14 @@ rip_response_process (struct rip_packet *packet, int size, { caddr_t lim; struct rte *rte; + struct prefix_ipv4 ifaddr; + struct prefix_ipv4 ifaddrclass; + struct connected *c; + int subnetted; + /* We don't know yet. */ + subnetted = -1; + /* The Response must be ignored if it is not from the RIP port. (RFC2453 - Sec. 3.9.2)*/ if (ntohs (from->sin_port) != RIP_PORT_DEFAULT) @@ -969,7 +979,7 @@ rip_response_process (struct rip_packet *packet, int size, /* The datagram's IPv4 source address should be checked to see whether the datagram is from a valid neighbor; the source of the datagram must be on a directly connected network */ - if (! if_valid_neighbor (from->sin_addr)) + if (if_lookup_address (from->sin_addr) == NULL) { zlog_info ("This datagram doesn't came from a valid neighbor: %s", inet_ntoa (from->sin_addr)); @@ -1108,23 +1118,51 @@ rip_response_process (struct rip_packet *packet, int size, { u_int32_t destination; - destination = ntohl (rte->prefix.s_addr); - - if (destination & 0xff) + if (subnetted == -1) { - masklen2ip (32, &rte->mask); + c = connected_lookup_address (ifp, from->sin_addr); + if (c != NULL) + { + memcpy (&ifaddr, c->address, sizeof (struct prefix_ipv4)); + memcpy (&ifaddrclass, &ifaddr, sizeof (struct prefix_ipv4)); + apply_classful_mask_ipv4 (&ifaddrclass); + subnetted = 0; + if (ifaddr.prefixlen > ifaddrclass.prefixlen) + subnetted = 1; + } } - else if ((destination & 0xff00) || IN_CLASSC (destination)) - { + + destination = ntohl (rte->prefix.s_addr); + + if (IN_CLASSA (destination)) + masklen2ip (8, &rte->mask); + else if (IN_CLASSB (destination)) + masklen2ip (16, &rte->mask); + else if (IN_CLASSC (destination)) masklen2ip (24, &rte->mask); + + if (subnetted == 1) + masklen2ip (ifaddrclass.prefixlen, + (struct in_addr *) &destination); + if ((subnetted == 1) && ((rte->prefix.s_addr & destination) == + ifaddrclass.prefix.s_addr)) + { + masklen2ip (ifaddr.prefixlen, &rte->mask); + if ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr) + masklen2ip (32, &rte->mask); + if (IS_RIP_DEBUG_EVENT) + zlog_info ("Subnetted route %s", inet_ntoa (rte->prefix)); } - else if ((destination & 0xff0000) || IN_CLASSB (destination)) + else { - masklen2ip (16, &rte->mask); + if ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr) + continue; } - else + + if (IS_RIP_DEBUG_EVENT) { - masklen2ip (8, &rte->mask); + zlog_info ("Resultant route %s", inet_ntoa (rte->prefix)); + zlog_info ("Resultant mask %s", inet_ntoa (rte->mask)); } } @@ -1353,7 +1391,7 @@ rip_request_process (struct rip_packet *packet, int size, ntohl (rte->metric) == RIP_METRIC_INFINITY) { /* All route with split horizon */ - rip_output_process (ifp, from, rip_all_route, packet->version); + rip_output_process (ifp, NULL, from, rip_all_route, packet->version); } else { @@ -1500,7 +1538,7 @@ rip_read (struct thread *t) } /* Check is this packet comming from myself? */ - if (if_check_address (from.sin_addr)) + if (if_lookup_exact_address (from.sin_addr)) { if (IS_RIP_DEBUG_PACKET) zlog_warn ("ignore packet comes from myself"); @@ -1785,13 +1823,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; } @@ -1884,8 +1926,8 @@ rip_write_rte (int num, struct stream *s, struct prefix_ipv4 *p, /* Send update to the ifp or spcified neighbor. */ void -rip_output_process (struct interface *ifp, struct sockaddr_in *to, - int route_type, u_char version) +rip_output_process (struct interface *ifp, struct prefix *ifaddr, + struct sockaddr_in *to, int route_type, u_char version) { int ret; struct stream *s; @@ -1894,8 +1936,11 @@ rip_output_process (struct interface *ifp, struct sockaddr_in *to, struct rip_interface *ri; struct prefix_ipv4 *p; struct prefix_ipv4 classfull; + struct prefix_ipv4 ifaddrclass; + struct connected *c; int num; int rtemax; + int subnetted; /* Logging output event. */ if (IS_RIP_DEBUG_EVENT) @@ -1946,29 +1991,60 @@ rip_output_process (struct interface *ifp, struct sockaddr_in *to, rtemax -=1; } + if (version == RIPv1) + { + if (ifaddr == NULL) + { + c = connected_lookup_address (ifp, to->sin_addr); + if (c != NULL) + ifaddr = c->address; + } + if (ifaddr == NULL) + { + zlog_warn ("cannot find source address for packets to neighbor %s", + inet_ntoa (to->sin_addr)); + return; + } + memcpy (&ifaddrclass, ifaddr, sizeof (struct prefix_ipv4)); + apply_classful_mask_ipv4 (&ifaddrclass); + subnetted = 0; + if (ifaddr->prefixlen > ifaddrclass.prefixlen) + subnetted = 1; + } + for (rp = route_top (rip->table); rp; rp = route_next (rp)) if ((rinfo = rp->info) != NULL) { - /* Some inheritance stuff: */ - /* Before we process with ipv4 prefix we should mask it */ - /* with Classful mask if we send RIPv1 packet.That's because */ - /* user could set non-classful mask or we could get it by RIPv2 */ - /* or other protocol. checked with Cisco's way of life :) */ + /* For RIPv1, if we are subnetted, output subnets in our network */ + /* that have the same mask as the output "interface". For other */ + /* networks, only the classfull version is output. */ if (version == RIPv1) { - memcpy (&classfull, &rp->p, sizeof (struct prefix_ipv4)); + p = (struct prefix_ipv4 *) &rp->p; if (IS_RIP_DEBUG_PACKET) - zlog_info("%s/%d before RIPv1 mask check ", - inet_ntoa (classfull.prefix), classfull.prefixlen); - - apply_classful_mask_ipv4 (&classfull); - p = &classfull; + zlog_info("RIPv1 mask check, %s/%d considered for output", + inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen); + if (subnetted && + prefix_match ((struct prefix *) &ifaddrclass, &rp->p)) + { + if ((ifaddr->prefixlen != rp->p.prefixlen) && + (rp->p.prefixlen != 32)) + continue; + } + else + { + memcpy (&classfull, &rp->p, sizeof(struct prefix_ipv4)); + apply_classful_mask_ipv4(&classfull); + if (rp->p.u.prefix4.s_addr != 0 && + classfull.prefixlen != rp->p.prefixlen) + continue; + } if (IS_RIP_DEBUG_PACKET) - zlog_info("%s/%d after RIPv1 mask check", - inet_ntoa (p->prefix), p->prefixlen); + zlog_info("RIPv1 mask check, %s/%d made it through", + inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen); } else p = (struct prefix_ipv4 *) &rp->p; @@ -2109,7 +2185,7 @@ rip_update_interface (struct interface *ifp, u_char version, int route_type) if (IS_RIP_DEBUG_EVENT) zlog_info ("multicast announce on %s ", ifp->name); - rip_output_process (ifp, NULL, route_type, version); + rip_output_process (ifp, NULL, NULL, route_type, version); return; } @@ -2136,7 +2212,8 @@ rip_update_interface (struct interface *ifp, u_char version, int route_type) if_is_pointopoint (ifp) ? "unicast" : "broadcast", inet_ntoa (to.sin_addr), ifp->name); - rip_output_process (ifp, &to, route_type, version); + rip_output_process (ifp, connected->address, &to, route_type, + version); } } } @@ -2161,7 +2238,7 @@ rip_update_process (int route_type) if (if_is_loopback (ifp)) continue; - if (! if_is_up (ifp)) + if (! if_is_operative (ifp)) continue; /* Fetch RIP interface information. */ @@ -2224,7 +2301,7 @@ rip_update_process (int route_type) to.sin_port = htons (RIP_PORT_DEFAULT); /* RIP version is rip's configuration. */ - rip_output_process (ifp, &to, route_type, rip->version); + rip_output_process (ifp, NULL, &to, route_type, rip->version); } } diff --git a/ripngd/Makefile.am b/ripngd/Makefile.am index 2835aa24..a54b1159 100644 --- a/ripngd/Makefile.am +++ b/ripngd/Makefile.am @@ -9,15 +9,15 @@ sbin_PROGRAMS = ripngd libripng_a_SOURCES = \ ripng_interface.c ripngd.c ripng_zebra.c ripng_route.c ripng_debug.c \ - ripng_routemap.c + ripng_routemap.c ripng_ifrmap.c noinst_HEADERS = \ - ripng_debug.h ripng_route.h ripngd.h + ripng_debug.h ripng_route.h ripngd.h ripng_ifrmap.h ripngd_SOURCES = \ ripng_main.c $(libripng_a_SOURCES) -ripngd_LDADD = ../lib/libzebra.a +ripngd_LDADD = ../lib/libzebra.a @LIBCAP@ sysconf_DATA = ripngd.conf.sample diff --git a/ripngd/ripng_main.c b/ripngd/ripng_main.c index aec74bb4..0d5fe78c 100644 --- a/ripngd/ripng_main.c +++ b/ripngd/ripng_main.c @@ -31,6 +31,7 @@ #include "log.h" #include "prefix.h" #include "if.h" +#include "privs.h" #include "ripngd/ripngd.h" @@ -49,10 +50,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. */ @@ -81,6 +104,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\ @@ -155,7 +179,7 @@ main (int argc, char **argv) { char *p; char *vty_addr = NULL; - int vty_port = 0; + int vty_port = RIPNG_VTY_PORT; int daemon_mode = 0; char *config_file = NULL; char *progname; @@ -197,13 +221,24 @@ main (int argc, char **argv) break; case 'i': pid_file = optarg; - break; + break; case 'P': - vty_port = atoi (optarg); - break; + /* Deal with atoi() returning 0 on failure, and ripngd not + listening on ripngd port... */ + if (strcmp(optarg, "0") == 0) + { + vty_port = 0; + break; + } + vty_port = atoi (optarg); + vty_port = (vty_port ? vty_port : RIPNG_VTY_PORT); + break; case 'r': retain_mode = 1; break; + case 'u': + ripngd_privs.group = ripngd_privs.user = optarg; + break; case 'v': print_version (progname); exit (0); @@ -220,6 +255,7 @@ main (int argc, char **argv) master = thread_master_create (); /* Library inits. */ + zprivs_init (&ripngd_privs); signal_init (); cmd_init (1); vty_init (); @@ -237,8 +273,7 @@ main (int argc, char **argv) daemon (0, 0); /* Create VTY socket */ - vty_serv_sock (vty_addr, - vty_port ? vty_port : RIPNG_VTY_PORT, RIPNG_VTYSH_PATH); + vty_serv_sock (vty_addr, vty_port, RIPNG_VTYSH_PATH); /* Process id file create. */ pid_output (pid_file); diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index 98d4bb70..677f7bbc 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -37,11 +37,12 @@ #include "distribute.h" #include "plist.h" #include "routemap.h" -#include "if_rmap.h" +#include "privs.c" #include "ripngd/ripngd.h" #include "ripngd/ripng_route.h" #include "ripngd/ripng_debug.h" +#include "ripngd/ripng_ifrmap.h" #define min(a, b) ((a) < (b) ? (a) : (b)) @@ -58,6 +59,8 @@ enum ripng_no_split_horizon }; +extern struct zebra_privs_t ripngd_privs; + /* Prototypes. */ void ripng_output_process (struct interface *, struct sockaddr_in6 *, int, int); @@ -153,12 +156,19 @@ ripng_make_socket (void) #endif /* SIN6_LEN */ ripaddr.sin6_port = htons (RIPNG_PORT_DEFAULT); + if (ripngd_privs.change (ZPRIVS_RAISE)) + zlog_err ("ripng_make_socket: could not raise privs"); + ret = bind (sock, (struct sockaddr *) &ripaddr, sizeof (ripaddr)); if (ret < 0) { zlog (NULL, LOG_ERR, "Can't bind ripng socket: %s.", strerror (errno)); return ret; } + + if (ripngd_privs.change (ZPRIVS_LOWER)) + zlog_err ("ripng_make_socket: could not lower privs"); + return sock; } @@ -2178,8 +2188,8 @@ DEFUN (show_ipv6_protocols, show_ipv6_protocols_cmd, } /* Please be carefull to use this command. */ -DEFUN (default_information_originate, - default_information_originate_cmd, +DEFUN (ripng_default_information_originate, + ripng_default_information_originate_cmd, "default-information originate", "Default route information\n" "Distribute default route\n") @@ -2194,8 +2204,8 @@ DEFUN (default_information_originate, return CMD_SUCCESS; } -DEFUN (no_default_information_originate, - no_default_information_originate_cmd, +DEFUN (no_ripng_default_information_originate, + no_ripng_default_information_originate_cmd, "no default-information originate", NO_STR "Default route information\n" @@ -2494,8 +2504,8 @@ ripng_init () install_element (RIPNG_NODE, &no_ripng_garbage_timer_cmd); #endif /* 0 */ - install_element (RIPNG_NODE, &default_information_originate_cmd); - install_element (RIPNG_NODE, &no_default_information_originate_cmd); + install_element (RIPNG_NODE, &ripng_default_information_originate_cmd); + install_element (RIPNG_NODE, &no_ripng_default_information_originate_cmd); ripng_if_init (); ripng_debug_init (); @@ -2520,7 +2530,7 @@ ripng_init () route_map_add_hook (ripng_routemap_update); route_map_delete_hook (ripng_routemap_update); - if_rmap_init (RIPNG_NODE); + if_rmap_init (); if_rmap_hook_add (ripng_if_rmap_update); if_rmap_hook_delete (ripng_if_rmap_update); } diff --git a/vtysh/Makefile.am b/vtysh/Makefile.am index 4327379b..39b7cee0 100644 --- a/vtysh/Makefile.am +++ b/vtysh/Makefile.am @@ -9,14 +9,16 @@ 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 EXTRA_DIST = extract.pl vtysh.conf.sample rebuild4: - ./extract.pl ../zebra/*.c ../ripd/*.c ../ospfd/*.c ../bgpd/*.c ../lib/keychain.c ../lib/routemap.c ../lib/filter.c ../lib/plist.c >vtysh_cmd.c + ./extract.pl ../zebra/*.c ../ripd/*.c ../ospfd/*.c ../bgpd/*.c ../lib/keychain.c ../lib/routemap.c ../lib/filter.c ../lib/plist.c ../lib/distribute.c > vtysh_cmd.c rebuild: - ./extract.pl ../zebra/*.c ../ripd/*.c ../ripngd/*.c ../ospfd/*.c ../ospf6d/*.c ../bgpd/*.c ../lib/keychain.c ../lib/routemap.c ../lib/filter.c ../lib/plist.c >vtysh_cmd.c + ./extract.pl ../zebra/*.c ../ripd/*.c ../ripngd/*.c ../ospfd/*.c ../ospf6d/*.c ../bgpd/*.c ../lib/keychain.c ../lib/routemap.c ../lib/filter.c ../lib/plist.c ../lib/distribute.c > vtysh_cmd.c + +vtysh_cmd.c: rebuild diff --git a/zebra/Makefile.am b/zebra/Makefile.am index a83543ee..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 diff --git a/zebra/ioctl.c b/zebra/ioctl.c index 13afba29..4c341e8b 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..e9d6b9fc 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,15 @@ 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 +143,14 @@ 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 +167,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_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/main.c b/zebra/main.c index 25d8b6de..1c9269d5 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,35 @@ 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_RAW, + ZCAP_BIND, + ZCAP_SYS_ADMIN, + ZCAP_FOWNER, +}; + +/* 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 +118,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\ @@ -174,7 +200,7 @@ main (int argc, char **argv) { char *p; char *vty_addr = NULL; - int vty_port = 0; + int vty_port = ZEBRA_VTY_PORT; int batch_mode = 0; int daemon_mode = 0; char *config_file = NULL; @@ -196,7 +222,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; @@ -226,11 +252,22 @@ main (int argc, char **argv) pid_file = optarg; break; case 'P': + /* Deal with atoi() returning 0 on failure, and zebra not + listening on zebra port... */ + if (strcmp(optarg, "0") == 0) + { + vty_port = 0; + break; + } vty_port = atoi (optarg); + vty_port = (vty_port ? vty_port : ZEBRA_VTY_PORT); break; case 'r': retain_mode = 1; break; + case 'u': + zserv_privs.user = zserv_privs.group = optarg; + break; case 'v': print_version (progname); exit (0); @@ -247,6 +284,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); @@ -305,8 +345,7 @@ main (int argc, char **argv) pid = getpid (); /* Make vty server socket. */ - vty_serv_sock (vty_addr, - vty_port ? vty_port : ZEBRA_VTY_PORT, ZEBRA_VTYSH_PATH); + vty_serv_sock (vty_addr, vty_port, ZEBRA_VTYSH_PATH); while (thread_fetch (master, &thread)) thread_call (&thread); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 7a8073c2..f4f51034 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -33,6 +33,8 @@ #include "connected.h" #include "table.h" #include "rib.h" +#include "thread.h" +#include "privs.h" #include "zebra/zserv.h" #include "zebra/redistribute.h" @@ -66,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) @@ -97,6 +101,9 @@ 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"); + ret = bind (sock, (struct sockaddr *) &snl, sizeof snl); if (ret < 0) { @@ -105,6 +112,9 @@ netlink_socket (struct nlsock *nl, unsigned long groups) 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; @@ -122,6 +132,39 @@ netlink_socket (struct nlsock *nl, unsigned long groups) return ret; } +int set_netlink_blocking(struct nlsock *nl, int *flags) +{ + + /* Change socket flags for blocking I/O. */ + if((*flags = fcntl(nl->sock, F_GETFL, 0)) < 0) + { + zlog (NULL, LOG_ERR, "%s:%i F_GETFL error: %s", + __FUNCTION__, __LINE__, strerror (errno)); + return -1; + } + *flags &= ~O_NONBLOCK; + if(fcntl(nl->sock, F_SETFL, *flags) < 0) + { + zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s", + __FUNCTION__, __LINE__, strerror (errno)); + return -1; + } + return 0; +} + +int set_netlink_nonblocking(struct nlsock *nl, int *flags) +{ + /* Restore socket flags for nonblocking I/O */ + *flags |= O_NONBLOCK; + if(fcntl(nl->sock, F_SETFL, *flags) < 0) + { + zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s", + __FUNCTION__, __LINE__, strerror (errno)); + return -1; + } + return 0; +} + /* Get type specified information from netlink. */ static int netlink_request (int family, int type, struct nlsock *nl) @@ -152,6 +195,12 @@ 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"); ret = sendto (nl->sock, (void*) &req, sizeof req, 0, (struct sockaddr*) &snl, sizeof snl); @@ -160,6 +209,10 @@ netlink_request (int family, int type, struct nlsock *nl) zlog (NULL, LOG_ERR, "%s sendto failed: %s", nl->name, strerror (errno)); return -1; } + + if ( zserv_privs.change(ZPRIVS_LOWER) ) + zlog (NULL, LOG_ERR, "Can't lower privileges"); + return 0; } @@ -181,7 +234,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) { @@ -244,11 +303,26 @@ netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *), nl->name); return -1; } - zlog (NULL, LOG_ERR, "%s error: %s, type=%s(%u), seq=%u, pid=%d", - nl->name, strerror (-err->error), - lookup (nlmsg_str, err->msg.nlmsg_type), - err->msg.nlmsg_type, err->msg.nlmsg_seq, + + /* Deal with Error Noise - MAG*/ + { + int loglvl = LOG_ERR; + int errnum = err->error; + int msg_type = err->msg.nlmsg_type; + + if (nl == &netlink_cmd + && (-errnum == ENODEV || -errnum == ESRCH) + && (msg_type == RTM_NEWROUTE + || msg_type == RTM_DELROUTE)) + loglvl = LOG_DEBUG; + + zlog (NULL, loglvl, "%s error: %s, type=%s(%u), " + "seq=%u, pid=%d", + nl->name, strerror (-errnum), + lookup (nlmsg_str, msg_type), + msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid); + } /* ret = -1; continue; @@ -388,6 +462,7 @@ netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h) void *broad = NULL; u_char flags = 0; char *label = NULL; + int peeronly = 0; ifa = NLMSG_DATA (h); @@ -416,40 +491,56 @@ netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h) return -1; } - if (tb[IFA_ADDRESS] == NULL) - tb[IFA_ADDRESS] = tb[IFA_LOCAL]; - - if (ifp->flags & IFF_POINTOPOINT) + if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */ { + char buf[BUFSIZ]; + zlog_info ("netlink_interface_addr %s %s/%d:", + lookup (nlmsg_str, h->nlmsg_type), + ifp->name, ifa->ifa_prefixlen); if (tb[IFA_LOCAL]) - { - addr = RTA_DATA (tb[IFA_LOCAL]); - if (tb[IFA_ADDRESS]) - broad = RTA_DATA (tb[IFA_ADDRESS]); - else - broad = NULL; - } - else - { - if (tb[IFA_ADDRESS]) - addr = RTA_DATA (tb[IFA_ADDRESS]); - else - addr = NULL; - } - } - else - { + zlog_info (" IFA_LOCAL %s", inet_ntop (ifa->ifa_family, + RTA_DATA (tb[IFA_LOCAL]), buf, BUFSIZ)); if (tb[IFA_ADDRESS]) - addr = RTA_DATA (tb[IFA_ADDRESS]); - else - addr = NULL; - + zlog_info (" IFA_ADDRESS %s", inet_ntop (ifa->ifa_family, + RTA_DATA (tb[IFA_ADDRESS]), buf, BUFSIZ)); if (tb[IFA_BROADCAST]) - broad = RTA_DATA(tb[IFA_BROADCAST]); - else - broad = NULL; + zlog_info (" IFA_BROADCAST %s", inet_ntop (ifa->ifa_family, + RTA_DATA (tb[IFA_BROADCAST]), buf, BUFSIZ)); + if (tb[IFA_LABEL] && strcmp (ifp->name, RTA_DATA (tb[IFA_LABEL]))) + zlog_info (" IFA_LABEL %s", RTA_DATA (tb[IFA_LABEL])); } + /* peer or broadcast network? */ + if (ifa->ifa_family == AF_INET) + peeronly = if_is_pointopoint (ifp) || + ifa->ifa_prefixlen >= IPV4_MAX_PREFIXLEN - 1; +#ifdef HAVE_IPV6 + if (ifa->ifa_family == AF_INET6) { + peeronly = if_is_pointopoint (ifp) || + ifa->ifa_prefixlen >= IPV6_MAX_PREFIXLEN - 1; + } +#endif /* HAVE_IPV6*/ + if (!(tb[IFA_LOCAL] && tb[IFA_ADDRESS])) { + /* FIXME: IPv6 Appears to have only IFA_ADDRESS */ + peeronly=0; + } + + /* network. prefixlen applies to IFA_ADDRESS rather than IFA_LOCAL */ + if (tb[IFA_ADDRESS] && !peeronly) + addr = RTA_DATA (tb[IFA_ADDRESS]); + else if (tb[IFA_LOCAL]) + addr = RTA_DATA (tb[IFA_LOCAL]); + else + addr = NULL; + + /* broadcast/peer */ + if (tb[IFA_BROADCAST]) + broad = RTA_DATA (tb[IFA_BROADCAST]); + else if (tb[IFA_ADDRESS] && peeronly) + broad = RTA_DATA (tb[IFA_ADDRESS]); /* peer address specified */ + else + broad = NULL; + /* Flags. */ if (ifa->ifa_flags & IFA_F_SECONDARY) SET_FLAG (flags, ZEBRA_IFA_SECONDARY); @@ -787,16 +878,16 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h) ifp->mtu = *(int *)RTA_DATA (tb[IFLA_MTU]); ifp->metric = 1; - if (if_is_up (ifp)) + if (if_is_operative (ifp)) { ifp->flags = ifi->ifi_flags & 0x0000fffff; - if (! if_is_up (ifp)) + if (! if_is_operative (ifp)) if_down (ifp); } else { ifp->flags = ifi->ifi_flags & 0x0000fffff; - if (if_is_up (ifp)) + if (if_is_operative (ifp)) if_up (ifp); } } @@ -854,7 +945,19 @@ int interface_lookup_netlink () { int ret; - + int flags; + int snb_ret; + + /* + * Change netlink socket flags to blocking to ensure we get + * a reply via nelink_parse_info + */ + snb_ret = set_netlink_blocking(&netlink_cmd, &flags); + if(snb_ret < 0) + zlog (NULL, LOG_WARNING, + "%s:%i Warning: Could not set netlink socket to blocking.", + __FUNCTION__, __LINE__); + /* Get interface information. */ ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd); if (ret < 0) @@ -881,6 +984,9 @@ interface_lookup_netlink () return ret; #endif /* HAVE_IPV6 */ + /* restore socket flags */ + if(snb_ret == 0) + set_netlink_nonblocking(&netlink_cmd, &flags); return 0; } @@ -890,7 +996,19 @@ int netlink_route_read () { int ret; - + int flags; + int snb_ret; + + /* + * Change netlink socket flags to blocking to ensure we get + * a reply via nelink_parse_info + */ + snb_ret = set_netlink_blocking(&netlink_cmd, &flags); + if(snb_ret < 0) + zlog (NULL, LOG_WARNING, + "%s:%i Warning: Could not set netlink socket to blocking.", + __FUNCTION__, __LINE__); + /* Get IPv4 routing table. */ ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd); if (ret < 0) @@ -909,6 +1027,9 @@ netlink_route_read () return ret; #endif /* HAVE_IPV6 */ + /* restore flags */ + if(snb_ret == 0) + set_netlink_nonblocking(&netlink_cmd, &flags); return 0; } @@ -992,6 +1113,7 @@ netlink_talk (struct nlmsghdr *n, struct nlsock *nl) struct iovec iov = { (void*) n, n->nlmsg_len }; struct msghdr msg = {(void*) &snl, sizeof snl, &iov, 1, NULL, 0, 0}; int flags = 0; + int snb_ret; memset (&snl, 0, sizeof snl); snl.nl_family = AF_NETLINK; @@ -1007,7 +1129,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", @@ -1019,17 +1146,11 @@ netlink_talk (struct nlmsghdr *n, struct nlsock *nl) * Change socket flags for blocking I/O. * This ensures we wait for a reply in netlink_parse_info(). */ - if((flags = fcntl(nl->sock, F_GETFL, 0)) < 0) - { - zlog (NULL, LOG_ERR, "%s:%i F_GETFL error: %s", - __FUNCTION__, __LINE__, strerror (errno)); - } - flags &= ~O_NONBLOCK; - if(fcntl(nl->sock, F_SETFL, flags) < 0) - { - zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s", - __FUNCTION__, __LINE__, strerror (errno)); - } + snb_ret = set_netlink_blocking(nl, &flags); + if(snb_ret < 0) + zlog (NULL, LOG_WARNING, + "%s:%i Warning: Could not set netlink socket to blocking.", + __FUNCTION__, __LINE__); /* * Get reply from netlink socket. @@ -1038,12 +1159,8 @@ netlink_talk (struct nlmsghdr *n, struct nlsock *nl) status = netlink_parse_info (netlink_talk_filter, nl); /* Restore socket flags for nonblocking I/O */ - flags |= O_NONBLOCK; - if(fcntl(nl->sock, F_SETFL, flags) < 0) - { - zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s", - __FUNCTION__, __LINE__, strerror (errno)); - } + if(snb_ret == 0) + set_netlink_nonblocking(nl, &flags); return status; } @@ -1448,7 +1565,6 @@ kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc) return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc); } -#include "thread.h" extern struct thread_master *master; diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index fe88be81..363363f7 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, @@ -188,13 +191,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 @@ -422,13 +441,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. */ @@ -436,6 +471,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 4d244197..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. */ @@ -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 aa1c8342..0508f905 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. */ @@ -195,6 +198,7 @@ zsend_interface_add (struct zserv *client, struct interface *ifp) /* Interface information. */ stream_put (s, ifp->name, INTERFACE_NAMSIZ); stream_putl (s, ifp->ifindex); + stream_putc (s, ifp->status); stream_putl (s, ifp->flags); stream_putl (s, ifp->metric); stream_putl (s, ifp->mtu); @@ -235,6 +239,7 @@ zsend_interface_delete (struct zserv *client, struct interface *ifp) stream_putc (s, ZEBRA_INTERFACE_DELETE); stream_put (s, ifp->name, INTERFACE_NAMSIZ); stream_putl (s, ifp->ifindex); + stream_putc (s, ifp->status); stream_putl (s, ifp->flags); stream_putl (s, ifp->metric); stream_putl (s, ifp->mtu); @@ -363,6 +368,7 @@ zsend_interface_up (struct zserv *client, struct interface *ifp) /* Interface information. */ stream_put (s, ifp->name, INTERFACE_NAMSIZ); stream_putl (s, ifp->ifindex); + stream_putc (s, ifp->status); stream_putl (s, ifp->flags); stream_putl (s, ifp->metric); stream_putl (s, ifp->mtu); @@ -397,6 +403,7 @@ zsend_interface_down (struct zserv *client, struct interface *ifp) /* Interface information. */ stream_put (s, ifp->name, INTERFACE_NAMSIZ); stream_putl (s, ifp->ifindex); + stream_putc (s, ifp->status); stream_putl (s, ifp->flags); stream_putl (s, ifp->metric); stream_putl (s, ifp->mtu); @@ -1622,6 +1629,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) @@ -1631,6 +1641,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) |