--- embedaddon/quagga/lib/privs.c 2012/02/21 17:26:12 1.1.1.1 +++ embedaddon/quagga/lib/privs.c 2016/11/02 10:09:11 1.1.1.2 @@ -2,7 +2,7 @@ * Zebra privileges. * * Copyright (C) 2003 Paul Jakma. - * Copyright (C) 2005 Sun Microsystems, Inc. + * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. * * This file is part of GNU Zebra. * @@ -47,7 +47,7 @@ struct _pset { 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; @@ -56,7 +56,7 @@ typedef priv_set_t *pstorage_t; #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. */ @@ -102,8 +102,7 @@ static struct #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_BIND] = { 2, (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, }, }, @@ -139,7 +138,7 @@ static struct [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 */ @@ -299,7 +298,21 @@ zprivs_caps_init (struct zebra_privs_t *zprivs) */ if ( cap_set_proc (zprivs_state.caps) ) { - fprintf (stderr, "privs_init: initial cap_set_proc failed\n"); + 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); + + 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 : "???"); + exit (1); } @@ -339,7 +352,7 @@ zprivs_caps_terminate (void) cap_free (zprivs_state.caps); } #elif defined (HAVE_SOLARIS_CAPABILITIES) /* !HAVE_LCAPS */ - + /* Solaris specific capability/privilege methods * * Resources: @@ -348,6 +361,26 @@ zprivs_caps_terminate (void) * - http://blogs.sun.com/roller/page/gbrunett?entry=privilege_enabling_set_id_programs1 */ +static pset_t * +zprivs_caps_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); + } + + /* 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; +} + /* convert zebras privileges to system capabilities */ static pset_t * zcaps2sys (zebra_capabilities_t *zcaps, int num) @@ -376,26 +409,34 @@ zcaps2sys (zebra_capabilities_t *zcaps, int num) 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 into our working effective set - * to lower: just clear the working effective set + + /* 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) - priv_copyset (zprivs_state.syscaps_p, zprivs_state.caps); + privset = zprivs_state.syscaps_p; else if (op == ZPRIVS_LOWER) - priv_emptyset (zprivs_state.caps); + privset = zprivs_state.caps; else return -1; - if (setppriv (PRIV_SET, PRIV_EFFECTIVE, zprivs_state.caps) != 0) + if (setppriv (PRIV_SET, PRIV_EFFECTIVE, privset) != 0) return -1; return 0; @@ -423,15 +464,15 @@ zprivs_state_caps (void) } else { - if (priv_isemptyset (effective) == B_TRUE) + 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_RAISED; + result = ZPRIVS_UNKNOWN; } - if (effective) - priv_freeset (effective); - + priv_freeset (effective); return result; } @@ -439,7 +480,7 @@ static void zprivs_caps_init (struct zebra_privs_t *zprivs) { pset_t *basic; - pset_t *empty; + pset_t *minimal; /* the specified sets */ zprivs_state.syscaps_p = zcaps2sys (zprivs->caps_p, zprivs->cap_num_p); @@ -467,14 +508,6 @@ zprivs_caps_init (struct zebra_privs_t *zprivs) 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 */ @@ -517,16 +550,19 @@ zprivs_caps_init (struct zebra_privs_t *zprivs) exit (1); } - /* now clear the effective set and we're ready to go */ - if (setppriv (PRIV_SET, PRIV_EFFECTIVE, empty)) + /* 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 this as our working-storage privset */ - zprivs_state.caps = empty; + /* 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; @@ -538,8 +574,7 @@ zprivs_caps_terminate (void) { assert (zprivs_state.caps); - /* clear all capabilities */ - priv_emptyset (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); @@ -556,7 +591,7 @@ zprivs_caps_terminate (void) #error "Neither Solaris nor Linux capabilities, dazed and confused..." #endif /* HAVE_LCAPS */ #endif /* HAVE_CAPABILITIES */ - + int zprivs_change_uid (zebra_privs_ops_t op) { @@ -587,11 +622,48 @@ 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; if (!zprivs) { @@ -610,33 +682,59 @@ zprivs_init(struct zebra_privs_t *zprivs) if (zprivs->user) { - if ( (pwentry = getpwnam (zprivs->user)) ) + if ( (pwentry = getpwnam (zprivs->user)) == NULL ) { - zprivs_state.zuid = pwentry->pw_uid; - } - else - { /* 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 ( (ngroups = 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 ( (grentry = getgrnam (zprivs->vty_group)) ) { zprivs_state.vtygrp = grentry->gr_gid; - if ( setgroups (1, &zprivs_state.vtygrp) ) + + for ( i = 0; i < ngroups; i++ ) + if ( groups[i] == zprivs_state.vtygrp ) + break; + + if ( i >= ngroups && ngroups < (int) ZEBRA_NUM_OF(groups) ) { - fprintf (stderr, "privs_init: could not setgroups, %s\n", - safe_strerror (errno) ); - exit (1); - } + groups[i] = zprivs_state.vtygrp; + } } else { @@ -645,19 +743,19 @@ zprivs_init(struct zebra_privs_t *zprivs) exit (1); } } - - if (zprivs->group) + + if (ngroups) { - if ( (grentry = getgrnam (zprivs->group)) ) + if ( setgroups (ngroups, groups) ) { - zprivs_state.zgid = grentry->gr_gid; - } - else - { - fprintf (stderr, "privs_init: could not lookup group %s\n", - zprivs->group); + fprintf (stderr, "privs_init: could not setgroups, %s\n", + safe_strerror (errno) ); exit (1); } + } + + if (zprivs_state.zgid) + { /* change group now, forever. uid we do later */ if ( setregid (zprivs_state.zgid, zprivs_state.zgid) ) {