]> git.proxmox.com Git - mirror_frr.git/commitdiff
Privilege support files for zebra.
authorpaul <paul>
Tue, 20 May 2003 01:22:17 +0000 (01:22 +0000)
committerpaul <paul>
Tue, 20 May 2003 01:22:17 +0000 (01:22 +0000)
Linux capabilities enabled (if libcap is enabled).

lib/privs.c [new file with mode: 0644]
lib/privs.h [new file with mode: 0644]

diff --git a/lib/privs.c b/lib/privs.c
new file mode 100644 (file)
index 0000000..174618a
--- /dev/null
@@ -0,0 +1,351 @@
+/* 
+ * 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            */
+} 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
+};
+
+static cap_value_t cap_setuid_value [] = { CAP_SETUID };
+
+/* 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_t flag;
+  cap_flag_value_t val;
+  
+  for (i=0; i < zprivs_state.syscaps_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 CAP_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);
+        }
+    }
+  
+  if (zprivs->group)
+    {
+      if ( (grentry = getgrnam (zprivs->user)) )
+        zprivs_state.zgid = pwentry->pw_uid;
+      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);
+    }
+  
+  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);
+
+  /* still need CAP_SETUID for the moment */
+  cap_set_flag(zprivs_state.caps, CAP_PERMITTED,
+               1, cap_setuid_value, CAP_SET);
+  cap_set_flag(zprivs_state.caps, CAP_EFFECTIVE,
+                               1, cap_setuid_value, 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 clear bar cap_setuid_value. 
+   * 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);
+    }
+  
+  /* 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);
+        }
+     }
+   */
+
+  /* No more need for cap_setuid_value */
+  cap_set_flag(zprivs_state.caps, CAP_PERMITTED,
+               1, cap_setuid_value, CAP_CLEAR);
+  cap_set_flag(zprivs_state.caps, CAP_EFFECTIVE,
+                               1, cap_setuid_value, CAP_CLEAR);
+  if ( cap_set_proc (zprivs_state.caps) ) 
+    {
+      zlog_err ("privs_init: cap_set_proc failed to clear cap_setuid, %s"
+                strerror (errno) );
+      exit (1);
+    }
+
+  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)
+    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.syscaps_num_p)
+    XFREE (MTYPE_PRIVS, zprivs_state.syscaps_p);
+  
+  if (zprivs_state.syscaps_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;
+}
diff --git a/lib/privs.h b/lib/privs.h
new file mode 100644 (file)
index 0000000..6839c47
--- /dev/null
@@ -0,0 +1,75 @@
+/* 
+ * 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_RAW,
+  ZCAP_CHROOT,
+  ZCAP_NICE,
+  ZCAP_PTRACE,
+  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;
+
+  /* methods */
+  int 
+    (*change) (zebra_privs_ops_t);    /* change privileges, 0 on success */
+  zebra_privs_current_t 
+    (*current_state) (void);          /* current privilege state */
+};
+
+  /* initialise zebra privileges */
+void zprivs_init (struct zebra_privs_t *zprivs);
+  /* drop all and terminate privileges */ 
+void zprivs_terminate (void);
+
+#endif /* _ZEBRA_PRIVS_H */