diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2012-06-05 02:09:04 +0400 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2012-06-05 02:09:04 +0400 |
commit | 415ee7d6e47dcb3e0906a7bebc6d52ab8ed899da (patch) | |
tree | f7773ad82023c8616b339d84faa4bb7643af0311 /sysdeps/unix/sysv/solaris2/kopensolaris-gnu/privP.c | |
parent | 3cc0cd4c5b3bed6f7d9aff26322d505785e11aa9 (diff) | |
download | glibc-415ee7d6e47dcb3e0906a7bebc6d52ab8ed899da.tar.gz |
Merged changes from kopensolaris-gnu project
http://git.csclub.uwaterloo.ca/?p=kopensolaris-gnu/glibc.git
Commits from 9157319 to bad8ac8.
This is only partial patch, some changes to not apply
and will be resovled and committed next.
Diffstat (limited to 'sysdeps/unix/sysv/solaris2/kopensolaris-gnu/privP.c')
-rw-r--r-- | sysdeps/unix/sysv/solaris2/kopensolaris-gnu/privP.c | 285 |
1 files changed, 285 insertions, 0 deletions
diff --git a/sysdeps/unix/sysv/solaris2/kopensolaris-gnu/privP.c b/sysdeps/unix/sysv/solaris2/kopensolaris-gnu/privP.c new file mode 100644 index 0000000000..0c2f296d26 --- /dev/null +++ b/sysdeps/unix/sysv/solaris2/kopensolaris-gnu/privP.c @@ -0,0 +1,285 @@ +/* Copyright (C) 2008 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by David Bartley <dtbartle@csclub.uwaterloo.ca>, 2008. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <privP.h> +#include <stdarg.h> +#include <grp.h> +#include <unistd.h> +#include <bits/libc-lock.h> + +__libc_lock_define_recursive (extern, __priv_lock); +libc_freeres_ptr (static priv_data_t *__data); +static priv_set_t *__suidset = NULL; + +priv_data_t * __priv_parse_info (const priv_impl_info_t *pii) +{ + priv_data_t *data = malloc (sizeof (priv_data_t)); + if (!data) + return NULL; + memset (data, 0, sizeof (*data)); + data->pd_setsize = pii->priv_setsize * sizeof (priv_chunk_t); + + /* Iterate over all priv_info_t's. Note that the first priv_info_t follows + the header. */ + priv_info_t *pi = (priv_info_t *)((char *)pii + pii->priv_headersize); + uint32_t left = pii->priv_globalinfosize; + while (left) + { + switch (pi->priv_info_type) + { + case PRIV_INFO_SETNAMES: + case PRIV_INFO_PRIVNAMES: + if ((pi->priv_info_type == PRIV_INFO_SETNAMES && + data->pd_setnames) || (pi->priv_info_type == + PRIV_INFO_PRIVNAMES && data->pd_privnames)) + break; + + /* XXX: In priv_get*byname we linearlly scan the list of strins; + we could speed this up by sorting the strings here. */ + + priv_info_names_t *pi_names = (priv_info_names_t *)pi; + + /* Allocate memory for the index. */ + char **name_list = malloc (sizeof (char *) * pi_names->cnt); + if (!name_list) + goto err; + if (pi->priv_info_type == PRIV_INFO_SETNAMES) + { + data->pd_setnames = name_list; + data->pd_setnames_cnt = pi_names->cnt; + } + else + { + data->pd_privnames = name_list; + data->pd_privnames_cnt = pi_names->cnt; + } + data->pd_privnames_cnt = pi_names->cnt; + + /* Setup the index. */ + char *names_ptr = pi_names->names; + for (int i = 0; i < pi_names->cnt; i++) + { + name_list[i] = names_ptr; + names_ptr += strlen (names_ptr) + 1; + } + + break; + + case PRIV_INFO_BASICPRIVS: + if (data->pd_basicprivs) + break; + + if (pi->priv_info_size != data->pd_setsize) + break; + data->pd_basicprivs = (priv_set_t *)((priv_info_set_t *)pi)->set; + + break; + } + + left -= pi->priv_info_size; + pi = (priv_info_t *)((char *)pi + pi->priv_info_size); + } + + return data; + +err: + + free (data->pd_setnames); + free (data->pd_privnames); + free (data); + + return NULL; +} + + +void __priv_free_info (priv_data_t *data) +{ + free (data->pd_setnames); + free (data->pd_privnames); + free (data); +} + + +const priv_data_t * __priv_parse_data_cached (void) +{ + if (__data) + return __data; + + __libc_lock_lock_recursive (__priv_lock); + __data = __priv_parse_info (getprivimplinfo ()); + __libc_lock_unlock_recursive (__priv_lock); + + return __data; +} + + +/* Specify what privileges an suid root binary needs. */ +int __init_suid_priv (int flags, ...) +{ + int res = 0; + priv_set_t *permit = NULL, *inherit = NULL, *scratch = NULL; + + /* Check flags. */ + if (flags != PU_LIMITPRIVS && flags != PU_CLEARLIMITSET) + return -1; + + /* We can only initialize once. */ + if (__suidset) + return -1; + + /* Do nothing if we are running as root but not setuid root. */ + uid_t uid = getuid (); + uid_t euid = geteuid (); + if (uid == 0 && euid == 0) + return 0; + + /* Allocate a scratch set. */ + scratch = priv_allocset (); + if (!scratch) + goto error; + + /* Get the basic set. */ + const priv_data_t *pd = __priv_parse_data_cached (); + if (!pd) + goto error; + priv_set_t *basic = pd->pd_basicprivs; + + /* Get the inherited set. */ + inherit = priv_allocset (); + if (!inherit) + goto error; + if (getppriv (PRIV_INHERITABLE, inherit) != 0) + goto error; + + /* Get the permitted set. */ + permit = priv_allocset (); + if (!permit) + goto error; + if (getppriv (PRIV_PERMITTED, permit) != 0) + goto error; + + /* Get passed privileges. */ + __suidset = priv_allocset (); + if (!__suidset) + goto error; + priv_emptyset (__suidset); + va_list ap; + va_start (ap, flags); + const char *priv; + while ((priv = va_arg (ap, const char *))) + if (priv_addset (__suidset, priv) != 0) + goto error; + + /* Make sure that the passed privileges are a subset of the current + permitted privileges. */ + if (priv_issubset (__suidset, permit) != _B_TRUE) + goto error; + + /* Set the effective privileges to the inherited ones. */ + if (setppriv (PRIV_SET, PRIV_EFFECTIVE, inherit) != 0) + goto error; + + /* Set the permitted privileges to those currently permitted privileges in + set of the ones passed in, the inherited ones, and the basic set. */ + priv_copyset (__suidset, scratch); + priv_union (inherit, scratch); + if (basic) + priv_union (basic, scratch); + priv_intersect (permit, scratch); + if (setppriv (PRIV_SET, PRIV_PERMITTED, scratch) != 0) + goto error; + + /* Check if we need to set the limit set. */ + if (flags & PU_CLEARLIMITSET) + { + priv_emptyset (scratch); + if (setppriv (PRIV_SET, PRIV_LIMIT, scratch) != 0) + goto error; + } + else if (flags & PU_LIMITPRIVS) + { + if (setppriv (PRIV_SET, PRIV_LIMIT, scratch) != 0) + goto error; + } + + /* Change the uid to the caller's uid if we're setuid root. */ + if (euid == 0 && setreuid (uid, uid) != 0) + goto error; + + goto out; + +error: + res = -1; + if (__suidset) + { + priv_freeset (__suidset); + __suidset = NULL; + } + if (euid == 0) + setreuid (uid, uid); + +out: + priv_freeset (permit); + priv_freeset (inherit); + priv_freeset (scratch); + + return res; +} + + +// TODO +#if 0 +int __init_daemon_priv (int flags, uid_t uid, gid_t gid, ...) +{ +} + + +void __fini_daemon_priv (const char *priv, ...) +{ +} +#endif + + +/* Enable or disable those privileges passed in __init_suid_priv. */ +int __priv_bracket (priv_op_t op) +{ + if (op != PRIV_ON && op != PRIV_OFF) + { + __set_errno (EINVAL); + return -1; + } + + /* We can only toggle privileges if __init_suid_priv was called. */ + if (__suidset) + return setppriv (op, PRIV_EFFECTIVE, __suidset); + else + return 0; +} + + +/* Permanently disable those privileges passed in __init_suid_priv. */ +void __priv_relinquish (void) +{ + if (__suidset) + { + setppriv (PRIV_OFF, PRIV_PERMITTED, __suidset); + priv_freeset (__suidset); + __suidset = NULL; + } +} |