1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright (c) 2012, Joyent, Inc. All rights reserved.
  24  */
  25 
  26 
  27 #include <sys/task.h>
  28 #include <sys/types.h>
  29 #include <unistd.h>
  30 
  31 #include <ctype.h>
  32 #include <project.h>
  33 #include <rctl.h>
  34 #include <secdb.h>
  35 #include <signal.h>
  36 #include <stdlib.h>
  37 #include <string.h>
  38 #include <strings.h>
  39 #include <nss_dbdefs.h>
  40 #include <pwd.h>
  41 #include <pool.h>
  42 #include <libproc.h>
  43 #include <priv.h>
  44 #include <priv_utils.h>
  45 #include <zone.h>
  46 #include <sys/pool.h>
  47 #include <sys/pool_impl.h>
  48 #include <sys/rctl_impl.h>
  49 
  50 static void
  51 xstrtolower(char *s)
  52 {
  53         for (; *s != '\0'; s++)
  54                 *s = tolower(*s);
  55 }
  56 
  57 static void
  58 remove_spaces(char *s)
  59 {
  60         char *current;
  61         char *next;
  62 
  63         current = next = s;
  64 
  65         while (*next != '\0') {
  66                 while (isspace(*next))
  67                         next++;
  68                 *current++ = *next++;
  69         }
  70         *current = '\0';
  71 }
  72 
  73 int
  74 build_rctlblk(rctlblk_t *blk, int comp_num, char *component)
  75 {
  76         char *signam;
  77         int sig = 0;
  78         uint_t act = rctlblk_get_local_action(blk, &sig);
  79 
  80         if (comp_num == 0) {
  81                 /*
  82                  * Setting privilege level for resource control block.
  83                  */
  84                 xstrtolower(component);
  85 
  86                 if (strcmp("basic", component) == 0) {
  87                         rctlblk_set_privilege(blk, RCPRIV_BASIC);
  88                         return (0);
  89                 }
  90 
  91                 if (strcmp("priv", component) == 0 ||
  92                     strcmp("privileged", component) == 0) {
  93                         rctlblk_set_privilege(blk, RCPRIV_PRIVILEGED);
  94                         return (0);
  95                 }
  96 
  97                 return (-1);
  98         }
  99 
 100         if (comp_num == 1) {
 101 
 102                 /*
 103                  * Setting value for resource control block.
 104                  */
 105                 unsigned long long val;
 106                 char *t;
 107 
 108                 /* Negative numbers are not allowed */
 109                 if (strchr(component, '-') != NULL)
 110                         return (-1);
 111 
 112                 errno = 0;
 113                 val = strtoull(component, &t, 10);
 114                 if (errno != 0 || t == component || *t != '\0')
 115                         return (-1);
 116 
 117                 rctlblk_set_value(blk, (rctl_qty_t)val);
 118                 return (0);
 119         }
 120 
 121         /*
 122          * Setting one or more actions on this resource control block.
 123          */
 124         if (comp_num >= 2) {
 125                 if (strcmp("none", component) == 0) {
 126                         rctlblk_set_local_action(blk, 0, 0);
 127                         return (0);
 128                 }
 129 
 130                 if (strcmp("deny", component) == 0) {
 131                         act |= RCTL_LOCAL_DENY;
 132 
 133                         rctlblk_set_local_action(blk, act, sig);
 134 
 135                         return (0);
 136                 }
 137 
 138                 /*
 139                  * The last, and trickiest, form of action is the signal
 140                  * specification.
 141                  */
 142                 if ((signam = strchr(component, '=')) == NULL)
 143                         return (-1);
 144 
 145                 *signam++ = '\0';
 146 
 147                 if (strcmp("sig", component) == 0 ||
 148                     strcmp("signal", component) == 0) {
 149                         if (strncmp("SIG", signam, 3) == 0)
 150                                 signam += 3;
 151 
 152                         if (str2sig(signam, &sig) == -1)
 153                                 return (-1);
 154 
 155                         act |= RCTL_LOCAL_SIGNAL;
 156 
 157                         rctlblk_set_local_action(blk, act, sig);
 158 
 159                         return (0);
 160                 }
 161         }
 162         return (-1);
 163 }
 164 
 165 /*
 166  * States:
 167  */
 168 #define INPAREN         0x1
 169 
 170 /*
 171  * Errors:
 172  */
 173 #define SETFAILED       (-1)
 174 #define COMPLETE        1
 175 #define NESTING         2
 176 #define UNCLOSED        3
 177 #define CLOSEBEFOREOPEN 4
 178 #define BADSPEC         5
 179 
 180 static void
 181 reinit_blk(rctlblk_t *blk, int local_action)
 182 {
 183         rctlblk_set_privilege(blk, RCPRIV_PRIVILEGED);
 184         rctlblk_set_value(blk, 0);
 185         rctlblk_set_local_flags(blk, 0);
 186         rctlblk_set_local_action(blk, local_action, 0);
 187 }
 188 
 189 static int
 190 rctl_set(char *ctl_name, char *val, struct ps_prochandle *Pr, int flags)
 191 {
 192         int error = 0;
 193         uint_t component = 0;
 194         int valuecount = 0;
 195         uint_t state = 0;
 196         char *component_head;
 197         rctlblk_t *blk;
 198         rctlblk_t *ablk;
 199         int project_entity = 0;
 200         int count = 0;
 201         char *tmp;
 202         int local_act;
 203         rctlblk_t *rnext;
 204         int teardown_basic = 0;
 205         int teardown_priv = 0;
 206 
 207         /* We cannot modify a zone resource control */
 208         if (strncmp(ctl_name, "zone.", strlen("zone.")) == 0) {
 209                 return (SETFAILED);
 210         }
 211 
 212         remove_spaces(val);
 213 
 214         if (strncmp(ctl_name, "project.", strlen("project.")) == 0) {
 215                 project_entity = 1;
 216         } else if ((strncmp(ctl_name, "process.", strlen("process.")) != 0) &&
 217             (strncmp(ctl_name, "task.", strlen("task.")) != 0)) {
 218                 return (SETFAILED);
 219         }
 220 
 221         /* Determine how many attributes we'll be setting */
 222         for (tmp = val; *tmp != '\0'; tmp++) {
 223                 if (*tmp == '(')
 224                         count++;
 225         }
 226         /* Allocate sufficient memory for rctl blocks */
 227         if ((count == 0) || ((ablk =
 228             (rctlblk_t *)malloc(rctlblk_size() * count)) == NULL)) {
 229                 return (SETFAILED);
 230         }
 231         blk = ablk;
 232 
 233         /*
 234          * In order to set the new rctl's local_action, we'll need the
 235          * current value of global_flags.  We obtain global_flags by
 236          * performing a pr_getrctl().
 237          *
 238          * The ctl_name has been verified as valid, so we have no reason
 239          * to suspect that pr_getrctl() will return an error.
 240          */
 241         (void) pr_getrctl(Pr, ctl_name, NULL, blk, RCTL_FIRST);
 242 
 243 
 244         /*
 245          * Set initial local action based on global deny properties.
 246          */
 247         rctlblk_set_privilege(blk, RCPRIV_PRIVILEGED);
 248         rctlblk_set_value(blk, 0);
 249         rctlblk_set_local_flags(blk, 0);
 250 
 251         if (rctlblk_get_global_flags(blk) & RCTL_GLOBAL_DENY_ALWAYS)
 252                 local_act = RCTL_LOCAL_DENY;
 253         else
 254                 local_act = RCTL_LOCAL_NOACTION;
 255 
 256         rctlblk_set_local_action(blk, local_act, 0);
 257 
 258         for (; ; val++) {
 259 
 260                 switch (*val) {
 261                         case '(':
 262                                 if (state & INPAREN) {
 263                                         error = NESTING;
 264                                         break;
 265                                 }
 266 
 267                                 state |= INPAREN;
 268                                 component_head = (char *)val + 1;
 269 
 270                                 break;
 271                         case ')':
 272                                 if (state & INPAREN) {
 273                                         *val = '\0';
 274                                         if (component < 2) {
 275                                                 error = BADSPEC;
 276                                                 break;
 277                                         }
 278                                         if (build_rctlblk(blk, component,
 279                                             component_head) == -1) {
 280                                                 error = BADSPEC;
 281                                                 break;
 282                                         }
 283                                         state &= ~INPAREN;
 284                                         component = 0;
 285                                         valuecount++;
 286 
 287                                         if (project_entity &&
 288                                             (rctlblk_get_privilege(blk) ==
 289                                             RCPRIV_BASIC)) {
 290                                                 error = SETFAILED;
 291                                         } else {
 292                                                 if (rctlblk_get_privilege(blk)
 293                                                     == RCPRIV_BASIC)
 294                                                         teardown_basic = 1;
 295 
 296                                                 if (rctlblk_get_privilege(blk)
 297                                                     == RCPRIV_PRIVILEGED)
 298                                                         teardown_priv = 1;
 299 
 300                                                 if (valuecount > count) {
 301                                                         free(ablk);
 302                                                         return (SETFAILED);
 303                                                 }
 304 
 305                                                 if (valuecount != count) {
 306                                                         blk = RCTLBLK_INC(ablk,
 307                                                             valuecount);
 308                                                         /* re-initialize blk */
 309                                                         reinit_blk(blk,
 310                                                             local_act);
 311                                                 }
 312                                         }
 313 
 314                                 } else {
 315                                         error = CLOSEBEFOREOPEN;
 316                                 }
 317                                 break;
 318                         case ',':
 319                                 if (state & INPAREN) {
 320                                         *val = '\0';
 321                                         if (build_rctlblk(blk, component,
 322                                             component_head) == -1)
 323                                                 error = BADSPEC;
 324 
 325                                         component++;
 326                                         component_head = (char *)val + 1;
 327 
 328                                 }
 329                                 break;
 330                         case '\0':
 331                                 if (valuecount == 0)
 332                                         error = BADSPEC;
 333                                 else if (state & INPAREN)
 334                                         error = UNCLOSED;
 335                                 else
 336                                         error = COMPLETE;
 337                                 break;
 338                         default:
 339                                 if (!(state & INPAREN))
 340                                         error = BADSPEC;
 341                                 break;
 342                 }
 343 
 344                 if (error)
 345                         break;
 346         }
 347         /* ablk points to array of rctlblk_t */
 348 
 349         if (valuecount == 0)
 350                 error = BADSPEC;
 351 
 352         if (error != COMPLETE) {
 353                 free(ablk);
 354                 return (error);
 355         }
 356 
 357         /* teardown rctls if required */
 358         if (!project_entity) {
 359 
 360                 if ((rnext = (rctlblk_t *)malloc(rctlblk_size())) == NULL) {
 361                         free(ablk);
 362                         return (SETFAILED);
 363                 }
 364 
 365 restart:
 366                 if (pr_getrctl(Pr, ctl_name, NULL, rnext, RCTL_FIRST) == 0) {
 367                         while (1) {
 368                                 if ((rctlblk_get_privilege(rnext) ==
 369                                     RCPRIV_PRIVILEGED) &&
 370                                     (teardown_priv == 1)) {
 371                                         (void) pr_setrctl(Pr, ctl_name, NULL,
 372                                             rnext, RCTL_DELETE);
 373                                         goto restart;
 374                                 }
 375                                 if ((rctlblk_get_privilege(rnext) ==
 376                                     RCPRIV_BASIC) && (teardown_basic == 1)) {
 377                                         (void) pr_setrctl(Pr, ctl_name, NULL,
 378                                             rnext, RCTL_DELETE);
 379                                         goto restart;
 380                                 }
 381 
 382                                 if (pr_getrctl(Pr, ctl_name, rnext, rnext,
 383                                     RCTL_NEXT) == -1)
 384                                         break;
 385                         }
 386                 }
 387 
 388                 free(rnext);
 389         }
 390 
 391         /* set rctls */
 392 
 393         blk = ablk;
 394 
 395         if (project_entity) {
 396                 if (pr_setprojrctl(Pr, ctl_name, blk, count, flags) == -1)
 397                         error = SETFAILED;
 398         } else {
 399                 valuecount = 0;
 400                 while (valuecount < count) {
 401                         if (pr_setrctl(Pr, ctl_name,
 402                             NULL, blk, RCTL_INSERT) == -1) {
 403                                 error = SETFAILED;
 404                                 break;
 405                                 }
 406                         valuecount++;
 407                         blk = RCTLBLK_INC(ablk, valuecount);
 408                 }
 409         }
 410 
 411 
 412 
 413         free(ablk);
 414 
 415         if (error != COMPLETE)
 416                 return (error);
 417 
 418         return (0);
 419 }
 420 
 421 static int
 422 rctlwalkfunc(const char *name, void *data)
 423 {
 424 
 425         if (strcmp(name, (char *)data) == 0)
 426                 return (-1);
 427         else
 428                 return (0);
 429 
 430 }
 431 
 432 /*
 433  * This routine determines if /dev/pool device is present on the system and
 434  * pools are currently enabled.  We want to do this directly from libproject
 435  * without using libpool's pool_get_status() routine because pools could be
 436  * completely removed from the system.  Return 1 if pools are enabled, or
 437  * 0 otherwise.  When used inside local zones, always pretend that pools
 438  * are disabled because binding is not allowed and we're already in the
 439  * right pool.
 440  */
 441 static int
 442 pools_enabled(void)
 443 {
 444         pool_status_t status;
 445         int fd;
 446 
 447         if (getzoneid() != GLOBAL_ZONEID)
 448                 return (0);
 449         if ((fd = open("/dev/pool", O_RDONLY)) < 0)
 450                 return (0);
 451         if (ioctl(fd, POOL_STATUSQ, &status) < 0) {
 452                 (void) close(fd);
 453                 return (0);
 454         }
 455         (void) close(fd);
 456         return (status.ps_io_state);
 457 }
 458 
 459 /*
 460  * A pool_name of NULL means to attempt to bind to the default pool.
 461  * If the "force" flag is non-zero, the value of "system.bind-default" will be
 462  * ignored, and the process will be bound to the default pool if one exists.
 463  */
 464 static int
 465 bind_to_pool(const char *pool_name, pid_t pid, int force)
 466 {
 467         pool_value_t *pvals[] = { NULL, NULL };
 468         pool_t **pools;
 469         uint_t nelem;
 470         uchar_t bval;
 471         pool_conf_t *conf;
 472         const char *nm;
 473         int retval;
 474 
 475         if ((conf = pool_conf_alloc()) == NULL)
 476                 return (-1);
 477         if (pool_conf_open(conf, pool_dynamic_location(), PO_RDONLY) < 0) {
 478                 /*
 479                  * Pools configuration file is corrupted; allow logins.
 480                  */
 481                 pool_conf_free(conf);
 482                 return (0);
 483         }
 484         if (pool_name != NULL && pool_get_pool(conf, pool_name) != NULL) {
 485                 /*
 486                  * There was a project.pool entry, and the pool it refers to
 487                  * is a valid (active) pool.
 488                  */
 489                 (void) pool_conf_close(conf);
 490                 pool_conf_free(conf);
 491                 if (pool_set_binding(pool_name, P_PID, pid) != PO_SUCCESS) {
 492                         if (pool_error() != POE_SYSTEM)
 493                                 errno = EINVAL;
 494                         return (-1);
 495                 }
 496                 return (0);
 497         }
 498 
 499         /*
 500          * Bind to the pool with 'pool.default' = 'true' if
 501          * 'system.bind-default' = 'true'.
 502          */
 503         if ((pvals[0] = pool_value_alloc()) == NULL) {
 504                 pool_conf_close(conf);
 505                 pool_conf_free(conf);
 506                 return (-1);
 507         }
 508         if (!force && pool_get_property(conf, pool_conf_to_elem(conf),
 509             "system.bind-default", pvals[0]) != POC_BOOL ||
 510             pool_value_get_bool(pvals[0], &bval) != PO_SUCCESS ||
 511             bval == PO_FALSE) {
 512                 pool_value_free(pvals[0]);
 513                 pool_conf_close(conf);
 514                 pool_conf_free(conf);
 515                 errno = pool_name == NULL ? EACCES : ESRCH;
 516                 return (-1);
 517         }
 518         (void) pool_value_set_name(pvals[0], "pool.default");
 519         pool_value_set_bool(pvals[0], PO_TRUE);
 520         if ((pools = pool_query_pools(conf, &nelem, pvals)) == NULL) {
 521                 /*
 522                  * No default pools exist.
 523                  */
 524                 pool_value_free(pvals[0]);
 525                 pool_conf_close(conf);
 526                 pool_conf_free(conf);
 527                 errno = pool_name == NULL ? EACCES : ESRCH;
 528                 return (-1);
 529         }
 530         if (nelem != 1 ||
 531             pool_get_property(conf, pool_to_elem(conf, pools[0]), "pool.name",
 532             pvals[0]) != POC_STRING) {
 533                 /*
 534                  * Configuration is invalid.
 535                  */
 536                 free(pools);
 537                 pool_value_free(pvals[0]);
 538                 (void) pool_conf_close(conf);
 539                 pool_conf_free(conf);
 540                 return (0);
 541         }
 542         free(pools);
 543         (void) pool_conf_close(conf);
 544         pool_conf_free(conf);
 545         (void) pool_value_get_string(pvals[0], &nm);
 546         if (pool_set_binding(nm, P_PID, pid) != PO_SUCCESS) {
 547                 if (pool_error() != POE_SYSTEM)
 548                         errno = EINVAL;
 549                 retval = -1;
 550         } else {
 551                 retval = 0;
 552         }
 553         pool_value_free(pvals[0]);
 554         return (retval);
 555 }
 556 
 557 /*
 558  * Changes the assigned project, task and resource pool of a stopped target
 559  * process.
 560  *
 561  * We may not have access to the project table if our target process is in
 562  * getprojbyname()'s execution path. Similarly, we may not be able to get user
 563  * information if the target process is in getpwnam()'s execution path. Thus we
 564  * give the caller the option of skipping these checks by providing a pointer to
 565  * a pre-validated project structure in proj (whose name matches project_name)
 566  * and taking responsibility for ensuring that the target process' owner is a
 567  * member of the target project.
 568  *
 569  * Callers of this function should always provide a pre-validated project
 570  * structure in proj unless they can be sure that the target process will never
 571  * be in setproject_proc()'s execution path.
 572  */
 573 
 574 projid_t
 575 setproject_proc(const char *project_name, const char *user_name, int flags,
 576     pid_t pid, struct ps_prochandle *Pr, struct project *proj)
 577 {
 578         char pwdbuf[NSS_BUFLEN_PASSWD];
 579         char prbuf[PROJECT_BUFSZ];
 580         projid_t projid;
 581         struct passwd pwd;
 582         int i;
 583         int unknown = 0;
 584         int ret = 0;
 585         kva_t *kv_array;
 586         struct project local_proj; /* space to store proj if not provided */
 587         const char *pool_name = NULL;
 588 
 589         if (project_name != NULL) {
 590                 /*
 591                  * Sanity checks.
 592                  */
 593                 if (strcmp(project_name, "") == 0 ||
 594                     user_name == NULL) {
 595                         errno = EINVAL;
 596                         return (SETPROJ_ERR_TASK);
 597                 }
 598 
 599                 /*
 600                  * If proj is NULL, acquire project information to ensure that
 601                  * project_name is a valid project, and confirm that user_name
 602                  * exists and is a member of the specified project.
 603                  */
 604                 if (proj == NULL) {
 605                         if ((proj = getprojbyname(project_name, &local_proj,
 606                             prbuf, PROJECT_BUFSZ)) == NULL) {
 607                                 errno = ESRCH;
 608                                 return (SETPROJ_ERR_TASK);
 609                         }
 610 
 611                         if (getpwnam_r(user_name, &pwd,
 612                             pwdbuf, NSS_BUFLEN_PASSWD) == NULL) {
 613                                 errno = ESRCH;
 614                                 return (SETPROJ_ERR_TASK);
 615                         }
 616                         /*
 617                          * Root can join any project.
 618                          */
 619                         if (pwd.pw_uid != (uid_t)0 &&
 620                             !inproj(user_name, project_name, prbuf,
 621                             PROJECT_BUFSZ)) {
 622                                 errno = ESRCH;
 623                                 return (SETPROJ_ERR_TASK);
 624                         }
 625                 }
 626                 projid = proj->pj_projid;
 627         } else {
 628                 projid = getprojid();
 629         }
 630 
 631 
 632         if ((kv_array = _str2kva(proj->pj_attr, KV_ASSIGN,
 633             KV_DELIMITER)) != NULL) {
 634                 for (i = 0; i < kv_array->length; i++) {
 635                         if (strcmp(kv_array->data[i].key,
 636                             "project.pool") == 0) {
 637                                 pool_name = kv_array->data[i].value;
 638                         }
 639                         if (strcmp(kv_array->data[i].key, "task.final") == 0) {
 640                                 flags |= TASK_FINAL;
 641                         }
 642                 }
 643         }
 644 
 645         /*
 646          * Bind process to a pool only if pools are configured
 647          */
 648         if (pools_enabled() == 1) {
 649                 char *old_pool_name;
 650                 /*
 651                  * Attempt to bind to pool before calling
 652                  * settaskid().
 653                  */
 654                 old_pool_name = pool_get_binding(pid);
 655                 if (bind_to_pool(pool_name, pid, 0) != 0) {
 656                         if (old_pool_name)
 657                                 free(old_pool_name);
 658                         _kva_free(kv_array);
 659                         return (SETPROJ_ERR_POOL);
 660                 }
 661                 if (pr_settaskid(Pr, projid, flags & TASK_MASK) == -1) {
 662                         int saved_errno = errno;
 663 
 664                         /*
 665                          * Undo pool binding.
 666                          */
 667                         (void) bind_to_pool(old_pool_name, pid, 1);
 668                         if (old_pool_name)
 669                                 free(old_pool_name);
 670                         _kva_free(kv_array);
 671                         /*
 672                          * Restore errno
 673                          */
 674                         errno = saved_errno;
 675                         return (SETPROJ_ERR_TASK);
 676                 }
 677                 if (old_pool_name)
 678                         free(old_pool_name);
 679         } else {
 680                 /*
 681                  * Pools are not configured, so simply create new task.
 682                  */
 683                 if (pr_settaskid(Pr, projid, flags & TASK_MASK) == -1) {
 684                         _kva_free(kv_array);
 685                         return (SETPROJ_ERR_TASK);
 686                 }
 687         }
 688 
 689         if (project_name == NULL) {
 690                 /*
 691                  * In the case that we are starting a new task in the
 692                  * current project, we are finished, since the current
 693                  * resource controls will still apply. (Implicit behaviour:
 694                  * a project must be entirely logged out before name
 695                  * service changes will take effect.)
 696                  */
 697                 _kva_free(kv_array);
 698                 return (projid);
 699         }
 700 
 701         if (kv_array == NULL)
 702                 return (0);
 703 
 704         for (i = 0; i < kv_array->length; i++) {
 705                 /*
 706                  * Providing a special, i.e. a non-resource control, key?  Then
 707                  * parse that key here and end with "continue;".
 708                  */
 709 
 710                 /*
 711                  * For generic bindings, the kernel performs the binding, as
 712                  * these are resource controls advertised by kernel subsystems.
 713                  */
 714 
 715                 /*
 716                  * Check for known attribute name.
 717                  */
 718                 errno = 0;
 719                 if (rctl_walk(rctlwalkfunc, (void *)kv_array->data[i].key)
 720                     == 0)
 721                         continue;
 722                 if (errno) {
 723                         _kva_free(kv_array);
 724                         return (SETPROJ_ERR_TASK);
 725                 }
 726 
 727                 ret = rctl_set(kv_array->data[i].key,
 728                     kv_array->data[i].value, Pr, flags & TASK_PROJ_MASK);
 729 
 730                 if (ret && unknown == 0) {
 731                         /*
 732                          * We only report the first failure.
 733                          */
 734                         unknown = i + 1;
 735                 }
 736 
 737                 if (ret && ret != SETFAILED) {
 738                         /*
 739                          * We abort if we couldn't set a component, but if
 740                          * it's merely that the system didn't recognize it, we
 741                          * continue, as this could be a third party attribute.
 742                          */
 743                         break;
 744                 }
 745         }
 746         _kva_free(kv_array);
 747 
 748         return (unknown);
 749 }
 750 
 751 projid_t
 752 setproject(const char *project_name, const char *user_name, int flags)
 753 {
 754         return (setproject_proc(project_name, user_name, flags, P_MYID, NULL,
 755             NULL));
 756 }
 757 
 758 
 759 priv_set_t *
 760 setproject_initpriv(void)
 761 {
 762         static priv_t taskpriv = PRIV_PROC_TASKID;
 763         static priv_t rctlpriv = PRIV_SYS_RESOURCE;
 764         static priv_t poolpriv = PRIV_SYS_RES_CONFIG;
 765         static priv_t schedpriv = PRIV_PROC_PRIOCNTL;
 766         int res;
 767 
 768         priv_set_t *nset;
 769 
 770         if (getzoneid() == GLOBAL_ZONEID) {
 771                 res = __init_suid_priv(0, taskpriv, rctlpriv, poolpriv,
 772                     schedpriv, (char *)NULL);
 773         } else {
 774                 res = __init_suid_priv(0, taskpriv, rctlpriv, (char *)NULL);
 775         }
 776 
 777         if (res != 0)
 778                 return (NULL);
 779 
 780         nset = priv_allocset();
 781         if (nset != NULL) {
 782                 priv_emptyset(nset);
 783                 (void) priv_addset(nset, taskpriv);
 784                 (void) priv_addset(nset, rctlpriv);
 785                 /*
 786                  * Only need these if we need to change pools, which can
 787                  * only happen if the target is in the global zone.  Rather
 788                  * than checking the target's zone just check our own
 789                  * (since if we're in a non-global zone we won't be able
 790                  * to control processes in other zones).
 791                  */
 792                 if (getzoneid() == GLOBAL_ZONEID) {
 793                         (void) priv_addset(nset, poolpriv);
 794                         (void) priv_addset(nset, schedpriv);
 795                 }
 796         }
 797         return (nset);
 798 }