/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
*/
#include <unistd.h>
#include <ctype.h>
#include <project.h>
#include <rctl.h>
#include <secdb.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <nss_dbdefs.h>
#include <pwd.h>
#include <pool.h>
#include <libproc.h>
#include <priv.h>
#include <priv_utils.h>
#include <zone.h>
#include <sys/pool_impl.h>
#include <sys/rctl_impl.h>
static void
xstrtolower(char *s)
{
for (; *s != '\0'; s++)
*s = tolower(*s);
}
static void
remove_spaces(char *s)
{
char *current;
char *next;
while (*next != '\0') {
next++;
}
*current = '\0';
}
int
{
char *signam;
int sig = 0;
if (comp_num == 0) {
/*
* Setting privilege level for resource control block.
*/
return (0);
}
return (0);
}
return (-1);
}
if (comp_num == 1) {
/*
* Setting value for resource control block.
*/
unsigned long long val;
char *t;
/* Negative numbers are not allowed */
return (-1);
errno = 0;
return (-1);
return (0);
}
/*
* Setting one or more actions on this resource control block.
*/
if (comp_num >= 2) {
rctlblk_set_local_action(blk, 0, 0);
return (0);
}
act |= RCTL_LOCAL_DENY;
return (0);
}
/*
* The last, and trickiest, form of action is the signal
* specification.
*/
return (-1);
*signam++ = '\0';
signam += 3;
return (-1);
act |= RCTL_LOCAL_SIGNAL;
return (0);
}
}
return (-1);
}
/*
* States:
*/
/*
* Errors:
*/
static void
{
rctlblk_set_value(blk, 0);
}
static int
{
int error = 0;
int valuecount = 0;
char *component_head;
int project_entity = 0;
int count = 0;
char *tmp;
int local_act;
int teardown_basic = 0;
int teardown_priv = 0;
/* We cannot modify a zone resource control */
return (SETFAILED);
}
project_entity = 1;
return (SETFAILED);
}
/* Determine how many attributes we'll be setting */
if (*tmp == '(')
count++;
}
/* Allocate sufficient memory for rctl blocks */
return (SETFAILED);
}
/*
* In order to set the new rctl's local_action, we'll need the
* current value of global_flags. We obtain global_flags by
* performing a pr_getrctl().
*
* The ctl_name has been verified as valid, so we have no reason
* to suspect that pr_getrctl() will return an error.
*/
/*
* Set initial local action based on global deny properties.
*/
rctlblk_set_value(blk, 0);
else
for (; ; val++) {
switch (*val) {
case '(':
break;
}
break;
case ')':
*val = '\0';
if (component < 2) {
break;
}
component_head) == -1) {
break;
}
component = 0;
valuecount++;
if (project_entity &&
(rctlblk_get_privilege(blk) ==
RCPRIV_BASIC)) {
} else {
if (rctlblk_get_privilege(blk)
== RCPRIV_BASIC)
teardown_basic = 1;
if (rctlblk_get_privilege(blk)
teardown_priv = 1;
if (valuecount > count) {
return (SETFAILED);
}
if (valuecount != count) {
/* re-initialize blk */
}
}
} else {
}
break;
case ',':
*val = '\0';
component_head) == -1)
component++;
}
break;
case '\0':
if (valuecount == 0)
else
break;
default:
break;
}
if (error)
break;
}
/* ablk points to array of rctlblk_t */
if (valuecount == 0)
return (error);
}
/* teardown rctls if required */
if (!project_entity) {
return (SETFAILED);
}
while (1) {
if ((rctlblk_get_privilege(rnext) ==
(teardown_priv == 1)) {
rnext, RCTL_DELETE);
goto restart;
}
if ((rctlblk_get_privilege(rnext) ==
rnext, RCTL_DELETE);
goto restart;
}
RCTL_NEXT) == -1)
break;
}
}
}
/* set rctls */
if (project_entity) {
} else {
valuecount = 0;
while (valuecount < count) {
break;
}
valuecount++;
}
}
return (error);
return (0);
}
static int
{
return (-1);
else
return (0);
}
/*
* pools are currently enabled. We want to do this directly from libproject
* without using libpool's pool_get_status() routine because pools could be
* completely removed from the system. Return 1 if pools are enabled, or
* 0 otherwise. When used inside local zones, always pretend that pools
* are disabled because binding is not allowed and we're already in the
* right pool.
*/
static int
pools_enabled(void)
{
int fd;
if (getzoneid() != GLOBAL_ZONEID)
return (0);
return (0);
return (0);
}
return (status.ps_io_state);
}
/*
* A pool_name of NULL means to attempt to bind to the default pool.
* If the "force" flag is non-zero, the value of "system.bind-default" will be
* ignored, and the process will be bound to the default pool if one exists.
*/
static int
{
const char *nm;
int retval;
return (-1);
/*
* Pools configuration file is corrupted; allow logins.
*/
return (0);
}
/*
* There was a project.pool entry, and the pool it refers to
* is a valid (active) pool.
*/
(void) pool_conf_close(conf);
if (pool_error() != POE_SYSTEM)
return (-1);
}
return (0);
}
/*
* Bind to the pool with 'pool.default' = 'true' if
* 'system.bind-default' = 'true'.
*/
return (-1);
}
pool_value_free(pvals[0]);
return (-1);
}
/*
* No default pools exist.
*/
pool_value_free(pvals[0]);
return (-1);
}
if (nelem != 1 ||
pvals[0]) != POC_STRING) {
/*
* Configuration is invalid.
*/
pool_value_free(pvals[0]);
(void) pool_conf_close(conf);
return (0);
}
(void) pool_conf_close(conf);
if (pool_error() != POE_SYSTEM)
retval = -1;
} else {
retval = 0;
}
pool_value_free(pvals[0]);
return (retval);
}
/*
* Changes the assigned project, task and resource pool of a stopped target
* process.
*
* We may not have access to the project table if our target process is in
* getprojbyname()'s execution path. Similarly, we may not be able to get user
* information if the target process is in getpwnam()'s execution path. Thus we
* give the caller the option of skipping these checks by providing a pointer to
* a pre-validated project structure in proj (whose name matches project_name)
* and taking responsibility for ensuring that the target process' owner is a
* member of the target project.
*
* Callers of this function should always provide a pre-validated project
* structure in proj unless they can be sure that the target process will never
* be in setproject_proc()'s execution path.
*/
{
int i;
int unknown = 0;
int ret = 0;
if (project_name != NULL) {
/*
* Sanity checks.
*/
return (SETPROJ_ERR_TASK);
}
/*
* If proj is NULL, acquire project information to ensure that
* project_name is a valid project, and confirm that user_name
* exists and is a member of the specified project.
*/
return (SETPROJ_ERR_TASK);
}
return (SETPROJ_ERR_TASK);
}
/*
* Root can join any project.
*/
PROJECT_BUFSZ)) {
return (SETPROJ_ERR_TASK);
}
}
} else {
}
KV_DELIMITER)) != NULL) {
"project.pool") == 0) {
}
flags |= TASK_FINAL;
}
}
}
/*
* Bind process to a pool only if pools are configured
*/
if (pools_enabled() == 1) {
char *old_pool_name;
/*
* Attempt to bind to pool before calling
* settaskid().
*/
if (old_pool_name)
return (SETPROJ_ERR_POOL);
}
/*
* Undo pool binding.
*/
if (old_pool_name)
/*
* Restore errno
*/
errno = saved_errno;
return (SETPROJ_ERR_TASK);
}
if (old_pool_name)
} else {
/*
* Pools are not configured, so simply create new task.
*/
return (SETPROJ_ERR_TASK);
}
}
if (project_name == NULL) {
/*
* In the case that we are starting a new task in the
* current project, we are finished, since the current
* resource controls will still apply. (Implicit behaviour:
* a project must be entirely logged out before name
* service changes will take effect.)
*/
return (projid);
}
return (0);
/*
* Providing a special, i.e. a non-resource control, key? Then
* parse that key here and end with "continue;".
*/
/*
* For generic bindings, the kernel performs the binding, as
* these are resource controls advertised by kernel subsystems.
*/
/*
* Check for known attribute name.
*/
errno = 0;
== 0)
continue;
if (errno) {
return (SETPROJ_ERR_TASK);
}
/*
* We only report the first failure.
*/
unknown = i + 1;
}
/*
* We abort if we couldn't set a component, but if
* it's merely that the system didn't recognize it, we
* continue, as this could be a third party attribute.
*/
break;
}
}
return (unknown);
}
{
NULL));
}
setproject_initpriv(void)
{
int res;
if (getzoneid() == GLOBAL_ZONEID) {
} else {
}
if (res != 0)
return (NULL);
nset = priv_allocset();
/*
* Only need these if we need to change pools, which can
* only happen if the target is in the global zone. Rather
* than checking the target's zone just check our own
* (since if we're in a non-global zone we won't be able
* to control processes in other zones).
*/
if (getzoneid() == GLOBAL_ZONEID) {
}
}
return (nset);
}