version 1.1.1.1, 2012/02/21 17:26:12
|
version 1.1.1.2, 2016/11/02 10:09:11
|
Line 2
|
Line 2
|
* Zebra privileges. |
* Zebra privileges. |
* |
* |
* Copyright (C) 2003 Paul Jakma. |
* 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. |
* This file is part of GNU Zebra. |
* |
* |
Line 47 struct _pset {
|
Line 47 struct _pset {
|
typedef cap_value_t pvalue_t; |
typedef cap_value_t pvalue_t; |
typedef struct _pset pset_t; |
typedef struct _pset pset_t; |
typedef cap_t pstorage_t; |
typedef cap_t pstorage_t; |
| |
#elif defined (HAVE_SOLARIS_CAPABILITIES) |
#elif defined (HAVE_SOLARIS_CAPABILITIES) |
typedef priv_t pvalue_t; |
typedef priv_t pvalue_t; |
typedef priv_set_t pset_t; |
typedef priv_set_t pset_t; |
Line 56 typedef priv_set_t *pstorage_t;
|
Line 56 typedef priv_set_t *pstorage_t;
|
#error "HAVE_CAPABILITIES defined, but neither LCAPS nor Solaris Capabilties!" |
#error "HAVE_CAPABILITIES defined, but neither LCAPS nor Solaris Capabilties!" |
#endif /* HAVE_LCAPS */ |
#endif /* HAVE_LCAPS */ |
#endif /* HAVE_CAPABILITIES */ |
#endif /* HAVE_CAPABILITIES */ |
| |
/* the default NULL state we report is RAISED, but could be LOWERED if |
/* the default NULL state we report is RAISED, but could be LOWERED if |
* zprivs_terminate is called and the NULL handler is installed. |
* zprivs_terminate is called and the NULL handler is installed. |
*/ |
*/ |
Line 102 static struct
|
Line 102 static struct
|
#ifdef HAVE_LCAPS /* Quagga -> Linux capabilities mappings */ |
#ifdef HAVE_LCAPS /* Quagga -> Linux capabilities mappings */ |
[ZCAP_SETID] = { 2, (pvalue_t []) { CAP_SETGID, |
[ZCAP_SETID] = { 2, (pvalue_t []) { CAP_SETGID, |
CAP_SETUID }, }, |
CAP_SETUID }, }, |
[ZCAP_BIND] = { 2, (pvalue_t []) { CAP_NET_BIND_SERVICE, | [ZCAP_BIND] = { 2, (pvalue_t []) { CAP_NET_BIND_SERVICE }, }, |
CAP_NET_BROADCAST }, }, | |
[ZCAP_NET_ADMIN] = { 1, (pvalue_t []) { CAP_NET_ADMIN }, }, |
[ZCAP_NET_ADMIN] = { 1, (pvalue_t []) { CAP_NET_ADMIN }, }, |
[ZCAP_NET_RAW] = { 1, (pvalue_t []) { CAP_NET_RAW }, }, |
[ZCAP_NET_RAW] = { 1, (pvalue_t []) { CAP_NET_RAW }, }, |
[ZCAP_CHROOT] = { 1, (pvalue_t []) { CAP_SYS_CHROOT, }, }, |
[ZCAP_CHROOT] = { 1, (pvalue_t []) { CAP_SYS_CHROOT, }, }, |
Line 139 static struct
|
Line 138 static struct
|
[ZCAP_FOWNER] = { 1, (pvalue_t []) { PRIV_FILE_OWNER }, }, |
[ZCAP_FOWNER] = { 1, (pvalue_t []) { PRIV_FILE_OWNER }, }, |
#endif /* HAVE_SOLARIS_CAPABILITIES */ |
#endif /* HAVE_SOLARIS_CAPABILITIES */ |
}; |
}; |
| |
#ifdef HAVE_LCAPS |
#ifdef HAVE_LCAPS |
/* Linux forms of capabilities methods */ |
/* Linux forms of capabilities methods */ |
/* convert zebras privileges to system capabilities */ |
/* convert zebras privileges to system capabilities */ |
Line 299 zprivs_caps_init (struct zebra_privs_t *zprivs)
|
Line 298 zprivs_caps_init (struct zebra_privs_t *zprivs)
|
*/ |
*/ |
if ( cap_set_proc (zprivs_state.caps) ) |
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); |
exit (1); |
} |
} |
|
|
Line 339 zprivs_caps_terminate (void)
|
Line 352 zprivs_caps_terminate (void)
|
cap_free (zprivs_state.caps); |
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: |
* Resources: |
Line 348 zprivs_caps_terminate (void)
|
Line 361 zprivs_caps_terminate (void)
|
* - 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 () |
|
{ |
|
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 */ |
/* convert zebras privileges to system capabilities */ |
static pset_t * |
static pset_t * |
zcaps2sys (zebra_capabilities_t *zcaps, int num) |
zcaps2sys (zebra_capabilities_t *zcaps, int num) |
Line 376 zcaps2sys (zebra_capabilities_t *zcaps, int num)
|
Line 409 zcaps2sys (zebra_capabilities_t *zcaps, int num)
|
int |
int |
zprivs_change_caps (zebra_privs_ops_t op) |
zprivs_change_caps (zebra_privs_ops_t op) |
{ |
{ |
|
pset_t *privset; |
|
|
/* should be no possibility of being called without valid caps */ |
/* should be no possibility of being called without valid caps */ |
assert (zprivs_state.syscaps_p); |
assert (zprivs_state.syscaps_p); |
if (!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__); |
fprintf (stderr, "%s: Eek, missing caps!", __func__); |
exit (1); |
exit (1); |
} |
} |
| |
/* to raise: copy original permitted into our working effective set | /* to raise: copy original permitted as our working effective set |
* to lower: just clear the working effective set | * to lower: copy regular effective set stored in zprivs_state.caps |
*/ |
*/ |
if (op == ZPRIVS_RAISE) |
if (op == ZPRIVS_RAISE) |
priv_copyset (zprivs_state.syscaps_p, zprivs_state.caps); | privset = zprivs_state.syscaps_p; |
else if (op == ZPRIVS_LOWER) |
else if (op == ZPRIVS_LOWER) |
priv_emptyset (zprivs_state.caps); | privset = zprivs_state.caps; |
else |
else |
return -1; |
return -1; |
|
|
if (setppriv (PRIV_SET, PRIV_EFFECTIVE, zprivs_state.caps) != 0) | if (setppriv (PRIV_SET, PRIV_EFFECTIVE, privset) != 0) |
return -1; |
return -1; |
|
|
return 0; |
return 0; |
Line 423 zprivs_state_caps (void)
|
Line 464 zprivs_state_caps (void)
|
} |
} |
else |
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; |
result = ZPRIVS_LOWERED; |
else |
else |
result = ZPRIVS_RAISED; | result = ZPRIVS_UNKNOWN; |
} |
} |
|
|
if (effective) | priv_freeset (effective); |
priv_freeset (effective); | |
| |
return result; |
return result; |
} |
} |
|
|
Line 439 static void
|
Line 480 static void
|
zprivs_caps_init (struct zebra_privs_t *zprivs) |
zprivs_caps_init (struct zebra_privs_t *zprivs) |
{ |
{ |
pset_t *basic; |
pset_t *basic; |
pset_t *empty; | pset_t *minimal; |
|
|
/* the specified sets */ |
/* the specified sets */ |
zprivs_state.syscaps_p = zcaps2sys (zprivs->caps_p, zprivs->cap_num_p); |
zprivs_state.syscaps_p = zcaps2sys (zprivs->caps_p, zprivs->cap_num_p); |
Line 467 zprivs_caps_init (struct zebra_privs_t *zprivs)
|
Line 508 zprivs_caps_init (struct zebra_privs_t *zprivs)
|
priv_union (basic, zprivs_state.syscaps_p); |
priv_union (basic, zprivs_state.syscaps_p); |
priv_freeset (basic); |
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! |
/* Hey kernel, we know about privileges! |
* this isn't strictly required, use of setppriv should have same effect |
* this isn't strictly required, use of setppriv should have same effect |
*/ |
*/ |
Line 517 zprivs_caps_init (struct zebra_privs_t *zprivs)
|
Line 550 zprivs_caps_init (struct zebra_privs_t *zprivs)
|
exit (1); |
exit (1); |
} |
} |
|
|
/* now clear the effective set and we're ready to go */ | /* we need a minimal basic set for 'effective', potentially for inheritable too */ |
if (setppriv (PRIV_SET, PRIV_EFFECTIVE, empty)) | 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__, |
fprintf (stderr, "%s: error setting effective set!, %s\n", __func__, |
safe_strerror (errno) ); |
safe_strerror (errno) ); |
exit (1); |
exit (1); |
} |
} |
|
|
/* we'll use this as our working-storage privset */ | /* we'll use the minimal set as our working-storage privset */ |
zprivs_state.caps = empty; | zprivs_state.caps = minimal; |
|
|
/* set methods for the caller to use */ |
/* set methods for the caller to use */ |
zprivs->change = zprivs_change_caps; |
zprivs->change = zprivs_change_caps; |
Line 538 zprivs_caps_terminate (void)
|
Line 574 zprivs_caps_terminate (void)
|
{ |
{ |
assert (zprivs_state.caps); |
assert (zprivs_state.caps); |
|
|
/* clear all capabilities */ | /* clear all capabilities by using working-storage privset */ |
priv_emptyset (zprivs_state.caps); | |
setppriv (PRIV_SET, PRIV_EFFECTIVE, zprivs_state.caps); |
setppriv (PRIV_SET, PRIV_EFFECTIVE, zprivs_state.caps); |
setppriv (PRIV_SET, PRIV_PERMITTED, zprivs_state.caps); |
setppriv (PRIV_SET, PRIV_PERMITTED, zprivs_state.caps); |
setppriv (PRIV_SET, PRIV_INHERITABLE, zprivs_state.caps); |
setppriv (PRIV_SET, PRIV_INHERITABLE, zprivs_state.caps); |
Line 556 zprivs_caps_terminate (void)
|
Line 591 zprivs_caps_terminate (void)
|
#error "Neither Solaris nor Linux capabilities, dazed and confused..." |
#error "Neither Solaris nor Linux capabilities, dazed and confused..." |
#endif /* HAVE_LCAPS */ |
#endif /* HAVE_LCAPS */ |
#endif /* HAVE_CAPABILITIES */ |
#endif /* HAVE_CAPABILITIES */ |
| |
int |
int |
zprivs_change_uid (zebra_privs_ops_t op) |
zprivs_change_uid (zebra_privs_ops_t op) |
{ |
{ |
Line 587 zprivs_state_null (void)
|
Line 622 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) |
|
{ |
|
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 |
void |
zprivs_init(struct zebra_privs_t *zprivs) |
zprivs_init(struct zebra_privs_t *zprivs) |
{ |
{ |
struct passwd *pwentry = NULL; |
struct passwd *pwentry = NULL; |
struct group *grentry = NULL; |
struct group *grentry = NULL; |
|
gid_t groups[NGROUPS_MAX]; |
|
int i, ngroups = 0; |
|
|
if (!zprivs) |
if (!zprivs) |
{ |
{ |
Line 610 zprivs_init(struct zebra_privs_t *zprivs)
|
Line 682 zprivs_init(struct zebra_privs_t *zprivs)
|
|
|
if (zprivs->user) |
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 */ |
/* cant use log.h here as it depends on vty */ |
fprintf (stderr, "privs_init: could not lookup user %s\n", |
fprintf (stderr, "privs_init: could not lookup user %s\n", |
zprivs->user); |
zprivs->user); |
exit (1); |
exit (1); |
} |
} |
|
|
|
zprivs_state.zuid = pwentry->pw_uid; |
|
zprivs_state.zgid = pwentry->pw_gid; |
} |
} |
|
|
grentry = NULL; |
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) |
if (zprivs->vty_group) |
/* Add the vty_group to the supplementary groups so it can be chowned to */ |
/* Add the vty_group to the supplementary groups so it can be chowned to */ |
{ |
{ |
if ( (grentry = getgrnam (zprivs->vty_group)) ) |
if ( (grentry = getgrnam (zprivs->vty_group)) ) |
{ |
{ |
zprivs_state.vtygrp = grentry->gr_gid; |
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", | groups[i] = zprivs_state.vtygrp; |
safe_strerror (errno) ); | } |
exit (1); | |
} | |
} |
} |
else |
else |
{ |
{ |
Line 645 zprivs_init(struct zebra_privs_t *zprivs)
|
Line 743 zprivs_init(struct zebra_privs_t *zprivs)
|
exit (1); |
exit (1); |
} |
} |
} |
} |
| |
if (zprivs->group) | if (ngroups) |
{ |
{ |
if ( (grentry = getgrnam (zprivs->group)) ) | if ( setgroups (ngroups, groups) ) |
{ |
{ |
zprivs_state.zgid = grentry->gr_gid; | fprintf (stderr, "privs_init: could not setgroups, %s\n", |
} | safe_strerror (errno) ); |
else | |
{ | |
fprintf (stderr, "privs_init: could not lookup group %s\n", | |
zprivs->group); | |
exit (1); |
exit (1); |
} |
} |
|
} |
|
|
|
if (zprivs_state.zgid) |
|
{ |
/* change group now, forever. uid we do later */ |
/* change group now, forever. uid we do later */ |
if ( setregid (zprivs_state.zgid, zprivs_state.zgid) ) |
if ( setregid (zprivs_state.zgid, zprivs_state.zgid) ) |
{ |
{ |