-/*
+/*
* Zebra privileges.
*
* Copyright (C) 2003 Paul Jakma.
* 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>
#include "log.h"
#include "privs.h"
#include "memory.h"
+#include "lib_errors.h"
#ifdef HAVE_CAPABILITIES
* sets are mostly opaque, to hold a set of privileges, related in some way.
* storage binds together a set of sets we're interested in.
* (in reality: cap_value_t and priv_t are ints)
- */
+ */
#ifdef HAVE_LCAPS
/* Linux doesn't have a 'set' type: a set of related privileges */
struct _pset {
- int num;
- cap_value_t *caps;
+ int num;
+ cap_value_t *caps;
};
typedef cap_value_t pvalue_t;
typedef struct _pset pset_t;
typedef cap_t pstorage_t;
-#elif defined (HAVE_SOLARIS_CAPABILITIES)
+#elif defined(HAVE_SOLARIS_CAPABILITIES)
typedef priv_t pvalue_t;
typedef priv_set_t pset_t;
typedef priv_set_t *pstorage_t;
static zebra_privs_current_t zprivs_null_state = ZPRIVS_RAISED;
/* internal privileges state */
-static struct _zprivs_t
-{
+static struct _zprivs_t {
#ifdef HAVE_CAPABILITIES
- pstorage_t caps; /* working storage */
- pset_t *syscaps_p; /* system-type requested permitted caps */
- pset_t *syscaps_i; /* system-type requested inheritable caps */
-#endif /* HAVE_CAPABILITIES */
- uid_t zuid, /* uid to run as */
- zsuid; /* saved uid */
- gid_t zgid; /* gid to run as */
- gid_t vtygrp; /* gid for vty sockets */
+ pstorage_t caps; /* working storage */
+ pset_t *syscaps_p; /* system-type requested permitted caps */
+ pset_t *syscaps_i; /* system-type requested inheritable caps */
+#endif /* HAVE_CAPABILITIES */
+ 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_CAPABILITIES
-int zprivs_change_caps (zebra_privs_ops_t);
-zebra_privs_current_t zprivs_state_caps (void);
+int zprivs_change_caps(zebra_privs_ops_t);
+zebra_privs_current_t zprivs_state_caps(void);
#endif /* HAVE_CAPABILITIES */
-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);
+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);
#ifdef HAVE_CAPABILITIES
/* internal capability API */
-static pset_t *zcaps2sys (zebra_capabilities_t *, int);
-static void zprivs_caps_init (struct zebra_privs_t *);
-static void zprivs_caps_terminate (void);
+static pset_t *zcaps2sys(zebra_capabilities_t *, int);
+static void zprivs_caps_init(struct zebra_privs_t *);
+static void zprivs_caps_terminate(void);
/* Map of Quagga abstract capabilities to system capabilities */
-static struct
-{
- int num;
- pvalue_t *system_caps;
-} cap_map [ZCAP_MAX] =
-{
+static struct {
+ int num;
+ pvalue_t *system_caps;
+} cap_map[ZCAP_MAX] = {
#ifdef HAVE_LCAPS /* Quagga -> Linux capabilities mappings */
- [ZCAP_SETID] = { 2, (pvalue_t []) { CAP_SETGID,
- CAP_SETUID }, },
- [ZCAP_BIND] = { 1, (pvalue_t []) { CAP_NET_BIND_SERVICE }, },
- [ZCAP_NET_ADMIN] = { 1, (pvalue_t []) { CAP_NET_ADMIN }, },
- [ZCAP_NET_RAW] = { 1, (pvalue_t []) { CAP_NET_RAW }, },
- [ZCAP_CHROOT] = { 1, (pvalue_t []) { CAP_SYS_CHROOT, }, },
- [ZCAP_NICE] = { 1, (pvalue_t []) { CAP_SYS_NICE }, },
- [ZCAP_PTRACE] = { 1, (pvalue_t []) { CAP_SYS_PTRACE }, },
- [ZCAP_DAC_OVERRIDE] = { 1, (pvalue_t []) { CAP_DAC_OVERRIDE }, },
- [ZCAP_READ_SEARCH] = { 1, (pvalue_t []) { CAP_DAC_READ_SEARCH }, },
- [ZCAP_SYS_ADMIN] = { 1, (pvalue_t []) { CAP_SYS_ADMIN }, },
- [ZCAP_FOWNER] = { 1, (pvalue_t []) { CAP_FOWNER }, },
+ [ZCAP_SETID] =
+ {
+ 2, (pvalue_t[]){CAP_SETGID, CAP_SETUID},
+ },
+ [ZCAP_BIND] =
+ {
+ 1, (pvalue_t[]){CAP_NET_BIND_SERVICE},
+ },
+ [ZCAP_NET_ADMIN] =
+ {
+ 1, (pvalue_t[]){CAP_NET_ADMIN},
+ },
+ [ZCAP_NET_RAW] =
+ {
+ 1, (pvalue_t[]){CAP_NET_RAW},
+ },
+ [ZCAP_CHROOT] =
+ {
+ 1,
+ (pvalue_t[]){
+ CAP_SYS_CHROOT,
+ },
+ },
+ [ZCAP_NICE] =
+ {
+ 1, (pvalue_t[]){CAP_SYS_NICE},
+ },
+ [ZCAP_PTRACE] =
+ {
+ 1, (pvalue_t[]){CAP_SYS_PTRACE},
+ },
+ [ZCAP_DAC_OVERRIDE] =
+ {
+ 1, (pvalue_t[]){CAP_DAC_OVERRIDE},
+ },
+ [ZCAP_READ_SEARCH] =
+ {
+ 1, (pvalue_t[]){CAP_DAC_READ_SEARCH},
+ },
+ [ZCAP_SYS_ADMIN] =
+ {
+ 1, (pvalue_t[]){CAP_SYS_ADMIN},
+ },
+ [ZCAP_FOWNER] =
+ {
+ 1, (pvalue_t[]){CAP_FOWNER},
+ },
#elif defined(HAVE_SOLARIS_CAPABILITIES) /* HAVE_LCAPS */
- /* Quagga -> Solaris privilege mappings */
- [ZCAP_SETID] = { 1, (pvalue_t []) { PRIV_PROC_SETID }, },
- [ZCAP_BIND] = { 1, (pvalue_t []) { PRIV_NET_PRIVADDR }, },
- /* IP_CONFIG is a subset of NET_CONFIG and is allowed in zones */
+ /* Quagga -> Solaris privilege mappings */
+ [ZCAP_SETID] =
+ {
+ 1, (pvalue_t[]){PRIV_PROC_SETID},
+ },
+ [ZCAP_BIND] =
+ {
+ 1, (pvalue_t[]){PRIV_NET_PRIVADDR},
+ },
+/* IP_CONFIG is a subset of NET_CONFIG and is allowed in zones */
#ifdef PRIV_SYS_IP_CONFIG
- [ZCAP_NET_ADMIN] = { 1, (pvalue_t []) { PRIV_SYS_IP_CONFIG }, },
+ [ZCAP_NET_ADMIN] =
+ {
+ 1, (pvalue_t[]){PRIV_SYS_IP_CONFIG},
+ },
#else
- [ZCAP_NET_ADMIN] = { 1, (pvalue_t []) { PRIV_SYS_NET_CONFIG }, },
+ [ZCAP_NET_ADMIN] =
+ {
+ 1, (pvalue_t[]){PRIV_SYS_NET_CONFIG},
+ },
#endif
- [ZCAP_NET_RAW] = { 2, (pvalue_t []) { PRIV_NET_RAWACCESS,
- PRIV_NET_ICMPACCESS }, },
- [ZCAP_CHROOT] = { 1, (pvalue_t []) { PRIV_PROC_CHROOT }, },
- [ZCAP_NICE] = { 1, (pvalue_t []) { PRIV_PROC_PRIOCNTL }, },
- [ZCAP_PTRACE] = { 1, (pvalue_t []) { PRIV_PROC_SESSION }, },
- [ZCAP_DAC_OVERRIDE] = { 5, (pvalue_t []) { PRIV_FILE_DAC_EXECUTE,
- PRIV_FILE_DAC_READ,
- PRIV_FILE_DAC_SEARCH,
- PRIV_FILE_DAC_WRITE,
- PRIV_FILE_DAC_SEARCH }, },
- [ZCAP_READ_SEARCH] = { 2, (pvalue_t []) { PRIV_FILE_DAC_SEARCH,
- PRIV_FILE_DAC_READ }, },
- [ZCAP_SYS_ADMIN] = { 1, (pvalue_t []) { PRIV_SYS_ADMIN }, },
- [ZCAP_FOWNER] = { 1, (pvalue_t []) { PRIV_FILE_OWNER }, },
+ [ZCAP_NET_RAW] =
+ {
+ 2, (pvalue_t[]){PRIV_NET_RAWACCESS,
+ PRIV_NET_ICMPACCESS},
+ },
+ [ZCAP_CHROOT] =
+ {
+ 1, (pvalue_t[]){PRIV_PROC_CHROOT},
+ },
+ [ZCAP_NICE] =
+ {
+ 1, (pvalue_t[]){PRIV_PROC_PRIOCNTL},
+ },
+ [ZCAP_PTRACE] =
+ {
+ 1, (pvalue_t[]){PRIV_PROC_SESSION},
+ },
+ [ZCAP_DAC_OVERRIDE] =
+ {
+ 5, (pvalue_t[]){PRIV_FILE_DAC_EXECUTE,
+ PRIV_FILE_DAC_READ,
+ PRIV_FILE_DAC_SEARCH,
+ PRIV_FILE_DAC_WRITE,
+ PRIV_FILE_DAC_SEARCH},
+ },
+ [ZCAP_READ_SEARCH] =
+ {
+ 2, (pvalue_t[]){PRIV_FILE_DAC_SEARCH,
+ PRIV_FILE_DAC_READ},
+ },
+ [ZCAP_SYS_ADMIN] =
+ {
+ 1, (pvalue_t[]){PRIV_SYS_ADMIN},
+ },
+ [ZCAP_FOWNER] =
+ {
+ 1, (pvalue_t[]){PRIV_FILE_OWNER},
+ },
#endif /* HAVE_SOLARIS_CAPABILITIES */
};
#ifdef HAVE_LCAPS
/* Linux forms of capabilities methods */
/* convert zebras privileges to system capabilities */
-static pset_t *
-zcaps2sys (zebra_capabilities_t *zcaps, int num)
+static pset_t *zcaps2sys(zebra_capabilities_t *zcaps, int num)
{
- pset_t *syscaps;
- int i, j = 0, count = 0;
-
- if (!num)
- return NULL;
-
- /* first count up how many system caps we have */
- for (i= 0; i < num; i++)
- count += cap_map[zcaps[i]].num;
-
- if ( (syscaps = XCALLOC (MTYPE_PRIVS, (sizeof(pset_t) * num))) == NULL)
- {
- fprintf (stderr, "%s: could not allocate syscaps!", __func__);
- return NULL;
- }
-
- syscaps->caps = XCALLOC (MTYPE_PRIVS, (sizeof (pvalue_t) * count));
-
- if (!syscaps->caps)
- {
- fprintf (stderr, "%s: could not XCALLOC caps!", __func__);
- return NULL;
- }
-
- /* copy the capabilities over */
- count = 0;
- for (i=0; i < num; i++)
- for (j = 0; j < cap_map[zcaps[i]].num; j++)
- syscaps->caps[count++] = cap_map[zcaps[i]].system_caps[j];
-
- /* iterations above should be exact same as previous count, obviously.. */
- syscaps->num = count;
-
- return syscaps;
+ pset_t *syscaps;
+ int i, j = 0, count = 0;
+
+ if (!num)
+ return NULL;
+
+ /* first count up how many system caps we have */
+ for (i = 0; i < num; i++)
+ count += cap_map[zcaps[i]].num;
+
+ if ((syscaps = XCALLOC(MTYPE_PRIVS, (sizeof(pset_t) * num))) == NULL) {
+ fprintf(stderr, "%s: could not allocate syscaps!", __func__);
+ return NULL;
+ }
+
+ syscaps->caps = XCALLOC(MTYPE_PRIVS, (sizeof(pvalue_t) * count));
+
+ if (!syscaps->caps) {
+ fprintf(stderr, "%s: could not XCALLOC caps!", __func__);
+ return NULL;
+ }
+
+ /* copy the capabilities over */
+ count = 0;
+ for (i = 0; i < num; i++)
+ for (j = 0; j < cap_map[zcaps[i]].num; j++)
+ syscaps->caps[count++] =
+ cap_map[zcaps[i]].system_caps[j];
+
+ /* iterations above should be exact same as previous count, obviously..
+ */
+ syscaps->num = count;
+
+ return syscaps;
}
/* set or clear the effective capabilities to/from permitted */
-int
-zprivs_change_caps (zebra_privs_ops_t op)
+int zprivs_change_caps(zebra_privs_ops_t op)
{
- cap_flag_value_t cflag;
-
- /* should be no possibility of being called without valid caps */
- assert (zprivs_state.syscaps_p && zprivs_state.caps);
- if (! (zprivs_state.syscaps_p && zprivs_state.caps))
- exit (1);
-
- 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.syscaps_p->num,
- zprivs_state.syscaps_p->caps,
- cflag))
- return cap_set_proc (zprivs_state.caps);
- return -1;
+ cap_flag_value_t cflag;
+
+ /* should be no possibility of being called without valid caps */
+ assert(zprivs_state.syscaps_p && zprivs_state.caps);
+ if (!(zprivs_state.syscaps_p && zprivs_state.caps))
+ exit(1);
+
+ 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.syscaps_p->num,
+ zprivs_state.syscaps_p->caps, cflag))
+ return cap_set_proc(zprivs_state.caps);
+ return -1;
}
-zebra_privs_current_t
-zprivs_state_caps (void)
+zebra_privs_current_t zprivs_state_caps(void)
{
- int i;
- cap_flag_value_t val;
-
- /* should be no possibility of being called without valid caps */
- assert (zprivs_state.syscaps_p && zprivs_state.caps);
- if (! (zprivs_state.syscaps_p && zprivs_state.caps))
- exit (1);
-
- for (i=0; i < zprivs_state.syscaps_p->num; i++)
- {
- if ( cap_get_flag (zprivs_state.caps, zprivs_state.syscaps_p->caps[i],
- CAP_EFFECTIVE, &val) )
- {
- zlog_warn ("zprivs_state_caps: could not cap_get_flag, %s",
- safe_strerror (errno) );
- return ZPRIVS_UNKNOWN;
- }
- if (val == CAP_SET)
- return ZPRIVS_RAISED;
- }
- return ZPRIVS_LOWERED;
+ int i;
+ cap_flag_value_t val;
+
+ /* should be no possibility of being called without valid caps */
+ assert(zprivs_state.syscaps_p && zprivs_state.caps);
+ if (!(zprivs_state.syscaps_p && zprivs_state.caps))
+ exit(1);
+
+ for (i = 0; i < zprivs_state.syscaps_p->num; i++) {
+ if (cap_get_flag(zprivs_state.caps,
+ zprivs_state.syscaps_p->caps[i], CAP_EFFECTIVE,
+ &val)) {
+ flog_err(
+ EC_LIB_SYSTEM_CALL,
+ "zprivs_state_caps: could not cap_get_flag, %s",
+ safe_strerror(errno));
+ return ZPRIVS_UNKNOWN;
+ }
+ if (val == CAP_SET)
+ return ZPRIVS_RAISED;
+ }
+ return ZPRIVS_LOWERED;
}
-static void
-zprivs_caps_init (struct zebra_privs_t *zprivs)
+static void zprivs_caps_init(struct zebra_privs_t *zprivs)
{
- zprivs_state.syscaps_p = zcaps2sys (zprivs->caps_p, zprivs->cap_num_p);
- zprivs_state.syscaps_i = zcaps2sys (zprivs->caps_i, zprivs->cap_num_i);
-
- /* Tell kernel we want caps maintained across uid changes */
- if ( prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1 )
- {
- fprintf (stderr, "privs_init: could not set PR_SET_KEEPCAPS, %s\n",
- safe_strerror (errno) );
- exit(1);
- }
-
- /* we have caps, we have no need to ever change back the original user */
- /* 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) )
- {
- fprintf (stderr, "zprivs_init (cap): could not setreuid, %s\n",
- safe_strerror (errno));
- exit (1);
- }
- }
-
- if ( !zprivs_state.syscaps_p )
- return;
-
- if ( !(zprivs_state.caps = cap_init()) )
- {
- fprintf (stderr, "privs_init: failed to cap_init, %s\n",
- safe_strerror (errno));
- exit (1);
- }
-
- if ( cap_clear (zprivs_state.caps) )
- {
- fprintf (stderr, "privs_init: failed to cap_clear, %s\n",
- safe_strerror (errno));
- exit (1);
- }
-
- /* set permitted caps */
- cap_set_flag(zprivs_state.caps, CAP_PERMITTED,
- zprivs_state.syscaps_p->num,
- zprivs_state.syscaps_p->caps,
- CAP_SET);
-
- /* set inheritable caps, if any */
- if (zprivs_state.syscaps_i && zprivs_state.syscaps_i->num)
- {
- cap_set_flag(zprivs_state.caps, CAP_INHERITABLE,
- zprivs_state.syscaps_i->num,
- zprivs_state.syscaps_i->caps,
- 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) )
- {
- cap_t current_caps;
- char *current_caps_text = NULL;
- char *wanted_caps_text = NULL;
-
- fprintf(stderr, "privs_init: initial cap_set_proc failed: %s\n",
- safe_strerror(errno));
-
- 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);
- }
-
- /* set methods for the caller to use */
- zprivs->change = zprivs_change_caps;
- zprivs->current_state = zprivs_state_caps;
+ zprivs_state.syscaps_p = zcaps2sys(zprivs->caps_p, zprivs->cap_num_p);
+ zprivs_state.syscaps_i = zcaps2sys(zprivs->caps_i, zprivs->cap_num_i);
+
+ /* Tell kernel we want caps maintained across uid changes */
+ if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1) {
+ fprintf(stderr,
+ "privs_init: could not set PR_SET_KEEPCAPS, %s\n",
+ safe_strerror(errno));
+ exit(1);
+ }
+
+ /* we have caps, we have no need to ever change back the original user
+ */
+ /* 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)) {
+ fprintf(stderr,
+ "zprivs_init (cap): could not setreuid, %s\n",
+ safe_strerror(errno));
+ exit(1);
+ }
+ }
+
+ if (!zprivs_state.syscaps_p)
+ return;
+
+ if (!(zprivs_state.caps = cap_init())) {
+ fprintf(stderr, "privs_init: failed to cap_init, %s\n",
+ safe_strerror(errno));
+ exit(1);
+ }
+
+ if (cap_clear(zprivs_state.caps)) {
+ fprintf(stderr, "privs_init: failed to cap_clear, %s\n",
+ safe_strerror(errno));
+ exit(1);
+ }
+
+ /* set permitted caps */
+ cap_set_flag(zprivs_state.caps, CAP_PERMITTED,
+ zprivs_state.syscaps_p->num, zprivs_state.syscaps_p->caps,
+ CAP_SET);
+
+ /* set inheritable caps, if any */
+ if (zprivs_state.syscaps_i && zprivs_state.syscaps_i->num) {
+ cap_set_flag(zprivs_state.caps, CAP_INHERITABLE,
+ zprivs_state.syscaps_i->num,
+ zprivs_state.syscaps_i->caps, 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)) {
+ cap_t current_caps;
+ char *current_caps_text = NULL;
+ char *wanted_caps_text = NULL;
+
+ fprintf(stderr, "privs_init: initial cap_set_proc failed: %s\n",
+ safe_strerror(errno));
+
+ 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);
+ }
+
+ /* set methods for the caller to use */
+ zprivs->change = zprivs_change_caps;
+ zprivs->current_state = zprivs_state_caps;
}
-static void
-zprivs_caps_terminate (void)
+static void zprivs_caps_terminate(void)
{
- /* clear all capabilities */
- if (zprivs_state.caps)
- cap_clear (zprivs_state.caps);
-
- /* and boom, capabilities are gone forever */
- if ( cap_set_proc (zprivs_state.caps) )
- {
- fprintf (stderr, "privs_terminate: cap_set_proc failed, %s",
- safe_strerror (errno) );
- exit (1);
- }
-
- /* free up private state */
- if (zprivs_state.syscaps_p->num)
- {
- XFREE (MTYPE_PRIVS, zprivs_state.syscaps_p->caps);
- XFREE (MTYPE_PRIVS, zprivs_state.syscaps_p);
- }
-
- if (zprivs_state.syscaps_i && zprivs_state.syscaps_i->num)
- {
- XFREE (MTYPE_PRIVS, zprivs_state.syscaps_i->caps);
- XFREE (MTYPE_PRIVS, zprivs_state.syscaps_i);
- }
-
- cap_free (zprivs_state.caps);
+ /* clear all capabilities */
+ if (zprivs_state.caps)
+ cap_clear(zprivs_state.caps);
+
+ /* and boom, capabilities are gone forever */
+ if (cap_set_proc(zprivs_state.caps)) {
+ fprintf(stderr, "privs_terminate: cap_set_proc failed, %s",
+ safe_strerror(errno));
+ exit(1);
+ }
+
+ /* free up private state */
+ if (zprivs_state.syscaps_p->num) {
+ XFREE(MTYPE_PRIVS, zprivs_state.syscaps_p->caps);
+ XFREE(MTYPE_PRIVS, zprivs_state.syscaps_p);
+ }
+
+ if (zprivs_state.syscaps_i && zprivs_state.syscaps_i->num) {
+ XFREE(MTYPE_PRIVS, zprivs_state.syscaps_i->caps);
+ XFREE(MTYPE_PRIVS, zprivs_state.syscaps_i);
+ }
+
+ cap_free(zprivs_state.caps);
}
-#elif defined (HAVE_SOLARIS_CAPABILITIES) /* !HAVE_LCAPS */
+#elif defined(HAVE_SOLARIS_CAPABILITIES) /* !HAVE_LCAPS */
-/* Solaris specific capability/privilege methods
+/* Solaris specific capability/privilege methods
*
* Resources:
* - the 'privileges' man page
* - http://cvs.opensolaris.org
- * - http://blogs.sun.com/roller/page/gbrunett?entry=privilege_enabling_set_id_programs1
+ * -
+ * http://blogs.sun.com/roller/page/gbrunett?entry=privilege_enabling_set_id_programs1
*/
-static pset_t *
-zprivs_caps_minimal ()
+static pset_t *zprivs_caps_minimal()
{
- pset_t *minimal;
+ pset_t *minimal;
- if ((minimal = priv_str_to_set("basic", ",", NULL)) == NULL)
- {
- fprintf (stderr, "%s: couldn't get basic set!\n", __func__);
- exit (1);
- }
+ if ((minimal = priv_str_to_set("basic", ",", NULL)) == NULL) {
+ fprintf(stderr, "%s: couldn't get basic set!\n", __func__);
+ exit(1);
+ }
- /* create a minimal privilege set from the basic set */
- (void) priv_delset(minimal, PRIV_PROC_EXEC);
- (void) priv_delset(minimal, PRIV_PROC_INFO);
- (void) priv_delset(minimal, PRIV_PROC_SESSION);
- (void) priv_delset(minimal, PRIV_FILE_LINK_ANY);
+ /* create a minimal privilege set from the basic set */
+ (void)priv_delset(minimal, PRIV_PROC_EXEC);
+ (void)priv_delset(minimal, PRIV_PROC_INFO);
+ (void)priv_delset(minimal, PRIV_PROC_SESSION);
+ (void)priv_delset(minimal, PRIV_FILE_LINK_ANY);
- return minimal;
+ return minimal;
}
/* convert zebras privileges to system capabilities */
-static pset_t *
-zcaps2sys (zebra_capabilities_t *zcaps, int num)
+static pset_t *zcaps2sys(zebra_capabilities_t *zcaps, int num)
{
- pset_t *syscaps;
- int i, j = 0;
-
- if ((syscaps = priv_allocset()) == NULL)
- {
- fprintf (stderr, "%s: could not allocate syscaps!\n", __func__);
- exit (1);
- }
-
- priv_emptyset (syscaps);
-
- for (i=0; i < num; i++)
- for (j = 0; j < cap_map[zcaps[i]].num; j++)
- priv_addset (syscaps, cap_map[zcaps[i]].system_caps[j]);
-
- return syscaps;
+ pset_t *syscaps;
+ int i, j = 0;
+
+ if ((syscaps = priv_allocset()) == NULL) {
+ fprintf(stderr, "%s: could not allocate syscaps!\n", __func__);
+ exit(1);
+ }
+
+ priv_emptyset(syscaps);
+
+ for (i = 0; i < num; i++)
+ for (j = 0; j < cap_map[zcaps[i]].num; j++)
+ priv_addset(syscaps, cap_map[zcaps[i]].system_caps[j]);
+
+ return syscaps;
}
/* callback exported to users to RAISE and LOWER effective privileges
* from nothing to the given permitted set and back down
*/
-int
-zprivs_change_caps (zebra_privs_ops_t op)
+int zprivs_change_caps(zebra_privs_ops_t op)
{
- pset_t *privset;
-
- /* should be no possibility of being called without valid caps */
- assert (zprivs_state.syscaps_p);
- if (!zprivs_state.syscaps_p)
- {
- fprintf (stderr, "%s: Eek, missing privileged caps!", __func__);
- exit (1);
- }
-
- assert (zprivs_state.caps);
- if (!zprivs_state.caps)
- {
- fprintf (stderr, "%s: Eek, missing caps!", __func__);
- exit (1);
- }
-
- /* to raise: copy original permitted as our working effective set
- * to lower: copy regular effective set stored in zprivs_state.caps
- */
- if (op == ZPRIVS_RAISE)
- privset = zprivs_state.syscaps_p;
- else if (op == ZPRIVS_LOWER)
- privset = zprivs_state.caps;
- else
- return -1;
-
- if (setppriv (PRIV_SET, PRIV_EFFECTIVE, privset) != 0)
- return -1;
-
- return 0;
+ pset_t *privset;
+
+ /* should be no possibility of being called without valid caps */
+ assert(zprivs_state.syscaps_p);
+ if (!zprivs_state.syscaps_p) {
+ fprintf(stderr, "%s: Eek, missing privileged caps!", __func__);
+ exit(1);
+ }
+
+ assert(zprivs_state.caps);
+ if (!zprivs_state.caps) {
+ fprintf(stderr, "%s: Eek, missing caps!", __func__);
+ exit(1);
+ }
+
+ /* to raise: copy original permitted as our working effective set
+ * to lower: copy regular effective set stored in zprivs_state.caps
+ */
+ if (op == ZPRIVS_RAISE)
+ privset = zprivs_state.syscaps_p;
+ else if (op == ZPRIVS_LOWER)
+ privset = zprivs_state.caps;
+ else
+ return -1;
+
+ if (setppriv(PRIV_SET, PRIV_EFFECTIVE, privset) != 0)
+ return -1;
+
+ return 0;
}
/* Retrieve current privilege state, is it RAISED or LOWERED? */
-zebra_privs_current_t
-zprivs_state_caps (void)
+zebra_privs_current_t zprivs_state_caps(void)
{
- zebra_privs_current_t result;
- pset_t *effective;
-
- if ( (effective = priv_allocset()) == NULL)
- {
- fprintf (stderr, "%s: failed to get priv_allocset! %s\n", __func__,
- safe_strerror (errno));
- return ZPRIVS_UNKNOWN;
- }
-
- if (getppriv (PRIV_EFFECTIVE, effective))
- {
- fprintf (stderr, "%s: failed to get state! %s\n", __func__,
- safe_strerror (errno));
- result = ZPRIVS_UNKNOWN;
- }
- else
- {
- if (priv_isequalset (effective, zprivs_state.syscaps_p))
- result = ZPRIVS_RAISED;
- else if (priv_isequalset (effective, zprivs_state.caps))
- result = ZPRIVS_LOWERED;
- else
- result = ZPRIVS_UNKNOWN;
- }
-
- priv_freeset (effective);
- return result;
+ zebra_privs_current_t result;
+ pset_t *effective;
+
+ if ((effective = priv_allocset()) == NULL) {
+ fprintf(stderr, "%s: failed to get priv_allocset! %s\n",
+ __func__, safe_strerror(errno));
+ return ZPRIVS_UNKNOWN;
+ }
+
+ if (getppriv(PRIV_EFFECTIVE, effective)) {
+ fprintf(stderr, "%s: failed to get state! %s\n", __func__,
+ safe_strerror(errno));
+ result = ZPRIVS_UNKNOWN;
+ } else {
+ if (priv_isequalset(effective, zprivs_state.syscaps_p))
+ result = ZPRIVS_RAISED;
+ else if (priv_isequalset(effective, zprivs_state.caps))
+ result = ZPRIVS_LOWERED;
+ else
+ result = ZPRIVS_UNKNOWN;
+ }
+
+ priv_freeset(effective);
+ return result;
}
-static void
-zprivs_caps_init (struct zebra_privs_t *zprivs)
+static void zprivs_caps_init(struct zebra_privs_t *zprivs)
{
- pset_t *basic;
- pset_t *minimal;
-
- /* the specified sets */
- zprivs_state.syscaps_p = zcaps2sys (zprivs->caps_p, zprivs->cap_num_p);
- zprivs_state.syscaps_i = zcaps2sys (zprivs->caps_i, zprivs->cap_num_i);
-
- /* nonsensical to have gotten here but not have capabilities */
- if (!zprivs_state.syscaps_p)
- {
- fprintf (stderr, "%s: capabilities enabled, "
- "but no valid capabilities supplied\n",
- __func__);
- }
-
- /* We retain the basic set in our permitted set, as Linux has no
- * equivalent. The basic set on Linux hence is implicit, always
- * there.
- */
- if ((basic = priv_str_to_set("basic", ",", NULL)) == NULL)
- {
- fprintf (stderr, "%s: couldn't get basic set!\n", __func__);
- exit (1);
- }
-
- /* Add the basic set to the permitted set */
- priv_union (basic, zprivs_state.syscaps_p);
- priv_freeset (basic);
-
- /* Hey kernel, we know about privileges!
- * this isn't strictly required, use of setppriv should have same effect
- */
- if (setpflags (PRIV_AWARE, 1))
- {
- fprintf (stderr, "%s: error setting PRIV_AWARE!, %s\n", __func__,
- safe_strerror (errno) );
- exit (1);
- }
-
- /* need either valid or empty sets for both p and i.. */
- assert (zprivs_state.syscaps_i && zprivs_state.syscaps_p);
-
- /* we have caps, we have no need to ever change back the original user
- * change real, effective and saved to the specified user.
- */
- /* 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) )
- {
- fprintf (stderr, "%s: could not setreuid, %s\n",
- __func__, safe_strerror (errno));
- exit (1);
- }
- }
-
- /* set the permitted set */
- if (setppriv (PRIV_SET, PRIV_PERMITTED, zprivs_state.syscaps_p))
- {
- fprintf (stderr, "%s: error setting permitted set!, %s\n", __func__,
- safe_strerror (errno) );
- exit (1);
- }
-
- /* set the inheritable set */
- if (setppriv (PRIV_SET, PRIV_INHERITABLE, zprivs_state.syscaps_i))
- {
- fprintf (stderr, "%s: error setting inheritable set!, %s\n", __func__,
- safe_strerror (errno) );
- exit (1);
- }
-
- /* we need a minimal basic set for 'effective', potentially for inheritable too */
- minimal = zprivs_caps_minimal();
-
- /* now set the effective set with a subset of basic privileges */
- if (setppriv (PRIV_SET, PRIV_EFFECTIVE, minimal))
- {
- fprintf (stderr, "%s: error setting effective set!, %s\n", __func__,
- safe_strerror (errno) );
- exit (1);
- }
-
- /* we'll use the minimal set as our working-storage privset */
- zprivs_state.caps = minimal;
-
- /* set methods for the caller to use */
- zprivs->change = zprivs_change_caps;
- zprivs->current_state = zprivs_state_caps;
+ pset_t *basic;
+ pset_t *minimal;
+
+ /* the specified sets */
+ zprivs_state.syscaps_p = zcaps2sys(zprivs->caps_p, zprivs->cap_num_p);
+ zprivs_state.syscaps_i = zcaps2sys(zprivs->caps_i, zprivs->cap_num_i);
+
+ /* nonsensical to have gotten here but not have capabilities */
+ if (!zprivs_state.syscaps_p) {
+ fprintf(stderr,
+ "%s: capabilities enabled, "
+ "but no valid capabilities supplied\n",
+ __func__);
+ }
+
+ /* We retain the basic set in our permitted set, as Linux has no
+ * equivalent. The basic set on Linux hence is implicit, always
+ * there.
+ */
+ if ((basic = priv_str_to_set("basic", ",", NULL)) == NULL) {
+ fprintf(stderr, "%s: couldn't get basic set!\n", __func__);
+ exit(1);
+ }
+
+ /* Add the basic set to the permitted set */
+ priv_union(basic, zprivs_state.syscaps_p);
+ priv_freeset(basic);
+
+ /* Hey kernel, we know about privileges!
+ * this isn't strictly required, use of setppriv should have same effect
+ */
+ if (setpflags(PRIV_AWARE, 1)) {
+ fprintf(stderr, "%s: error setting PRIV_AWARE!, %s\n", __func__,
+ safe_strerror(errno));
+ exit(1);
+ }
+
+ /* need either valid or empty sets for both p and i.. */
+ assert(zprivs_state.syscaps_i && zprivs_state.syscaps_p);
+
+ /* we have caps, we have no need to ever change back the original user
+ * change real, effective and saved to the specified user.
+ */
+ /* 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)) {
+ fprintf(stderr, "%s: could not setreuid, %s\n",
+ __func__, safe_strerror(errno));
+ exit(1);
+ }
+ }
+
+ /* set the permitted set */
+ if (setppriv(PRIV_SET, PRIV_PERMITTED, zprivs_state.syscaps_p)) {
+ fprintf(stderr, "%s: error setting permitted set!, %s\n",
+ __func__, safe_strerror(errno));
+ exit(1);
+ }
+
+ /* set the inheritable set */
+ if (setppriv(PRIV_SET, PRIV_INHERITABLE, zprivs_state.syscaps_i)) {
+ fprintf(stderr, "%s: error setting inheritable set!, %s\n",
+ __func__, safe_strerror(errno));
+ exit(1);
+ }
+
+ /* we need a minimal basic set for 'effective', potentially for
+ * inheritable too */
+ minimal = zprivs_caps_minimal();
+
+ /* now set the effective set with a subset of basic privileges */
+ if (setppriv(PRIV_SET, PRIV_EFFECTIVE, minimal)) {
+ fprintf(stderr, "%s: error setting effective set!, %s\n",
+ __func__, safe_strerror(errno));
+ exit(1);
+ }
+
+ /* we'll use the minimal set as our working-storage privset */
+ zprivs_state.caps = minimal;
+
+ /* set methods for the caller to use */
+ zprivs->change = zprivs_change_caps;
+ zprivs->current_state = zprivs_state_caps;
}
-static void
-zprivs_caps_terminate (void)
+static void zprivs_caps_terminate(void)
{
- assert (zprivs_state.caps);
-
- /* clear all capabilities by using working-storage privset */
- setppriv (PRIV_SET, PRIV_EFFECTIVE, zprivs_state.caps);
- setppriv (PRIV_SET, PRIV_PERMITTED, zprivs_state.caps);
- setppriv (PRIV_SET, PRIV_INHERITABLE, zprivs_state.caps);
-
- /* free up private state */
- if (zprivs_state.syscaps_p)
- priv_freeset (zprivs_state.syscaps_p);
- if (zprivs_state.syscaps_i)
- priv_freeset (zprivs_state.syscaps_i);
-
- priv_freeset (zprivs_state.caps);
+ assert(zprivs_state.caps);
+
+ /* clear all capabilities by using working-storage privset */
+ setppriv(PRIV_SET, PRIV_EFFECTIVE, zprivs_state.caps);
+ setppriv(PRIV_SET, PRIV_PERMITTED, zprivs_state.caps);
+ setppriv(PRIV_SET, PRIV_INHERITABLE, zprivs_state.caps);
+
+ /* free up private state */
+ if (zprivs_state.syscaps_p)
+ priv_freeset(zprivs_state.syscaps_p);
+ if (zprivs_state.syscaps_i)
+ priv_freeset(zprivs_state.syscaps_i);
+
+ priv_freeset(zprivs_state.caps);
}
#else /* !HAVE_LCAPS && ! HAVE_SOLARIS_CAPABILITIES */
#error "Neither Solaris nor Linux capabilities, dazed and confused..."
#endif /* HAVE_LCAPS */
#endif /* HAVE_CAPABILITIES */
-int
-zprivs_change_uid (zebra_privs_ops_t op)
+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)
- return seteuid (zprivs_state.zuid);
- else
- return -1;
+ if (zprivs_state.zsuid == zprivs_state.zuid)
+ return 0;
+ 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)
+zebra_privs_current_t zprivs_state_uid(void)
{
- return ( (zprivs_state.zuid == geteuid()) ? ZPRIVS_LOWERED : ZPRIVS_RAISED);
+ return ((zprivs_state.zuid == geteuid()) ? ZPRIVS_LOWERED
+ : ZPRIVS_RAISED);
}
-int
-zprivs_change_null (zebra_privs_ops_t op)
+int zprivs_change_null(zebra_privs_ops_t op)
{
- return 0;
+ return 0;
}
-zebra_privs_current_t
-zprivs_state_null (void)
+zebra_privs_current_t zprivs_state_null(void)
{
- return zprivs_null_state;
+ 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)
+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;
+ 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 zebra_privs_t *_zprivs_raise(struct zebra_privs_t *privs,
+ const char *funcname)
+{
+ int save_errno = errno;
+
+ if (!privs)
+ return NULL;
+
+ errno = 0;
+ if (privs->change(ZPRIVS_RAISE)) {
+ zlog_err("%s: Failed to raise privileges (%s)",
+ funcname, safe_strerror(errno));
+ }
+ errno = save_errno;
+ privs->raised_in_funcname = funcname;
+ return privs;
+}
+
+void _zprivs_lower(struct zebra_privs_t **privs)
+{
+ int save_errno = errno;
+
+ if (!*privs)
+ return;
+
+ errno = 0;
+ if ((*privs)->change(ZPRIVS_LOWER)) {
+ zlog_err("%s: Failed to lower privileges (%s)",
+ (*privs)->raised_in_funcname, safe_strerror(errno));
+ }
+ errno = save_errno;
+ (*privs)->raised_in_funcname = NULL;
+ *privs = NULL;
+}
+
+void zprivs_preinit(struct zebra_privs_t *zprivs)
+{
+ struct passwd *pwentry = NULL;
+ struct group *grentry = NULL;
+
+ if (!zprivs) {
+ fprintf(stderr, "zprivs_init: called with NULL arg!\n");
+ 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)) {
+ zprivs->change = zprivs_change_null;
+ zprivs->current_state = zprivs_state_null;
+ return;
+ }
+
+ if (zprivs->user) {
+ 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->group) {
+ if ((grentry = getgrnam(zprivs->group)) == NULL) {
+ fprintf(stderr,
+ "privs_init: could not lookup group %s\n",
+ zprivs->group);
+ exit(1);
+ }
+
+ zprivs_state.zgid = grentry->gr_gid;
+ }
+}
+
+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)
- {
- fprintf (stderr, "zprivs_init: called with NULL arg!\n");
- 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) )
- {
- zprivs->change = zprivs_change_null;
- zprivs->current_state = zprivs_state_null;
- return;
- }
-
- if (zprivs->user)
- {
- 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->group)
- {
- if ( (grentry = getgrnam (zprivs->group)) == NULL )
- {
- fprintf (stderr, "privs_init: could not lookup group %s\n",
- zprivs->group);
- exit (1);
- }
-
- zprivs_state.zgid = grentry->gr_gid;
- }
-
- if (zprivs->user)
- {
- ngroups = sizeof(groups);
- if (getgrouplist (zprivs->user, zprivs_state.zgid, groups, &ngroups) < 0)
- {
- /* 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->vty_group)
- /* Add the vty_group to the supplementary groups so it can be chowned to */
- {
- if (zprivs_state.vtygrp == (gid_t)-1)
- {
- fprintf (stderr, "privs_init: could not lookup vty group %s\n",
- zprivs->vty_group);
- exit (1);
- }
-
- for ( i = 0; i < ngroups; i++ )
- if ( groups[i] == zprivs_state.vtygrp )
- {
- found++;
- break;
- }
-
- if (!found)
- {
- 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) )
- {
- fprintf (stderr, "zprivs_init: could not setregid, %s\n",
- safe_strerror (errno) );
- exit (1);
- }
- }
-
+ gid_t groups[NGROUPS_MAX];
+ int i, ngroups = 0;
+ int found = 0;
+
+ /* NULL privs */
+ if (!(zprivs->user || zprivs->group || zprivs->cap_num_p
+ || zprivs->cap_num_i))
+ return;
+
+ if (zprivs->user) {
+ ngroups = sizeof(groups);
+ if (getgrouplist(zprivs->user, zprivs_state.zgid, groups,
+ &ngroups)
+ < 0) {
+ /* 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->vty_group)
+ /* Add the vty_group to the supplementary groups so it can be chowned to
+ */
+ {
+ if (zprivs_state.vtygrp == (gid_t)-1) {
+ fprintf(stderr,
+ "privs_init: could not lookup vty group %s\n",
+ zprivs->vty_group);
+ exit(1);
+ }
+
+ for (i = 0; i < ngroups; i++)
+ if (groups[i] == zprivs_state.vtygrp) {
+ found++;
+ break;
+ }
+
+ if (!found) {
+ 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;
+ }
+ }
+
+ zprivs_state.zsuid = geteuid(); /* initial uid */
+ /* 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)) {
+ fprintf(stderr, "zprivs_init: could not setregid, %s\n",
+ safe_strerror(errno));
+ exit(1);
+ }
+ }
+
#ifdef HAVE_CAPABILITIES
- zprivs_caps_init (zprivs);
-#else /* !HAVE_CAPABILITIES */
- /* 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.
- *
- * This is not worth that much security wise, but all we can do.
- */
- zprivs_state.zsuid = geteuid();
- /* 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) )
- {
- fprintf (stderr, "privs_init (uid): could not setreuid, %s\n",
- safe_strerror (errno));
- exit (1);
- }
- }
-
- zprivs->change = zprivs_change_uid;
- zprivs->current_state = zprivs_state_uid;
+ zprivs_caps_init(zprivs);
+
+ /*
+ * If we have initialized the system with no requested
+ * capabilities, change will not have been set
+ * to anything by zprivs_caps_init, As such
+ * we should make sure that when we attempt
+ * to raize privileges that we actually have
+ * a do nothing function to call instead of a
+ * crash :).
+ */
+ if (!zprivs->change)
+ zprivs->change = zprivs_change_null;
+
+#else /* !HAVE_CAPABILITIES */
+ /* 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.
+ *
+ * This is not worth that much security wise, but all we can do.
+ */
+ zprivs_state.zsuid = geteuid();
+ /* 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)) {
+ fprintf(stderr,
+ "privs_init (uid): could not setreuid, %s\n",
+ safe_strerror(errno));
+ exit(1);
+ }
+ }
+
+ zprivs->change = zprivs_change_uid;
+ zprivs->current_state = zprivs_state_uid;
#endif /* HAVE_CAPABILITIES */
}
-void
-zprivs_terminate (struct zebra_privs_t *zprivs)
+void zprivs_terminate(struct zebra_privs_t *zprivs)
{
- if (!zprivs)
- {
- fprintf (stderr, "%s: no privs struct given, terminating", __func__);
- exit (0);
- }
-
+ if (!zprivs) {
+ fprintf(stderr, "%s: no privs struct given, terminating",
+ __func__);
+ exit(0);
+ }
+
#ifdef HAVE_CAPABILITIES
- zprivs_caps_terminate();
-#else /* !HAVE_CAPABILITIES */
- /* 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) )
- {
- fprintf (stderr, "privs_terminate: could not setreuid, %s",
- safe_strerror (errno) );
- exit (1);
- }
- }
+ if (zprivs->user || zprivs->group || zprivs->cap_num_p
+ || zprivs->cap_num_i)
+ zprivs_caps_terminate();
+#else /* !HAVE_CAPABILITIES */
+ /* 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)) {
+ fprintf(stderr,
+ "privs_terminate: could not setreuid, %s",
+ safe_strerror(errno));
+ exit(1);
+ }
+ }
#endif /* HAVE_LCAPS */
- zprivs->change = zprivs_change_null;
- zprivs->current_state = zprivs_state_null;
- zprivs_null_state = ZPRIVS_LOWERED;
- return;
+ zprivs->change = zprivs_change_null;
+ zprivs->current_state = zprivs_state_null;
+ zprivs_null_state = ZPRIVS_LOWERED;
+ return;
}
-void
-zprivs_get_ids(struct zprivs_ids_t *ids)
+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;
+ 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;
}