diff options
Diffstat (limited to 'lib/privs.c')
-rw-r--r-- | lib/privs.c | 203 |
1 files changed, 159 insertions, 44 deletions
diff --git a/lib/privs.c b/lib/privs.c index 69606f57..68757340 100644 --- a/lib/privs.c +++ b/lib/privs.c @@ -25,6 +25,10 @@ #include "log.h" #include "privs.h" #include "memory.h" +#include "qpthreads.h" + +/* Needs to be qpthread safe */ +static qpt_mutex_t* mx = NULL; #ifdef HAVE_CAPABILITIES /* sort out some generic internal types for: @@ -61,6 +65,7 @@ typedef priv_set_t *pstorage_t; * zprivs_terminate is called and the NULL handler is installed. */ static zebra_privs_current_t zprivs_null_state = ZPRIVS_RAISED; +static int raise_count = 0; /* keep raised until all pthreads have lowered */ /* internal privileges state */ static struct _zprivs_t @@ -187,25 +192,42 @@ int zprivs_change_caps (zebra_privs_ops_t op) { cap_flag_value_t cflag; - + int result = 0; + int change = 0; + + qpt_mutex_lock(mx); + /* 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); - + { + qpt_mutex_unlock(mx); + exit (1); + } + if (op == ZPRIVS_RAISE) - cflag = CAP_SET; + { + cflag = CAP_SET; + change = (raise_count++ == 0); + } else if (op == ZPRIVS_LOWER) - cflag = CAP_CLEAR; + { + cflag = CAP_CLEAR; + change = (--raise_count == 0); + } else - return -1; + { + result = -1; + } - if ( !cap_set_flag (zprivs_state.caps, CAP_EFFECTIVE, + if ( change && !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; + result = cap_set_proc (zprivs_state.caps); + + qpt_mutex_unlock(mx); + return result; } zebra_privs_current_t @@ -213,11 +235,17 @@ zprivs_state_caps (void) { int i; cap_flag_value_t val; + zebra_privs_current_t result = ZPRIVS_LOWERED; + + qpt_mutex_lock(mx); /* 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); + { + qpt_mutex_unlock(mx); + exit (1); + } for (i=0; i < zprivs_state.syscaps_p->num; i++) { @@ -226,12 +254,18 @@ zprivs_state_caps (void) { zlog_warn ("zprivs_state_caps: could not cap_get_flag, %s", safe_strerror (errno) ); - return ZPRIVS_UNKNOWN; + result = ZPRIVS_UNKNOWN; + break; } if (val == CAP_SET) - return ZPRIVS_RAISED; + { + result = ZPRIVS_RAISED; + break; + } } - return ZPRIVS_LOWERED; + + qpt_mutex_unlock(mx); + return result; } static void @@ -376,12 +410,16 @@ zcaps2sys (zebra_capabilities_t *zcaps, int num) int zprivs_change_caps (zebra_privs_ops_t op) { + int result = 0; + qpt_mutex_lock(mx); + /* 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__); + qpt_mutex_unlock(mx); exit (1); } @@ -389,49 +427,66 @@ zprivs_change_caps (zebra_privs_ops_t op) * to lower: just clear the working effective set */ if (op == ZPRIVS_RAISE) - priv_copyset (zprivs_state.syscaps_p, zprivs_state.caps); + { + if (raise_count++ == 0) + { + priv_copyset (zprivs_state.syscaps_p, zprivs_state.caps); + if (setppriv (PRIV_SET, PRIV_EFFECTIVE, zprivs_state.caps) != 0) + result = -1; + } + } else if (op == ZPRIVS_LOWER) - priv_emptyset (zprivs_state.caps); + { + if (--raise_count == 0) + { + priv_emptyset (zprivs_state.caps); + if (setppriv (PRIV_SET, PRIV_EFFECTIVE, zprivs_state.caps) != 0) + result = -1; + } + } else - return -1; + result = -1; - if (setppriv (PRIV_SET, PRIV_EFFECTIVE, zprivs_state.caps) != 0) - return -1; + qpt_mutex_unlock(mx); - return 0; + return result; } /* Retrieve current privilege state, is it RAISED or LOWERED? */ zebra_privs_current_t zprivs_state_caps (void) { - zebra_privs_current_t result; + zebra_privs_current_t result = ZPRIVS_UNKNOWN; pset_t *effective; + qpt_mutex_lock(mx); + 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_isemptyset (effective) == B_TRUE) - result = ZPRIVS_LOWERED; + + if (getppriv (PRIV_EFFECTIVE, effective)) + { + fprintf (stderr, "%s: failed to get state! %s\n", __func__, + safe_strerror (errno)); + } else - result = ZPRIVS_RAISED; + { + if (priv_isemptyset (effective) == B_TRUE) + result = ZPRIVS_LOWERED; + else + result = ZPRIVS_RAISED; + } + + if (effective) + priv_freeset (effective); } - if (effective) - priv_freeset (effective); - + qpt_mutex_unlock(mx); return result; } @@ -560,19 +615,42 @@ zprivs_caps_terminate (void) int zprivs_change_uid (zebra_privs_ops_t op) { + int result = 0; + + qpt_mutex_lock(mx); if (op == ZPRIVS_RAISE) - return seteuid (zprivs_state.zsuid); + { + if (raise_count++ == 0) + { + result = seteuid (zprivs_state.zsuid); + } + } else if (op == ZPRIVS_LOWER) - return seteuid (zprivs_state.zuid); + { + if (--raise_count == 0) + { + result = seteuid (zprivs_state.zuid); + } + } else - return -1; + { + result = -1; + } + + qpt_mutex_unlock(mx); + return result; } zebra_privs_current_t zprivs_state_uid (void) { - return ( (zprivs_state.zuid == geteuid()) ? ZPRIVS_LOWERED : ZPRIVS_RAISED); + zebra_privs_current_t result; + + qpt_mutex_lock(mx); + result = ( (zprivs_state.zuid == geteuid()) ? ZPRIVS_LOWERED : ZPRIVS_RAISED); + qpt_mutex_unlock(mx); + return result; } int @@ -584,7 +662,25 @@ zprivs_change_null (zebra_privs_ops_t op) zebra_privs_current_t zprivs_state_null (void) { - return zprivs_null_state; + int result; + + qpt_mutex_lock(mx); + result = zprivs_null_state; + qpt_mutex_unlock(mx); + return result; +} + +void +zprivs_init_r(struct zebra_privs_t *zprivs) +{ + mx = qpt_mutex_init(mx, qpt_mutex_quagga); + zprivs_init(zprivs); +} + +void +zprivs_destroy_r(void) +{ + mx = qpt_mutex_destroy(mx, 1); } void @@ -599,12 +695,15 @@ zprivs_init(struct zebra_privs_t *zprivs) exit (1); } + qpt_mutex_lock(mx); + /* 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; + qpt_mutex_unlock(mx); return; } @@ -619,6 +718,7 @@ zprivs_init(struct zebra_privs_t *zprivs) /* cant use log.h here as it depends on vty */ fprintf (stderr, "privs_init: could not lookup user %s\n", zprivs->user); + qpt_mutex_unlock(mx); exit (1); } } @@ -635,6 +735,7 @@ zprivs_init(struct zebra_privs_t *zprivs) { fprintf (stderr, "privs_init: could not setgroups, %s\n", safe_strerror (errno) ); + qpt_mutex_unlock(mx); exit (1); } } @@ -642,6 +743,7 @@ zprivs_init(struct zebra_privs_t *zprivs) { fprintf (stderr, "privs_init: could not lookup vty group %s\n", zprivs->vty_group); + qpt_mutex_unlock(mx); exit (1); } } @@ -656,6 +758,7 @@ zprivs_init(struct zebra_privs_t *zprivs) { fprintf (stderr, "privs_init: could not lookup group %s\n", zprivs->group); + qpt_mutex_unlock(mx); exit (1); } /* change group now, forever. uid we do later */ @@ -663,6 +766,7 @@ zprivs_init(struct zebra_privs_t *zprivs) { fprintf (stderr, "zprivs_init: could not setregid, %s\n", safe_strerror (errno) ); + qpt_mutex_unlock(mx); exit (1); } } @@ -671,7 +775,7 @@ zprivs_init(struct zebra_privs_t *zprivs) 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 + * and change euid back to saved uid (who we presume has all necessary * privileges) whenever we are asked to raise our privileges. * * This is not worth that much security wise, but all we can do. @@ -683,6 +787,7 @@ zprivs_init(struct zebra_privs_t *zprivs) { fprintf (stderr, "privs_init (uid): could not setreuid, %s\n", safe_strerror (errno)); + qpt_mutex_unlock(mx); exit (1); } } @@ -690,6 +795,8 @@ zprivs_init(struct zebra_privs_t *zprivs) zprivs->change = zprivs_change_uid; zprivs->current_state = zprivs_state_uid; #endif /* HAVE_CAPABILITIES */ + + qpt_mutex_unlock(mx); } void @@ -701,6 +808,8 @@ zprivs_terminate (struct zebra_privs_t *zprivs) exit (0); } + qpt_mutex_lock(mx); + #ifdef HAVE_CAPABILITIES zprivs_caps_terminate(); #else /* !HAVE_CAPABILITIES */ @@ -710,6 +819,7 @@ zprivs_terminate (struct zebra_privs_t *zprivs) { fprintf (stderr, "privs_terminate: could not setreuid, %s", safe_strerror (errno) ); + qpt_mutex_unlock(mx); exit (1); } } @@ -718,20 +828,25 @@ zprivs_terminate (struct zebra_privs_t *zprivs) zprivs->change = zprivs_change_null; zprivs->current_state = zprivs_state_null; zprivs_null_state = ZPRIVS_LOWERED; + raise_count = 0; + + qpt_mutex_unlock(mx); return; } void zprivs_get_ids(struct zprivs_ids_t *ids) { + qpt_mutex_lock(mx); - ids->uid_priv = getuid(); - (zprivs_state.zuid) ? (ids->uid_normal = zprivs_state.zuid) + 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) + (zprivs_state.zgid) ? (ids->gid_normal = zprivs_state.zgid) : (ids->gid_normal = -1); - (zprivs_state.vtygrp) ? (ids->gid_vty = zprivs_state.vtygrp) + (zprivs_state.vtygrp) ? (ids->gid_vty = zprivs_state.vtygrp) : (ids->gid_vty = -1); + qpt_mutex_unlock(mx); return; } |