]> git.proxmox.com Git - mirror_frr.git/blobdiff - zebra/if_ioctl_solaris.c
*: use frr_elevate_privs() (1/2: coccinelle)
[mirror_frr.git] / zebra / if_ioctl_solaris.c
index dbc4109913819c7f23492152635498a2d1f0cb8f..ee7f22e780cd2389b60c93ee25de574cae553e1d 100644 (file)
  * 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.  
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
 #include <zebra.h>
 
+#ifdef SUNOS_5
+
 #include "if.h"
 #include "sockunion.h"
 #include "prefix.h"
 #include "privs.h"
 #include "vrf.h"
 #include "vty.h"
+#include "lib_errors.h"
 
 #include "zebra/interface.h"
 #include "zebra/ioctl_solaris.h"
 #include "zebra/rib.h"
 
-static int if_get_addr (struct interface *, struct sockaddr *, const char *);
-static void interface_info_ioctl (struct interface *);
+static int if_get_addr(struct interface *, struct sockaddr *, const char *);
+static void interface_info_ioctl(struct interface *);
 extern struct zebra_privs_t zserv_privs;
 
-static int
-interface_list_ioctl (int af)
+static int interface_list_ioctl(int af)
 {
-  int ret;
-  int sock;
+       int ret;
+       int sock;
 #define IFNUM_BASE 32
-  struct lifnum lifn;
-  int ifnum;
-  struct lifreq *lifreq;
-  struct lifconf lifconf;
-  struct interface *ifp;
-  int n;
-  int save_errno;
-  size_t needed, lastneeded = 0;
-  char *buf = NULL;
-
-  if (zserv_privs.change(ZPRIVS_RAISE))
-    zlog_err("Can't raise privileges");
-  
-  sock = socket (af, SOCK_DGRAM, 0);
-  if (sock < 0)
-    {
-      zlog_warn ("Can't make %s socket stream: %s",
-                 (af == AF_INET ? "AF_INET" : "AF_INET6"), safe_strerror (errno));
-                 
-      if (zserv_privs.change(ZPRIVS_LOWER))
-        zlog_err("Can't lower privileges");
-        
-      return -1;
-    }
-
-calculate_lifc_len:     /* must hold privileges to enter here */
-  lifn.lifn_family = af;
-  lifn.lifn_flags = LIFC_NOXMIT; /* we want NOXMIT interfaces too */
-  ret = ioctl (sock, SIOCGLIFNUM, &lifn);
-  save_errno = errno;
-  
-  if (zserv_privs.change(ZPRIVS_LOWER))
-    zlog_err("Can't lower privileges");
-  if (ret < 0)
-    {
-      zlog_warn ("interface_list_ioctl: SIOCGLIFNUM failed %s",
-                 safe_strerror (save_errno));
-      close (sock);
-      return -1;
-    }
-  ifnum = lifn.lifn_count;
-
-  /*
-   * When calculating the buffer size needed, add a small number
-   * of interfaces to those we counted.  We do this to capture
-   * the interface status of potential interfaces which may have
-   * been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF.
-   */
-  needed = (ifnum + 4) * sizeof (struct lifreq);
-  if (needed > lastneeded || needed < lastneeded / 2)
-    {
-      if (buf != NULL)
-        XFREE (MTYPE_TMP, buf);
-      if ((buf = XMALLOC (MTYPE_TMP, needed)) == NULL)
-        {
-          zlog_warn ("interface_list_ioctl: malloc failed");
-          close (sock);
-          return -1;
-        }
-    }
-  lastneeded = needed;
-
-  lifconf.lifc_family = af;
-  lifconf.lifc_flags = LIFC_NOXMIT;
-  lifconf.lifc_len = needed;
-  lifconf.lifc_buf = buf;
-
-  if (zserv_privs.change(ZPRIVS_RAISE))
-    zlog_err("Can't raise privileges");
-    
-  ret = ioctl (sock, SIOCGLIFCONF, &lifconf);
-
-  if (ret < 0)
-    {
-      if (errno == EINVAL)
-        goto calculate_lifc_len; /* deliberately hold privileges */
-
-      zlog_warn ("SIOCGLIFCONF: %s", safe_strerror (errno));
-
-      if (zserv_privs.change(ZPRIVS_LOWER))
-        zlog_err("Can't lower privileges");
-
-      goto end;
-    }
-
-  if (zserv_privs.change(ZPRIVS_LOWER))
-    zlog_err("Can't lower privileges");
-    
-  /* Allocate interface. */
-  lifreq = lifconf.lifc_req;
-
-  for (n = 0; n < lifconf.lifc_len; n += sizeof (struct lifreq))
-    {
-      /* we treat Solaris logical interfaces as addresses, because that is
-       * how PF_ROUTE on Solaris treats them. Hence we can not directly use
-       * the lifreq_name to get the ifp.  We need to normalise the name
-       * before attempting get.
-       *
-       * Solaris logical interface names are in the form of:
-       * <interface name>:<logical interface id>
-       */
-      unsigned int normallen = 0;
-      uint64_t lifflags;
-      
-      /* We should exclude ~IFF_UP interfaces, as we'll find out about them
-       * coming up later through RTM_NEWADDR message on the route socket.
-       */
-      if (if_get_flags_direct (lifreq->lifr_name, &lifflags,
-                           lifreq->lifr_addr.ss_family)
-          || !CHECK_FLAG (lifflags, IFF_UP))
-        {
-          lifreq++;
-          continue;
-        }
-      
-      /* Find the normalised name */
-      while ( (normallen < sizeof(lifreq->lifr_name))
-             && ( *(lifreq->lifr_name + normallen) != '\0')
-             && ( *(lifreq->lifr_name + normallen) != ':') )
-        normallen++;
-      
-      ifp = if_get_by_name_len(lifreq->lifr_name, normallen, VRF_DEFAULT, 0);
-
-      if (lifreq->lifr_addr.ss_family == AF_INET)
-        ifp->flags |= IFF_IPV4;
-
-      if (lifreq->lifr_addr.ss_family == AF_INET6)
-        {
-          ifp->flags |= IFF_IPV6;
-        }
-        
-      if_add_update (ifp);
-
-      interface_info_ioctl (ifp);
-      
-      /* If a logical interface pass the full name so it can be
-       * as a label on the address
-       */
-      if ( *(lifreq->lifr_name + normallen) != '\0')
-        if_get_addr (ifp, (struct sockaddr *) &lifreq->lifr_addr,
-                     lifreq->lifr_name);
-      else
-        if_get_addr (ifp, (struct sockaddr *) &lifreq->lifr_addr, NULL);
-        
-      /* Poke the interface flags. Lets IFF_UP mangling kick in */
-      if_flags_update (ifp, ifp->flags);
-      
-      lifreq++;
-    }
+       struct lifnum lifn;
+       int ifnum;
+       struct lifreq *lifreq;
+       struct lifconf lifconf;
+       struct interface *ifp;
+       int n;
+       int save_errno;
+       size_t needed, lastneeded = 0;
+       char *buf = NULL;
+
+       frr_elevate_privs(&zserv_privs) {
+
+               sock = socket(af, SOCK_DGRAM, 0);
+               if (sock < 0) {
+                       zlog_warn("Can't make %s socket stream: %s",
+                                 (af == AF_INET ? "AF_INET" : "AF_INET6"),
+                                 safe_strerror(errno));
+
+                       return -1;
+               }
+
+calculate_lifc_len: /* must hold privileges to enter here */
+               lifn.lifn_family = af;
+               lifn.lifn_flags = LIFC_NOXMIT; /* we want NOXMIT interfaces too */
+               ret = ioctl(sock, SIOCGLIFNUM, &lifn);
+               save_errno = errno;
+
+       }
+
+       if (ret < 0) {
+               zlog_warn("interface_list_ioctl: SIOCGLIFNUM failed %s",
+                         safe_strerror(save_errno));
+               close(sock);
+               return -1;
+       }
+       ifnum = lifn.lifn_count;
+
+       /*
+        * When calculating the buffer size needed, add a small number
+        * of interfaces to those we counted.  We do this to capture
+        * the interface status of potential interfaces which may have
+        * been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF.
+        */
+       needed = (ifnum + 4) * sizeof(struct lifreq);
+       if (needed > lastneeded || needed < lastneeded / 2) {
+               if (buf != NULL)
+                       XFREE(MTYPE_TMP, buf);
+               buf = XMALLOC(MTYPE_TMP, needed);
+       }
+       lastneeded = needed;
+
+       lifconf.lifc_family = af;
+       lifconf.lifc_flags = LIFC_NOXMIT;
+       lifconf.lifc_len = needed;
+       lifconf.lifc_buf = buf;
+
+       if (zserv_privs.change(ZPRIVS_RAISE))
+               flog_err(LIB_ERR_PRIVILEGES, "Can't raise privileges");
+
+       ret = ioctl(sock, SIOCGLIFCONF, &lifconf);
+
+       if (ret < 0) {
+               if (errno == EINVAL)
+                       goto calculate_lifc_len; /* deliberately hold privileges
+                                                   */
+
+               zlog_warn("SIOCGLIFCONF: %s", safe_strerror(errno));
+
+               if (zserv_privs.change(ZPRIVS_LOWER))
+                       flog_err(LIB_ERR_PRIVILEGES, "Can't lower privileges");
+
+               goto end;
+       }
+
+       if (zserv_privs.change(ZPRIVS_LOWER))
+               flog_err(LIB_ERR_PRIVILEGES, "Can't lower privileges");
+
+       /* Allocate interface. */
+       lifreq = lifconf.lifc_req;
+
+       for (n = 0; n < lifconf.lifc_len; n += sizeof(struct lifreq)) {
+               /* we treat Solaris logical interfaces as addresses, because
+                * that is
+                * how PF_ROUTE on Solaris treats them. Hence we can not
+                * directly use
+                * the lifreq_name to get the ifp.  We need to normalise the
+                * name
+                * before attempting get.
+                *
+                * Solaris logical interface names are in the form of:
+                * <interface name>:<logical interface id>
+                */
+               unsigned int normallen = 0;
+               uint64_t lifflags;
+
+               /* We should exclude ~IFF_UP interfaces, as we'll find out about
+                * them
+                * coming up later through RTM_NEWADDR message on the route
+                * socket.
+                */
+               if (if_get_flags_direct(lifreq->lifr_name, &lifflags,
+                                       lifreq->lifr_addr.ss_family)
+                   || !CHECK_FLAG(lifflags, IFF_UP)) {
+                       lifreq++;
+                       continue;
+               }
+
+               /* Find the normalised name */
+               while ((normallen < sizeof(lifreq->lifr_name))
+                      && (*(lifreq->lifr_name + normallen) != '\0')
+                      && (*(lifreq->lifr_name + normallen) != ':'))
+                       normallen++;
+
+               ifp = if_get_by_name(lifreq->lifr_name, VRF_DEFAULT, 0);
+
+               if (lifreq->lifr_addr.ss_family == AF_INET)
+                       ifp->flags |= IFF_IPV4;
+
+               if (lifreq->lifr_addr.ss_family == AF_INET6) {
+                       ifp->flags |= IFF_IPV6;
+               }
+
+               if_add_update(ifp);
+
+               interface_info_ioctl(ifp);
+
+               /* If a logical interface pass the full name so it can be
+                * as a label on the address
+                */
+               if (*(lifreq->lifr_name + normallen) != '\0')
+                       if_get_addr(ifp, (struct sockaddr *)&lifreq->lifr_addr,
+                                   lifreq->lifr_name);
+               else
+                       if_get_addr(ifp, (struct sockaddr *)&lifreq->lifr_addr,
+                                   NULL);
+
+               /* Poke the interface flags. Lets IFF_UP mangling kick in */
+               if_flags_update(ifp, ifp->flags);
+
+               lifreq++;
+       }
 
 end:
-  close (sock);
-  XFREE (MTYPE_TMP, lifconf.lifc_buf);
-  return ret;
+       close(sock);
+       XFREE(MTYPE_TMP, lifconf.lifc_buf);
+       return ret;
 }
 
 /* Get interface's index by ioctl. */
-static int
-if_get_index (struct interface *ifp)
+static int if_get_index(struct interface *ifp)
 {
-  int ret;
-  struct lifreq lifreq;
+       int ret;
+       struct lifreq lifreq;
 
-  lifreq_set_name (&lifreq, ifp->name);
+       lifreq_set_name(&lifreq, ifp->name);
 
-  if (ifp->flags & IFF_IPV4)
-    ret = AF_IOCTL (AF_INET, SIOCGLIFINDEX, (caddr_t) & lifreq);
-  else if (ifp->flags & IFF_IPV6)
-    ret = AF_IOCTL (AF_INET6, SIOCGLIFINDEX, (caddr_t) & lifreq);
-  else
-    ret = -1;
+       if (ifp->flags & IFF_IPV4)
+               ret = AF_IOCTL(AF_INET, SIOCGLIFINDEX, (caddr_t)&lifreq);
+       else if (ifp->flags & IFF_IPV6)
+               ret = AF_IOCTL(AF_INET6, SIOCGLIFINDEX, (caddr_t)&lifreq);
+       else
+               ret = -1;
 
-  if (ret < 0)
-    {
-      zlog_warn ("SIOCGLIFINDEX(%s) failed", ifp->name);
-      return ret;
-    }
+       if (ret < 0) {
+               zlog_warn("SIOCGLIFINDEX(%s) failed", ifp->name);
+               return ret;
+       }
 
-  /* OK we got interface index. */
+/* OK we got interface index. */
 #ifdef ifr_ifindex
-  ifp->ifindex = lifreq.lifr_ifindex;
+       if_set_index(ifp, lifreq.lifr_ifindex);
 #else
-  ifp->ifindex = lifreq.lifr_index;
+       if_set_index(ifp, lifreq.lifr_index);
 #endif
-  return ifp->ifindex;
-
+       return ifp->ifindex;
 }
 
 
 /* Interface address lookup by ioctl.  This function only looks up
    IPv4 address. */
-#define ADDRLEN(sa) (((sa)->sa_family == AF_INET ?  \
-                sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6)))
+#define ADDRLEN(sa)                                                            \
+       (((sa)->sa_family == AF_INET ? sizeof(struct sockaddr_in)              \
+                                    : sizeof(struct sockaddr_in6)))
 
 #define SIN(s) ((struct sockaddr_in *)(s))
 #define SIN6(s) ((struct sockaddr_in6 *)(s))
 
 /* Retrieve address information for the given ifp */
-static int
-if_get_addr (struct interface *ifp, struct sockaddr *addr, const char *label)
+static int if_get_addr(struct interface *ifp, struct sockaddr *addr,
+                      const char *label)
 {
-  int ret;
-  struct lifreq lifreq;
-  struct sockaddr_storage mask, dest;
-  char *dest_pnt = NULL;
-  u_char prefixlen = 0;
-  afi_t af;
-  int flags = 0;
-
-  /* Interface's name and address family.
-   * We need to use the logical interface name / label, if we've been
-   * given one, in order to get the right address
-   */
-  strncpy (lifreq.lifr_name, (label ? label : ifp->name), IFNAMSIZ);
-
-  /* Interface's address. */
-  memcpy (&lifreq.lifr_addr, addr, ADDRLEN (addr));
-  af = addr->sa_family;
-
-  /* Point to point or broad cast address pointer init. */
-  dest_pnt = NULL;
-
-  if (AF_IOCTL (af, SIOCGLIFDSTADDR, (caddr_t) & lifreq) >= 0)
-    {
-      memcpy (&dest, &lifreq.lifr_dstaddr, ADDRLEN (addr));
-      if (af == AF_INET)
-        dest_pnt = (char *) &(SIN (&dest)->sin_addr);
-      else
-        dest_pnt = (char *) &(SIN6 (&dest)->sin6_addr);
-      flags = ZEBRA_IFA_PEER;
-    }
-
-  if (af == AF_INET)
-    {
-      ret = if_ioctl (SIOCGLIFNETMASK, (caddr_t) & lifreq);
-      
-      if (ret < 0)
-        {
-          if (errno != EADDRNOTAVAIL)
-            {
-              zlog_warn ("SIOCGLIFNETMASK (%s) fail: %s", ifp->name,
-                         safe_strerror (errno));
-              return ret;
-            }
-          return 0;
-        }
-      memcpy (&mask, &lifreq.lifr_addr, ADDRLEN (addr));
-
-      prefixlen = ip_masklen (SIN (&mask)->sin_addr);
-      if (!dest_pnt && (if_ioctl (SIOCGLIFBRDADDR, (caddr_t) & lifreq) >= 0))
-       {
-          memcpy (&dest, &lifreq.lifr_broadaddr, sizeof (struct sockaddr_in));
-          dest_pnt = (char *) &SIN (&dest)->sin_addr;
-        }
-    }
-  else if (af == AF_INET6)
-    {
-      if (if_ioctl_ipv6 (SIOCGLIFSUBNET, (caddr_t) & lifreq) < 0)
-       {
-         if (ifp->flags & IFF_POINTOPOINT)
-           prefixlen = IPV6_MAX_BITLEN;
-         else
-           zlog_warn ("SIOCGLIFSUBNET (%s) fail: %s",
-                      ifp->name, safe_strerror (errno));
+       int ret;
+       struct lifreq lifreq;
+       struct sockaddr_storage mask, dest;
+       char *dest_pnt = NULL;
+       uint8_t prefixlen = 0;
+       afi_t af;
+       int flags = 0;
+
+       /* Interface's name and address family.
+        * We need to use the logical interface name / label, if we've been
+        * given one, in order to get the right address
+        */
+       strncpy(lifreq.lifr_name, (label ? label : ifp->name), IFNAMSIZ);
+
+       /* Interface's address. */
+       memcpy(&lifreq.lifr_addr, addr, ADDRLEN(addr));
+       af = addr->sa_family;
+
+       /* Point to point or broad cast address pointer init. */
+       dest_pnt = NULL;
+
+       if (AF_IOCTL(af, SIOCGLIFDSTADDR, (caddr_t)&lifreq) >= 0) {
+               memcpy(&dest, &lifreq.lifr_dstaddr, ADDRLEN(addr));
+               if (af == AF_INET)
+                       dest_pnt = (char *)&(SIN(&dest)->sin_addr);
+               else
+                       dest_pnt = (char *)&(SIN6(&dest)->sin6_addr);
+               flags = ZEBRA_IFA_PEER;
        }
-      else
-       {
-         prefixlen = lifreq.lifr_addrlen;
+
+       if (af == AF_INET) {
+               ret = if_ioctl(SIOCGLIFNETMASK, (caddr_t)&lifreq);
+
+               if (ret < 0) {
+                       if (errno != EADDRNOTAVAIL) {
+                               zlog_warn("SIOCGLIFNETMASK (%s) fail: %s",
+                                         ifp->name, safe_strerror(errno));
+                               return ret;
+                       }
+                       return 0;
+               }
+               memcpy(&mask, &lifreq.lifr_addr, ADDRLEN(addr));
+
+               prefixlen = ip_masklen(SIN(&mask)->sin_addr);
+               if (!dest_pnt
+                   && (if_ioctl(SIOCGLIFBRDADDR, (caddr_t)&lifreq) >= 0)) {
+                       memcpy(&dest, &lifreq.lifr_broadaddr,
+                              sizeof(struct sockaddr_in));
+                       dest_pnt = (char *)&SIN(&dest)->sin_addr;
+               }
+       } else if (af == AF_INET6) {
+               if (if_ioctl_ipv6(SIOCGLIFSUBNET, (caddr_t)&lifreq) < 0) {
+                       if (ifp->flags & IFF_POINTOPOINT)
+                               prefixlen = IPV6_MAX_BITLEN;
+                       else
+                               zlog_warn("SIOCGLIFSUBNET (%s) fail: %s",
+                                         ifp->name, safe_strerror(errno));
+               } else {
+                       prefixlen = lifreq.lifr_addrlen;
+               }
        }
-    }
 
-  /* Set address to the interface. */
-  if (af == AF_INET)
-    connected_add_ipv4 (ifp, flags, &SIN (addr)->sin_addr, prefixlen,
-                        (struct in_addr *) dest_pnt, label);
-  else if (af == AF_INET6)
-    connected_add_ipv6 (ifp, flags, &SIN6 (addr)->sin6_addr, prefixlen,
-                        (struct in6_addr *) dest_pnt, label);
+       /* Set address to the interface. */
+       if (af == AF_INET)
+               connected_add_ipv4(ifp, flags, &SIN(addr)->sin_addr, prefixlen,
+                                  (struct in_addr *)dest_pnt, label);
+       else if (af == AF_INET6)
+               connected_add_ipv6(ifp, flags, &SIN6(addr)->sin6_addr, NULL,
+                                  prefixlen, label);
 
-  return 0;
+       return 0;
 }
 
 /* Fetch interface information via ioctl(). */
-static void
-interface_info_ioctl (struct interface *ifp)
+static void interface_info_ioctl(struct interface *ifp)
 {
-  if_get_index (ifp);
-  if_get_flags (ifp);
-  if_get_mtu (ifp);
-  if_get_metric (ifp);
+       if_get_index(ifp);
+       if_get_flags(ifp);
+       if_get_mtu(ifp);
+       if_get_metric(ifp);
 }
 
 /* Lookup all interface information. */
-void
-interface_list (struct zebra_ns *zns)
+void interface_list(struct zebra_ns *zns)
 {
-  if (zns->ns_id != NS_DEFAULT)
-    {
-      zlog_warn ("interface_list: ignore NS %u", zns->ns_id);
-      return;
-    }
-  interface_list_ioctl (AF_INET);
-  interface_list_ioctl (AF_INET6);
-  interface_list_ioctl (AF_UNSPEC);
+       if (zns->ns_id != NS_DEFAULT) {
+               zlog_warn("interface_list: ignore NS %u", zns->ns_id);
+               return;
+       }
+       interface_list_ioctl(AF_INET);
+       interface_list_ioctl(AF_INET6);
+       interface_list_ioctl(AF_UNSPEC);
 }
 
-struct connected *
-if_lookup_linklocal (struct interface *ifp)
+struct connected *if_lookup_linklocal(struct interface *ifp)
 {
-  struct listnode *node;
-  struct connected *ifc;
+       struct listnode *node;
+       struct connected *ifc;
 
-  if (ifp == NULL)
-    return NULL;
+       if (ifp == NULL)
+               return NULL;
 
-  for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc))
-    {
-      if ((ifc->address->family == AF_INET6) &&
-          (IN6_IS_ADDR_LINKLOCAL (&ifc->address->u.prefix6)))
-        return ifc;
-    }
+       for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
+               if ((ifc->address->family == AF_INET6)
+                   && (IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6)))
+                       return ifc;
+       }
 
-  return NULL;
+       return NULL;
 }
+
+#endif /* SUNOS_5 */