forked from Mirror/frr
2005-09-29 Paul Jakma <paul.jakma@sun.com>
* configure.ac: Add the test for Solaris least-privileges. Set defines for whether capabilities are supported and whether of the linux or solaris variety. Add missing-prototypes, missing-declarations, char-subscripts and cast-qual warnings to default cflags, cause Hasso enjoys warnings, and we really should clean the remaining ones up. (ie isisd..). * (*/*main.c) Update the zebra_capabilities_t arrays in the various daemons to match the changes made in lib/privs.h. * zebra.h: Solaris capabilities requires priv.h to be included. * privs.{c,h}: Add support for Solaris Least-Privileges. privs.h: Reduce some of the abstract capabilities, which do not have rough equivalents on both systems. Rename the net related caps to _NET, as they should have been in first place. (zprivs_terminate) should take the zebra_privs_t as argument so that it can update change pointer. Add an additional privilege state, ZPRIVS_UNKNOWN. * privs.c: (various capability functions) Add Solaris privileges variants. (zprivs_state) Use privs.c specific generic types to represent various capability/privilege related types, so that each can be typedef'd as appropriate on each platform. (zprivs_null_state) static added, to hold the state the null method should report (should be raised by default, and LOWERED if zprivs_terminate has been called) (zprivs_state_null) Report back the zprivs_null_state. (cap_map) Make it able to map abstract capability to multiple system capabilities. (zcaps2sys) Map to abstract capabilities to multiple system privileges/capabilities. (zprivs_init) move capability related init to seperate function, zprivs_caps_init. (zprivs_terminate) ditto, moved to zprivs_caps_terminate. Set the change_state callback to the NULL state, so the user can continue to run and use the callbacks.
This commit is contained in:
parent
e62178797d
commit
ceacedba22
11
ChangeLog
11
ChangeLog
|
@ -1,3 +1,14 @@
|
|||
2005-09-29 Paul Jakma <paul.jakma@sun.com>
|
||||
|
||||
* configure.ac: Add the test for Solaris least-privileges. Set
|
||||
defines for whether capabilities are supported and whether of
|
||||
the linux or solaris variety.
|
||||
Add missing-prototypes, missing-declarations, char-subscripts
|
||||
and cast-qual warnings to default cflags, cause Hasso enjoys warnings,
|
||||
and we really should clean the remaining ones up. (ie isisd..).
|
||||
* (*/*main.c) Update the zebra_capabilities_t arrays in the various
|
||||
daemons to match the changes made in lib/privs.h.
|
||||
|
||||
2005-09-19 Hasso Tepper <hasso at quagga.net>
|
||||
|
||||
* configure.ac: Test existance of strndup.
|
||||
|
|
|
@ -102,7 +102,7 @@ char *vty_addr = NULL;
|
|||
zebra_capabilities_t _caps_p [] =
|
||||
{
|
||||
ZCAP_BIND,
|
||||
ZCAP_RAW,
|
||||
ZCAP_NET_RAW,
|
||||
};
|
||||
|
||||
struct zebra_privs_t bgpd_privs =
|
||||
|
|
21
configure.ac
21
configure.ac
|
@ -5,7 +5,7 @@
|
|||
## Copyright (c) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
|
||||
## Portions Copyright (c) 2003 Paul Jakma <paul@dishone.st>
|
||||
##
|
||||
## $Id: configure.ac,v 1.112 2005/09/19 09:53:21 hasso Exp $
|
||||
## $Id: configure.ac,v 1.113 2005/09/29 14:39:32 paul Exp $
|
||||
AC_PREREQ(2.53)
|
||||
|
||||
AC_INIT(Quagga, 0.99.1, [http://bugzilla.quagga.net])
|
||||
|
@ -91,6 +91,8 @@ if test "x$cflags_specified" = "x" ; then
|
|||
CFLAGS="-Os -fno-omit-frame-pointer -g -Wall"
|
||||
CFLAGS="${CFLAGS} -Wsign-compare -Wpointer-arith"
|
||||
CFLAGS="${CFLAGS} -Wbad-function-cast -Wwrite-strings"
|
||||
CFLAGS="${CFLAGS} -Wmissing-prototypes -Wmissing-declarations"
|
||||
CFLAGS="${CFLAGS} -Wchar-subscripts -Wcast-qual"
|
||||
fi
|
||||
# TODO: conditionally addd -Wpacked if handled
|
||||
fi
|
||||
|
@ -1238,8 +1240,23 @@ if test "${enable_capabilities}" != "no"; then
|
|||
AC_CHECK_LIB(cap, cap_init,
|
||||
[AC_DEFINE(HAVE_LCAPS,1,Capabilities)
|
||||
LIBCAP="-lcap"
|
||||
]
|
||||
quagga_ac_lcaps="yes"]
|
||||
)
|
||||
else
|
||||
AC_CHECK_HEADERS(priv.h,
|
||||
[AC_MSG_CHECKING(Solaris style privileges are available)
|
||||
AC_TRY_COMPILE([#include <priv.h>],[getpflags(PRIV_AWARE);],
|
||||
[AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAVE_SOLARIS_CAPABILITIES,1,getpflags)
|
||||
quagga_ac_scaps="yes"],
|
||||
AC_MSG_RESULT(no)
|
||||
)
|
||||
]
|
||||
)
|
||||
fi
|
||||
if test x"${quagga_ac_scaps}" = x"yes" \
|
||||
-o x"${quagga_ac_lcaps}" = x"yes"; then
|
||||
AC_DEFINE(HAVE_CAPABILITIES,1,capabilities)
|
||||
fi
|
||||
fi
|
||||
AC_SUBST(LIBCAP)
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
|
||||
/* isisd privileges */
|
||||
zebra_capabilities_t _caps_p[] = {
|
||||
ZCAP_RAW,
|
||||
ZCAP_NET_RAW,
|
||||
ZCAP_BIND
|
||||
};
|
||||
|
||||
|
|
|
@ -1,3 +1,33 @@
|
|||
2005-09-29 Paul Jakma <paul.jakma@sun.com>
|
||||
|
||||
* zebra.h: Solaris capabilities requires priv.h to be included.
|
||||
* privs.{c,h}: Add support for Solaris Least-Privileges.
|
||||
privs.h: Reduce some of the abstract capabilities, which do
|
||||
not have rough equivalents on both systems. Rename the net
|
||||
related caps to _NET, as they should have been in first
|
||||
place.
|
||||
(zprivs_terminate) should take the zebra_privs_t as argument so
|
||||
that it can update change pointer.
|
||||
Add an additional privilege state, ZPRIVS_UNKNOWN.
|
||||
* privs.c: (various capability functions) Add
|
||||
Solaris privileges variants.
|
||||
(zprivs_state) Use privs.c specific generic types to
|
||||
represent various capability/privilege related types, so that
|
||||
each can be typedef'd as appropriate on each platform.
|
||||
(zprivs_null_state) static added, to hold the state the null
|
||||
method should report (should be raised by default, and
|
||||
LOWERED if zprivs_terminate has been called)
|
||||
(zprivs_state_null) Report back the zprivs_null_state.
|
||||
(cap_map) Make it able to map abstract capability to multiple
|
||||
system capabilities.
|
||||
(zcaps2sys) Map to abstract capabilities to multiple system
|
||||
privileges/capabilities.
|
||||
(zprivs_init) move capability related init to seperate
|
||||
function, zprivs_caps_init.
|
||||
(zprivs_terminate) ditto, moved to zprivs_caps_terminate.
|
||||
Set the change_state callback to the NULL state, so the
|
||||
user can continue to run and use the callbacks.
|
||||
|
||||
2005-09-29 Alain Ritoux <alain.ritoux@6wind.com>
|
||||
|
||||
* filer.c: show protocol name in filter_show()
|
||||
|
|
618
lib/privs.c
618
lib/privs.c
|
@ -2,6 +2,7 @@
|
|||
* Zebra privileges.
|
||||
*
|
||||
* Copyright (C) 2003 Paul Jakma.
|
||||
* Copyright (C) 2005 Sun Microsystems, Inc.
|
||||
*
|
||||
* This file is part of GNU Zebra.
|
||||
*
|
||||
|
@ -20,22 +21,55 @@
|
|||
* 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"
|
||||
|
||||
#ifdef HAVE_CAPABILITIES
|
||||
/* sort out some generic internal types for:
|
||||
*
|
||||
* privilege values (cap_value_t, priv_t) -> pvalue_t
|
||||
* privilege set (..., priv_set_t) -> pset_t
|
||||
* privilege working storage (cap_t, ...) -> pstorage_t
|
||||
*
|
||||
* values we think of as numeric (they're ints really, but we dont know)
|
||||
* 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;
|
||||
};
|
||||
typedef cap_value_t pvalue_t;
|
||||
typedef struct _pset pset_t;
|
||||
typedef cap_t pstorage_t;
|
||||
|
||||
#elif defined (HAVE_SOLARIS_CAPABILITIES)
|
||||
typedef priv_t pvalue_t;
|
||||
typedef priv_set_t pset_t;
|
||||
typedef priv_set_t *pstorage_t;
|
||||
#else /* neither LCAPS nor SOLARIS_CAPABILITIES */
|
||||
#error "HAVE_CAPABILITIES defined, but neither LCAPS nor Solaris Capabilties!"
|
||||
#endif /* HAVE_LCAPS */
|
||||
#endif /* HAVE_CAPABILITIES */
|
||||
|
||||
/* the default NULL state we report is RAISED, but could be LOWERED if
|
||||
* zprivs_terminate is called and the NULL handler is installed.
|
||||
*/
|
||||
static zebra_privs_current_t zprivs_null_state = ZPRIVS_RAISED;
|
||||
|
||||
/* 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 */
|
||||
#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 */
|
||||
|
@ -43,58 +77,103 @@ static struct _zprivs_t
|
|||
} zprivs_state;
|
||||
|
||||
/* externally exported but not directly accessed functions */
|
||||
#ifdef HAVE_LCAPS
|
||||
#ifdef HAVE_CAPABILITIES
|
||||
int zprivs_change_caps (zebra_privs_ops_t);
|
||||
zebra_privs_current_t zprivs_state_caps (void);
|
||||
#endif /* HAVE_LCAPS */
|
||||
#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);
|
||||
void zprivs_terminate (void);
|
||||
|
||||
#ifdef HAVE_LCAPS
|
||||
static int
|
||||
cap_map [ZCAP_MAX] =
|
||||
#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);
|
||||
|
||||
/* Map of Quagga abstract capabilities to system capabilities */
|
||||
static struct
|
||||
{
|
||||
[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,
|
||||
[ZCAP_DAC_OVERRIDE] = CAP_DAC_OVERRIDE,
|
||||
[ZCAP_READ_SEARCH] = CAP_DAC_READ_SEARCH,
|
||||
[ZCAP_SYS_ADMIN] = CAP_SYS_ADMIN,
|
||||
[ZCAP_FOWNER] = CAP_FOWNER
|
||||
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] = { 2, (pvalue_t []) { CAP_NET_BIND_SERVICE,
|
||||
CAP_NET_BROADCAST }, },
|
||||
[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 }, },
|
||||
[ZCAP_NET_ADMIN] = { 1, (pvalue_t []) { PRIV_SYS_NET_CONFIG }, },
|
||||
[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] = { 2, (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 cap_value_t *
|
||||
static pset_t *
|
||||
zcaps2sys (zebra_capabilities_t *zcaps, int num)
|
||||
{
|
||||
cap_value_t *syscaps;
|
||||
int i;
|
||||
pset_t *syscaps;
|
||||
int i, j = 0, count = 0;
|
||||
|
||||
if (!num)
|
||||
return NULL;
|
||||
|
||||
syscaps = (cap_value_t *) XCALLOC ( MTYPE_PRIVS,
|
||||
(sizeof(cap_value_t) * num) );
|
||||
if (!syscaps)
|
||||
|
||||
/* 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)
|
||||
{
|
||||
zlog_err ("zcap2sys: could not XCALLOC!");
|
||||
fprintf (stderr, "%s: could not allocate syscaps!", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i=0; i < num; i++)
|
||||
syscaps->caps = XCALLOC (MTYPE_PRIVS, (sizeof (pvalue_t) * count));
|
||||
|
||||
if (!syscaps->caps)
|
||||
{
|
||||
syscaps[i] = cap_map[zcaps[i]];
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -104,6 +183,11 @@ 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)
|
||||
|
@ -112,7 +196,9 @@ zprivs_change_caps (zebra_privs_ops_t op)
|
|||
return -1;
|
||||
|
||||
if ( !cap_set_flag (zprivs_state.caps, CAP_EFFECTIVE,
|
||||
zprivs_state.sys_num_p, zprivs_state.syscaps_p, cflag))
|
||||
zprivs_state.syscaps_p->num,
|
||||
zprivs_state.syscaps_p->caps,
|
||||
cflag))
|
||||
return cap_set_proc (zprivs_state.caps);
|
||||
return -1;
|
||||
}
|
||||
|
@ -122,21 +208,348 @@ 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.sys_num_p; i++)
|
||||
for (i=0; i < zprivs_state.syscaps_p->num; i++)
|
||||
{
|
||||
if ( cap_get_flag (zprivs_state.caps, zprivs_state.syscaps_p[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) );
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
#endif /* HAVE_LCAPS */
|
||||
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);
|
||||
}
|
||||
|
||||
if ( !zprivs_state.syscaps_p )
|
||||
{
|
||||
fprintf (stderr, "privs_init: capabilities enabled, "
|
||||
"but no capabilities supplied\n");
|
||||
}
|
||||
|
||||
if ( !(zprivs_state.caps = cap_init()) )
|
||||
{
|
||||
fprintf (stderr, "privs_init: failed to cap_init, %s\n",
|
||||
safe_strerror (errno));
|
||||
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) )
|
||||
{
|
||||
fprintf (stderr, "zprivs_init (cap): could not setreuid, %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) )
|
||||
{
|
||||
fprintf (stderr, "privs_init: initial cap_set_proc failed\n");
|
||||
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)
|
||||
{
|
||||
/* 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 */
|
||||
|
||||
/* 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
|
||||
*/
|
||||
|
||||
/* convert zebras privileges to system capabilities */
|
||||
static pset_t *
|
||||
zcaps2sys (zebra_capabilities_t *zcaps, int num)
|
||||
{
|
||||
pset_t *syscaps;
|
||||
int i, j = 0, count = 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)
|
||||
{
|
||||
|
||||
/* 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 caps!", __func__);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* to raise: copy original permitted into our working effective set
|
||||
* to lower: just clear the working effective set
|
||||
*/
|
||||
if (op == ZPRIVS_RAISE)
|
||||
priv_copyset (zprivs_state.syscaps_p, zprivs_state.caps);
|
||||
else if (op == ZPRIVS_LOWER)
|
||||
priv_emptyset (zprivs_state.caps);
|
||||
else
|
||||
return -1;
|
||||
|
||||
if (setppriv (PRIV_SET, PRIV_EFFECTIVE, zprivs_state.caps) != 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 result;
|
||||
pset_t *effective;
|
||||
|
||||
if ( (effective = priv_allocset()) == NULL)
|
||||
{
|
||||
fprintf (stderr, "%s: failed to get priv_allocset!\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_isemptyset (effective) == B_TRUE)
|
||||
result = ZPRIVS_LOWERED;
|
||||
else
|
||||
result = ZPRIVS_RAISED;
|
||||
}
|
||||
|
||||
if (effective)
|
||||
priv_freeset (effective);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
zprivs_caps_init (struct zebra_privs_t *zprivs)
|
||||
{
|
||||
pset_t *basic;
|
||||
pset_t *empty;
|
||||
|
||||
/* 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);
|
||||
|
||||
/* we need an empty set for 'effective', potentially for inheritable too */
|
||||
if ( (empty = priv_allocset()) == NULL)
|
||||
{
|
||||
fprintf (stderr, "%s: couldn't get empty set!\n", __func__);
|
||||
exit (1);
|
||||
}
|
||||
priv_emptyset (empty);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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 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) )
|
||||
{
|
||||
fprintf (stderr, "%s: could not setreuid, %s\n",
|
||||
__func__, safe_strerror (errno));
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
/* now clear the effective set and we're ready to go */
|
||||
if (setppriv (PRIV_SET, PRIV_EFFECTIVE, empty))
|
||||
{
|
||||
fprintf (stderr, "%s: error setting effective set!, %s\n", __func__,
|
||||
safe_strerror (errno) );
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* we'll use this as our working-storage privset */
|
||||
zprivs_state.caps = empty;
|
||||
|
||||
/* set methods for the caller to use */
|
||||
zprivs->change = zprivs_change_caps;
|
||||
zprivs->current_state = zprivs_state_caps;
|
||||
}
|
||||
|
||||
static void
|
||||
zprivs_caps_terminate (void)
|
||||
{
|
||||
assert (zprivs_state.caps);
|
||||
|
||||
/* clear all capabilities */
|
||||
priv_emptyset (zprivs_state.caps);
|
||||
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)
|
||||
{
|
||||
|
@ -164,10 +577,9 @@ zprivs_change_null (zebra_privs_ops_t op)
|
|||
zebra_privs_current_t
|
||||
zprivs_state_null (void)
|
||||
{
|
||||
return ZPRIVS_RAISED;
|
||||
return zprivs_null_state;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
zprivs_init(struct zebra_privs_t *zprivs)
|
||||
{
|
||||
|
@ -248,80 +660,14 @@ zprivs_init(struct zebra_privs_t *zprivs)
|
|||
}
|
||||
}
|
||||
|
||||
#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 )
|
||||
{
|
||||
fprintf (stderr, "privs_init: could not set PR_SET_KEEPCAPS, %s\n",
|
||||
safe_strerror (errno) );
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ( !zprivs_state.syscaps_p )
|
||||
{
|
||||
fprintf (stderr, "privs_init: capabilities enabled, but no capabilities supplied\n");
|
||||
}
|
||||
|
||||
if ( !(zprivs_state.caps = cap_init()) )
|
||||
{
|
||||
fprintf (stderr, "privs_init: failed to cap_init, %s\n",
|
||||
safe_strerror (errno));
|
||||
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) )
|
||||
{
|
||||
fprintf (stderr, "zprivs_init (cap): could not setreuid, %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.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);
|
||||
|
||||
/* 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 cleared. we'll raise the caps as
|
||||
* and when, and only when, they are needed.
|
||||
*/
|
||||
if ( cap_set_proc (zprivs_state.caps) )
|
||||
{
|
||||
fprintf (stderr, "privs_init: initial cap_set_proc failed\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* set methods for the caller to use */
|
||||
zprivs->change = zprivs_change_caps;
|
||||
zprivs->current_state = zprivs_state_caps;
|
||||
|
||||
#elif !defined(HAVE_LCAPS)
|
||||
#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();
|
||||
if ( zprivs_state.zuid )
|
||||
|
@ -336,43 +682,35 @@ zprivs_init(struct zebra_privs_t *zprivs)
|
|||
|
||||
zprivs->change = zprivs_change_uid;
|
||||
zprivs->current_state = zprivs_state_uid;
|
||||
#endif /* HAVE_LCAPS */
|
||||
#endif /* HAVE_CAPABILITIES */
|
||||
}
|
||||
|
||||
void
|
||||
zprivs_terminate (void)
|
||||
zprivs_terminate (struct zebra_privs_t *zprivs)
|
||||
{
|
||||
|
||||
#ifdef HAVE_LCAPS
|
||||
|
||||
if (zprivs_state.caps)
|
||||
cap_clear (zprivs_state.caps);
|
||||
|
||||
if ( cap_set_proc (zprivs_state.caps) )
|
||||
if (!zprivs)
|
||||
{
|
||||
zlog_err ("privs_terminate: cap_set_proc failed, %s",
|
||||
safe_strerror (errno) );
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (zprivs_state.sys_num_p)
|
||||
XFREE (MTYPE_PRIVS, zprivs_state.syscaps_p);
|
||||
fprintf (stderr, "%s: no privs struct given, terminating", __func__);
|
||||
exit (0);
|
||||
}
|
||||
|
||||
if (zprivs_state.sys_num_i)
|
||||
XFREE (MTYPE_PRIVS, zprivs_state.syscaps_i);
|
||||
|
||||
cap_free (zprivs_state.caps);
|
||||
#else
|
||||
#ifdef HAVE_CAPABILITIES
|
||||
zprivs_caps_terminate();
|
||||
#else /* !HAVE_CAPABILITIES */
|
||||
if (zprivs_state.zuid)
|
||||
{
|
||||
if ( setreuid (zprivs_state.zuid, zprivs_state.zuid) )
|
||||
{
|
||||
zlog_err ("privs_terminate: could not setreuid, %s",
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
13
lib/privs.h
13
lib/privs.h
|
@ -27,13 +27,11 @@
|
|||
/* list of zebra capabilities */
|
||||
typedef enum
|
||||
{
|
||||
ZCAP_SETGID,
|
||||
ZCAP_SETUID,
|
||||
ZCAP_SETID,
|
||||
ZCAP_BIND,
|
||||
ZCAP_BROADCAST,
|
||||
ZCAP_ADMIN,
|
||||
ZCAP_NET_ADMIN,
|
||||
ZCAP_SYS_ADMIN,
|
||||
ZCAP_RAW,
|
||||
ZCAP_NET_RAW,
|
||||
ZCAP_CHROOT,
|
||||
ZCAP_NICE,
|
||||
ZCAP_PTRACE,
|
||||
|
@ -46,7 +44,8 @@ typedef enum
|
|||
typedef enum
|
||||
{
|
||||
ZPRIVS_LOWERED,
|
||||
ZPRIVS_RAISED
|
||||
ZPRIVS_RAISED,
|
||||
ZPRIVS_UNKNOWN,
|
||||
} zebra_privs_current_t;
|
||||
|
||||
typedef enum
|
||||
|
@ -84,7 +83,7 @@ struct zprivs_ids_t
|
|||
/* initialise zebra privileges */
|
||||
extern void zprivs_init (struct zebra_privs_t *zprivs);
|
||||
/* drop all and terminate privileges */
|
||||
extern void zprivs_terminate (void);
|
||||
extern void zprivs_terminate (struct zebra_privs_t *);
|
||||
/* query for runtime uid's and gid's, eg vty needs this */
|
||||
extern void zprivs_get_ids(struct zprivs_ids_t *);
|
||||
|
||||
|
|
|
@ -120,6 +120,10 @@ typedef int socklen_t;
|
|||
#include <sys/prctl.h>
|
||||
#endif /* HAVE_LCAPS */
|
||||
|
||||
#ifdef HAVE_SOLARIS_CAPABILITIES
|
||||
#include <priv.h>
|
||||
#endif /* HAVE_SOLARIS_CAPABILITIES */
|
||||
|
||||
/* network include group */
|
||||
|
||||
#include <sys/socket.h>
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
/* ospf6d privileges */
|
||||
zebra_capabilities_t _caps_p [] =
|
||||
{
|
||||
ZCAP_RAW,
|
||||
ZCAP_NET_RAW,
|
||||
ZCAP_BIND
|
||||
};
|
||||
|
||||
|
|
|
@ -52,10 +52,9 @@
|
|||
/* ospfd privileges */
|
||||
zebra_capabilities_t _caps_p [] =
|
||||
{
|
||||
ZCAP_RAW,
|
||||
ZCAP_NET_RAW,
|
||||
ZCAP_BIND,
|
||||
ZCAP_BROADCAST,
|
||||
ZCAP_ADMIN,
|
||||
ZCAP_NET_ADMIN,
|
||||
};
|
||||
|
||||
struct zebra_privs_t ospfd_privs =
|
||||
|
|
|
@ -54,7 +54,7 @@ static struct option longopts[] =
|
|||
/* ripd privileges */
|
||||
zebra_capabilities_t _caps_p [] =
|
||||
{
|
||||
ZCAP_RAW,
|
||||
ZCAP_NET_RAW,
|
||||
ZCAP_BIND
|
||||
};
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ struct option longopts[] =
|
|||
/* ripngd privileges */
|
||||
zebra_capabilities_t _caps_p [] =
|
||||
{
|
||||
ZCAP_RAW,
|
||||
ZCAP_NET_RAW,
|
||||
ZCAP_BIND
|
||||
};
|
||||
|
||||
|
|
|
@ -87,9 +87,9 @@ struct option longopts[] =
|
|||
|
||||
zebra_capabilities_t _caps_p [] =
|
||||
{
|
||||
ZCAP_ADMIN,
|
||||
ZCAP_NET_ADMIN,
|
||||
ZCAP_SYS_ADMIN,
|
||||
ZCAP_RAW,
|
||||
ZCAP_NET_RAW,
|
||||
};
|
||||
|
||||
/* zebra privileges to run with */
|
||||
|
|
Loading…
Reference in a new issue