]> git.proxmox.com Git - mirror_frr.git/blobdiff - lib/privs.c
ldpd: use red-black trees to store 'tnbr' elements
[mirror_frr.git] / lib / privs.c
index 8cfd8dfd5e401154a1125858c14fb7e8712964ad..376d6f3365bb8c22f50397420acabbb554492493 100644 (file)
@@ -27,6 +27,9 @@
 #include "memory.h"
 
 #ifdef HAVE_CAPABILITIES
+
+DEFINE_MTYPE_STATIC(LIB, PRIVS, "Privilege information")
+
 /* sort out some generic internal types for:
  *
  * privilege values (cap_value_t, priv_t)      -> pvalue_t
@@ -247,14 +250,9 @@ zprivs_caps_init (struct zebra_privs_t *zprivs)
       exit(1);
     }
 
-  if ( !zprivs_state.syscaps_p )
-    {
-      fprintf (stderr, "privs_init: capabilities enabled, "
-                       "but no capabilities supplied\n");
-    }
-
   /* we have caps, we have no need to ever change back the original user */
-  if (zprivs_state.zuid)
+    /* only change uid if we don't have the correct one */
+    if ((zprivs_state.zuid) && (zprivs_state.zsuid != zprivs_state.zuid))
     {
       if ( setreuid (zprivs_state.zuid, zprivs_state.zuid) )
         {
@@ -263,6 +261,9 @@ zprivs_caps_init (struct zebra_privs_t *zprivs)
           exit (1);
         }
     }
+
+  if ( !zprivs_state.syscaps_p )
+    return;
   
   if ( !(zprivs_state.caps = cap_init()) )
     {
@@ -307,11 +308,18 @@ zprivs_caps_init (struct zebra_privs_t *zprivs)
 
       current_caps = cap_get_proc();
       if (current_caps)
+        {
           current_caps_text = cap_to_text(current_caps, NULL);
+          cap_free(current_caps);
+        }
 
       wanted_caps_text = cap_to_text(zprivs_state.caps, NULL);
       fprintf(stderr, "Wanted caps: %s\n", wanted_caps_text ? wanted_caps_text : "???");
       fprintf(stderr, "Have   caps: %s\n", current_caps_text ? current_caps_text : "???");
+      if (current_caps_text)
+          cap_free(current_caps_text);
+      if (wanted_caps_text)
+          cap_free(wanted_caps_text);
 
       exit (1);
     }
@@ -524,7 +532,8 @@ zprivs_caps_init (struct zebra_privs_t *zprivs)
   /* we have caps, we have no need to ever change back the original user
    * change real, effective and saved to the specified user.
    */
-  if (zprivs_state.zuid)
+   /* only change uid if we don't have the correct one */
+   if ((zprivs_state.zuid) && (zprivs_state.zsuid != zprivs_state.zuid))
     {
       if ( setreuid (zprivs_state.zuid, zprivs_state.zuid) )
         {
@@ -595,7 +604,8 @@ zprivs_caps_terminate (void)
 int
 zprivs_change_uid (zebra_privs_ops_t op)
 {
-
+  if (zprivs_state.zsuid == zprivs_state.zuid)
+    return 0;
   if (op == ZPRIVS_RAISE)
     return seteuid (zprivs_state.zsuid);
   else if (op == ZPRIVS_LOWER)
@@ -622,11 +632,49 @@ zprivs_state_null (void)
   return zprivs_null_state;
 }
 
+#ifndef HAVE_GETGROUPLIST
+/* Solaris 11 has no getgrouplist() */
+static int
+getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups)
+{
+  struct group *grp;
+  size_t usridx;
+  int pos = 0, ret;
+
+  if (pos < *ngroups)
+    groups[pos] = group;
+  pos++;
+
+  setgrent();
+  while ((grp = getgrent()))
+    {
+      if (grp->gr_gid == group)
+        continue;
+      for (usridx = 0; grp->gr_mem[usridx] != NULL; usridx++)
+        if (!strcmp (grp->gr_mem[usridx], user))
+          {
+            if (pos < *ngroups)
+              groups[pos] = grp->gr_gid;
+            pos++;
+            break;
+          }
+    }
+  endgrent();
+
+  ret = (pos <= *ngroups) ? pos : -1;
+  *ngroups = pos;
+  return ret;
+}
+#endif /* HAVE_GETGROUPLIST */
+
 void
 zprivs_init(struct zebra_privs_t *zprivs)
 {
   struct passwd *pwentry = NULL;
   struct group *grentry = NULL;
+  gid_t groups[NGROUPS_MAX];
+  int i, ngroups = 0;
+  int found = 0;
 
   if (!zprivs)
     {
@@ -634,6 +682,15 @@ zprivs_init(struct zebra_privs_t *zprivs)
       exit (1);
     }
 
+  if (zprivs->vty_group)
+    {
+      /* in a "NULL" setup, this is allowed to fail too, but still try. */
+      if ((grentry = getgrnam (zprivs->vty_group)))
+        zprivs_state.vtygrp = grentry->gr_gid;
+      else
+        zprivs_state.vtygrp = (gid_t)-1;
+    }
+
   /* NULL privs */
   if (! (zprivs->user || zprivs->group 
          || zprivs->cap_num_p || zprivs->cap_num_i) )
@@ -645,54 +702,87 @@ zprivs_init(struct zebra_privs_t *zprivs)
 
   if (zprivs->user)
     {
-      if ( (pwentry = getpwnam (zprivs->user)) )
-        {
-          zprivs_state.zuid = pwentry->pw_uid;
-        }
-      else
+      if ( (pwentry = getpwnam (zprivs->user)) == NULL )
         {
           /* cant use log.h here as it depends on vty */
           fprintf (stderr, "privs_init: could not lookup user %s\n",
                    zprivs->user);
           exit (1);
         }
+
+      zprivs_state.zuid = pwentry->pw_uid;
+      zprivs_state.zgid = pwentry->pw_gid;
     }
 
   grentry = NULL;
 
-  if (zprivs->vty_group)
-    /* Add the vty_group to the supplementary groups so it can be chowned to */
+  if (zprivs->group)
     {
-      if ( (grentry = getgrnam (zprivs->vty_group)) )
+      if ( (grentry = getgrnam (zprivs->group)) == NULL )
         {
-          zprivs_state.vtygrp = grentry->gr_gid;
-          if ( setgroups (1, &zprivs_state.vtygrp) )
-            {
-              fprintf (stderr, "privs_init: could not setgroups, %s\n",
-                         safe_strerror (errno) );
-              exit (1);
-            }       
+          fprintf (stderr, "privs_init: could not lookup group %s\n",
+                   zprivs->group);
+          exit (1);
         }
-      else
+
+      zprivs_state.zgid = grentry->gr_gid;
+    }
+
+  if (zprivs->user)
+    {
+      ngroups = sizeof(groups);
+      if ( (ngroups = getgrouplist (zprivs->user, zprivs_state.zgid, groups, &ngroups )) < 0 )
         {
-          fprintf (stderr, "privs_init: could not lookup vty group %s\n",
-                   zprivs->vty_group);
+          /* cant use log.h here as it depends on vty */
+          fprintf (stderr, "privs_init: could not getgrouplist for user %s\n",
+                   zprivs->user);
           exit (1);
         }
     }
-  
-  if (zprivs->group)
+
+  if (zprivs->vty_group)
+    /* Add the vty_group to the supplementary groups so it can be chowned to */
     {
-      if ( (grentry = getgrnam (zprivs->group)) )
+      if (zprivs_state.vtygrp == (gid_t)-1)
         {
-          zprivs_state.zgid = grentry->gr_gid;
+          fprintf (stderr, "privs_init: could not lookup vty group %s\n",
+                   zprivs->vty_group);
+          exit (1);
         }
-      else
+
+      for ( i = 0; i < ngroups; i++ )
+        if ( groups[i] == zprivs_state.vtygrp )
+          {
+            found++;
+            break;
+          }
+
+      if (!found)
         {
-          fprintf (stderr, "privs_init: could not lookup group %s\n",
-                   zprivs->group);
+          fprintf (stderr, "privs_init: user(%s) is not part of vty group specified(%s)\n",
+                   zprivs->user, zprivs->vty_group);
           exit (1);
         }
+      if ( i >= ngroups && ngroups < (int) ZEBRA_NUM_OF(groups) )
+        {
+          groups[i] = zprivs_state.vtygrp;
+        }
+    }
+
+  /* add groups only if we changed uid - otherwise skip */
+  if ((ngroups) && (zprivs_state.zsuid != zprivs_state.zuid))
+    {
+      if ( setgroups (ngroups, groups) )
+        {
+          fprintf (stderr, "privs_init: could not setgroups, %s\n",
+                   safe_strerror (errno) );
+          exit (1);
+        }
+    }
+
+  /* change gid only if we changed uid - otherwise skip */
+  if ((zprivs_state.zgid) && (zprivs_state.zsuid != zprivs_state.zuid))
+    {
       /* change group now, forever. uid we do later */
       if ( setregid (zprivs_state.zgid, zprivs_state.zgid) )
         {
@@ -712,7 +802,8 @@ zprivs_init(struct zebra_privs_t *zprivs)
    * This is not worth that much security wise, but all we can do.
    */
   zprivs_state.zsuid = geteuid();  
-  if ( zprivs_state.zuid )
+  /* only change uid if we don't have the correct one */
+  if (( zprivs_state.zuid ) && (zprivs_state.zsuid != zprivs_state.zuid))
     {
       if ( setreuid (-1, zprivs_state.zuid) )
         {
@@ -739,7 +830,8 @@ zprivs_terminate (struct zebra_privs_t *zprivs)
 #ifdef HAVE_CAPABILITIES
   zprivs_caps_terminate();
 #else /* !HAVE_CAPABILITIES */
-  if (zprivs_state.zuid)
+  /* only change uid if we don't have the correct one */
+  if ((zprivs_state.zuid) && (zprivs_state.zsuid != zprivs_state.zuid))
     {
       if ( setreuid (zprivs_state.zuid, zprivs_state.zuid) )
         {