]> git.ipfire.org Git - thirdparty/lldpd.git/commitdiff
More privilege separation
authorVincent Bernat <bernat@luffy.cx>
Sat, 15 Nov 2008 07:42:35 +0000 (08:42 +0100)
committerVincent Bernat <bernat@luffy.cx>
Sat, 15 Nov 2008 07:42:35 +0000 (08:42 +0100)
src/lldpd.c
src/lldpd.h
src/priv.c

index f995465afa94b860d53b0fa818bc9d67624259d1..a235d0566e8aac9984c9b44f2093738b4f30a8aa 100644 (file)
@@ -50,7 +50,6 @@ void           usage(void);
 int                     lldpd_iface_init(struct lldpd *, struct lldpd_hardware *);
 int                     lldpd_iface_init_vlan(struct lldpd *, struct lldpd_vif *);
 void                    lldpd_iface_init_mtu(struct lldpd *, struct lldpd_hardware *);
-int                     lldpd_iface_init_socket(struct lldpd *, struct lldpd_hardware *);
 int                     lldpd_iface_close(struct lldpd *, struct lldpd_hardware *);
 void                    lldpd_iface_multicast(struct lldpd *, const char *, int);
 
@@ -182,25 +181,6 @@ lldpd_iface_init_mtu(struct lldpd *global, struct lldpd_hardware *hardware)
                hardware->h_mtu = ifr.ifr_mtu;
 }
 
-int
-lldpd_iface_init_socket(struct lldpd *global, struct lldpd_hardware *hardware)
-{
-       struct sockaddr_ll sa;
-
-       /* Open listening socket to receive/send frames */
-       if ((hardware->h_raw = socket(PF_PACKET, SOCK_RAW,
-                   htons(ETH_P_ALL))) < 0)
-               return errno;
-       memset(&sa, 0, sizeof(sa));
-       sa.sll_family = AF_PACKET;
-       sa.sll_protocol = 0;
-       sa.sll_ifindex = if_nametoindex(hardware->h_ifname);
-       if (bind(hardware->h_raw, (struct sockaddr*)&sa, sizeof(sa)) < 0)
-               return errno;
-
-       return 0;
-}
-
 int
 lldpd_iface_init_vlan(struct lldpd *global, struct lldpd_vif *vif)
 {
@@ -208,7 +188,7 @@ lldpd_iface_init_vlan(struct lldpd *global, struct lldpd_vif *vif)
        short int filter;
 
        lldpd_iface_init_mtu(global, (struct lldpd_hardware*)vif);
-       status = lldpd_iface_init_socket(global, (struct lldpd_hardware*)vif);
+       status = priv_iface_init((struct lldpd_hardware*)vif, -1);
        if (status != 0)
                return status;
 
@@ -233,15 +213,13 @@ lldpd_iface_init_vlan(struct lldpd *global, struct lldpd_vif *vif)
 int
 lldpd_iface_init(struct lldpd *global, struct lldpd_hardware *hardware)
 {
-       struct sockaddr_ll sa;
        int master;             /* Bond device */
        char if_bond[IFNAMSIZ];
-       int un = 1;
        int status;
        short int filter;
 
        lldpd_iface_init_mtu(global, hardware);
-       status = lldpd_iface_init_socket(global, hardware);
+       status = priv_iface_init(hardware, -1);
        if (status != 0)
                return status;
 
@@ -255,25 +233,13 @@ lldpd_iface_init(struct lldpd *global, struct lldpd_hardware *hardware)
                hardware->h_raw_real = hardware->h_raw;
                hardware->h_master = master;
                hardware->h_raw = -1;
-               if ((hardware->h_raw = socket(PF_PACKET, SOCK_RAW,
-                           htons(ETH_P_ALL))) < 0)
-                       return errno;
-               memset(&sa, 0, sizeof(sa));
-               sa.sll_family = AF_PACKET;
-               sa.sll_protocol = 0;
-               sa.sll_ifindex = master;
-               if (bind(hardware->h_raw, (struct sockaddr*)&sa,
-                       sizeof(sa)) < 0)
-                       return errno;
-               /* With bonding, we need to listen to bond device. We use
-                * setsockopt() PACKET_ORIGDEV to get physical device instead of
-                * bond device */
-               if (setsockopt(hardware->h_raw, SOL_PACKET,
-                       PACKET_ORIGDEV, &un, sizeof(un)) == -1) {
-                       LLOG_WARN("unable to setsockopt for master bonding device of %s. "
-                            "You will get inaccurate results",
-                           hardware->h_ifname);
-                }
+               status = priv_iface_init(hardware, master);
+               if (status != 0) {
+                       close(hardware->h_raw_real);
+                       if (hardware->h_raw != -1)
+                               close(hardware->h_raw);
+                       return status;
+               }
        }
 
        if (global->g_multi)
@@ -297,23 +263,18 @@ lldpd_iface_init(struct lldpd *global, struct lldpd_hardware *hardware)
 void
 lldpd_iface_multicast(struct lldpd *global, const char *name, int remove)
 {
-       struct ifreq ifr;
-       int i;
-
+       int i, rc;
+       
        for (i=0; global->g_protocols[i].mode != 0; i++) {
                if (!global->g_protocols[i].enabled) continue;
-               memset(&ifr, 0, sizeof(ifr));
-               strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
-               memcpy(ifr.ifr_hwaddr.sa_data,
-                   global->g_protocols[i].mac, ETH_ALEN);
-               if (ioctl(global->g_sock, (remove)?SIOCDELMULTI:SIOCADDMULTI,
-                       &ifr) < 0) {
-                       if (errno == ENOENT)
-                               return;
-                       LLOG_INFO("unable to %s %s address to multicast filter for %s",
-                           (remove)?"delete":"add",
-                           global->g_protocols[i].name,
-                           name);
+               if ((rc = priv_iface_multicast(name,
+                           global->g_protocols[i].mac, !remove)) != 0) {
+                       errno = rc;
+                       if (errno != ENOENT)
+                               LLOG_INFO("unable to %s %s address to multicast filter for %s",
+                                   (remove)?"delete":"add",
+                                   global->g_protocols[i].name,
+                                   name);
                }
        }
 }
index 6156822b1a0acbf517fab8d531ef3e53264ef3fb..61614ccd7f89956aa4d8024d81cc1640a4d6c18e 100644 (file)
@@ -328,13 +328,15 @@ void       client_handle_shutdown(struct lldpd *, struct hmsg *,
            struct hmsg *);
 
 /* priv.c */
-void            priv_init();
-void            priv_fork();
-int             priv_ctl_create();
-void            priv_ctl_cleanup();
-char           *priv_gethostbyname();
-int             priv_open(char*);
-int             priv_ethtool(char*, struct ethtool_cmd*);
+void    priv_init();
+void    priv_fork();
+int     priv_ctl_create();
+void    priv_ctl_cleanup();
+char           *priv_gethostbyname();
+int             priv_open(char*);
+int             priv_ethtool(char*, struct ethtool_cmd*);
+int             priv_iface_init(struct lldpd_hardware *, int);
+int     priv_iface_multicast(char *, u_int8_t *, int);
 
 /* privsep_fdpass.c */
 int     receive_fd(int);
index fd26a8fa6e2fcdab2ebf2b8b9b4c6a76109d81d6..f4a01e3620ee0b4cad077c114ba863edf1c34cd5 100644 (file)
@@ -34,6 +34,7 @@
 #include <sys/ioctl.h>
 #include <netdb.h>
 #include <linux/sockios.h>
+#include <netpacket/packet.h>
 
 enum {
        PRIV_FORK,
@@ -42,6 +43,8 @@ enum {
        PRIV_GET_HOSTNAME,
        PRIV_OPEN,
        PRIV_ETHTOOL,
+       PRIV_IFACE_INIT,
+       PRIV_IFACE_MULTICAST,
 };
 
 static int may_read(int, void *, size_t);
@@ -50,6 +53,7 @@ static void must_write(int, void *, size_t);
 
 int remote;                    /* Other side */
 int monitored = -1;            /* Child */
+int sock = -1;
 
 /* Proxies */
 
@@ -135,6 +139,34 @@ priv_ethtool(char *ifname, struct ethtool_cmd *ethc)
        return rc;
 }
 
+int
+priv_iface_init(struct lldpd_hardware *hardware, int master)
+{
+       int cmd, rc;
+       cmd = PRIV_IFACE_INIT;
+       must_write(remote, &cmd, sizeof(int));
+       must_write(remote, &master, sizeof(int));
+       must_write(remote, hardware->h_ifname, IFNAMSIZ);
+       must_read(remote, &rc, sizeof(int));
+       if (rc != 0)
+               return rc;      /* It's errno */
+       hardware->h_raw = receive_fd(remote);
+       return 0;
+}
+
+int
+priv_iface_multicast(char *name, u_int8_t *mac, int add)
+{
+       int cmd, rc;
+       cmd = PRIV_IFACE_MULTICAST;
+       must_write(remote, &cmd, sizeof(cmd));
+       must_write(remote, name, IFNAMSIZ);
+       must_write(remote, mac, ETH_ALEN);
+       must_write(remote, &add, sizeof(int));
+       must_read(remote, &rc, sizeof(int));
+       return rc;
+}
+
 void
 asroot_fork()
 {
@@ -240,7 +272,7 @@ asroot_ethtool()
 {
        struct ifreq ifr;
        struct ethtool_cmd ethc;
-       int len, rc, sock;
+       int len, rc;
        char *ifname;
 
        memset(&ifr, 0, sizeof(ifr));
@@ -252,12 +284,6 @@ asroot_ethtool()
        strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
        ifr.ifr_data = (caddr_t)&ethc;
        ethc.cmd = ETHTOOL_GSET;
-       if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
-               LLOG_WARN("[priv]: unable to get a socket");
-               must_write(remote, &sock, sizeof(int));
-               free(ifname);
-               return;
-       }
        if ((rc = ioctl(sock, SIOCETHTOOL, &ifr)) != 0) {
                LLOG_WARN("[priv]: unable to ioctl ETHTOOL for %s", ifname);
                must_write(remote, &rc, sizeof(int));
@@ -265,11 +291,76 @@ asroot_ethtool()
                close(sock);
                return;
        }
-       close(sock);
        must_write(remote, &rc, sizeof(int));
        must_write(remote, &ethc, sizeof(struct ethtool_cmd));
 }
 
+void
+asroot_iface_init()
+{
+       struct sockaddr_ll sa;
+       int un = 1;
+       int s, master;
+       char ifname[IFNAMSIZ];
+
+       must_read(remote, &master, sizeof(int));
+       must_read(remote, ifname, IFNAMSIZ);
+
+       /* Open listening socket to receive/send frames */
+       if ((s = socket(PF_PACKET, SOCK_RAW,
+                   htons(ETH_P_ALL))) < 0) {
+               must_write(remote, &errno, sizeof(errno));
+               return;
+       }
+       memset(&sa, 0, sizeof(sa));
+       sa.sll_family = AF_PACKET;
+       sa.sll_protocol = 0;
+       if (master == -1)
+               sa.sll_ifindex = if_nametoindex(ifname);
+       else
+               sa.sll_ifindex = master;
+       if (bind(s, (struct sockaddr*)&sa, sizeof(sa)) < 0) {
+               must_write(remote, &errno, sizeof(errno));
+               close(s);
+               return;
+       }
+
+       if (master != -1) {
+               /* With bonding, we need to listen to bond device. We use
+                * setsockopt() PACKET_ORIGDEV to get physical device instead of
+                * bond device */
+               if (setsockopt(s, SOL_PACKET,
+                       PACKET_ORIGDEV, &un, sizeof(un)) == -1) {
+                       LLOG_WARN("[priv]: unable to setsockopt for master bonding device of %s. "
+                            "You will get inaccurate results",
+                           ifname);
+                }
+       }
+       errno = 0;
+       must_write(remote, &errno, sizeof(errno));
+       send_fd(remote, s);
+       close(s);
+}
+
+void
+asroot_iface_multicast()
+{
+       int add, rc = 0;
+       struct ifreq ifr;
+       memset(&ifr, 0, sizeof(ifr));
+       must_read(remote, ifr.ifr_name, IFNAMSIZ);
+       must_read(remote, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+       must_read(remote, &add, sizeof(int));
+
+       if (ioctl(sock, (add)?SIOCADDMULTI:SIOCDELMULTI,
+               &ifr) < 0) {
+               must_write(remote, &errno, sizeof(errno));
+               return;
+               }
+       
+       must_write(remote, &rc, sizeof(rc));
+}
+
 struct dispatch_actions {
        int                             msg;
        void(*function)(void);
@@ -282,6 +373,8 @@ struct dispatch_actions actions[] = {
        {PRIV_GET_HOSTNAME, asroot_gethostbyname},
        {PRIV_OPEN, asroot_open},
        {PRIV_ETHTOOL, asroot_ethtool},
+       {PRIV_IFACE_INIT, asroot_iface_init},
+       {PRIV_IFACE_MULTICAST, asroot_iface_multicast},
        {-1, NULL}
 };
 
@@ -390,6 +483,9 @@ priv_init()
                close(pair[0]);
                if (atexit(priv_exit) != 0)
                        fatal("[priv]: unable to set exit function");
+               if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+                       fatal("[priv]: unable to get a socket");
+               }
 
                signal(SIGALRM, sig_pass_to_chld);
                signal(SIGTERM, sig_pass_to_chld);