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) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
  23  */
  24 
  25 #include <nss_dbdefs.h>
  26 #include <pwd.h>
  27 #include <stdlib.h>
  28 #include <string.h>
  29 #include <syslog.h>
  30 #include <unistd.h>
  31 #include <auth_attr.h>
  32 #include <deflt.h>
  33 #include <priv.h>
  34 #include <secdb.h>
  35 #include <user_attr.h>
  36 #include <sys/task.h>
  37 #include <libintl.h>
  38 #include <project.h>
  39 #include <errno.h>
  40 #include <alloca.h>
  41 
  42 #include <bsm/adt.h>
  43 #include <bsm/adt_event.h>        /* adt_get_auid() */
  44 
  45 #include <security/pam_appl.h>
  46 #include <security/pam_modules.h>
  47 #include <security/pam_impl.h>
  48 
  49 #define PROJECT         "project="
  50 #define PROJSZ          (sizeof (PROJECT) - 1)
  51 
  52 /*
  53  *      unix_cred - PAM auth modules must contain both pam_sm_authenticate
  54  *              and pam_sm_setcred.  Some other auth module is responsible
  55  *              for authentication (e.g., pam_unix_auth.so), this module
  56  *              only implements pam_sm_setcred so that the authentication
  57  *              can be separated without knowledge of the Solaris Unix style
  58  *              credential setting.
  59  *              Solaris Unix style credential setting includes initializing
  60  *              the audit characteristics if not already initialized and
  61  *              setting the user's default and limit privileges.
  62  */
  63 
  64 /*
  65  *      unix_cred - pam_sm_authenticate
  66  *
  67  *      Returns PAM_IGNORE.
  68  */
  69 
  70 /*ARGSUSED*/
  71 int
  72 pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
  73 {
  74         return (PAM_IGNORE);
  75 }
  76 
  77 /*
  78  * Set the privilege set.  The attributes are enumerated by _enum_attrs,
  79  * including the attribues user_attr, prof_attr and policy.conf
  80  */
  81 static int
  82 getset(char *str, priv_set_t **res)
  83 {
  84         priv_set_t *tmp;
  85         char *badp;
  86         int len;
  87 
  88         if (str == NULL)
  89                 return (0);
  90 
  91         len = strlen(str) + 1;
  92         badp = alloca(len);
  93         (void) memset(badp, '\0', len);
  94         do {
  95                 const char *q, *endp;
  96                 tmp = priv_str_to_set(str, ",", &endp);
  97                 if (tmp == NULL) {
  98                         if (endp == NULL)
  99                                 break;
 100 
 101                         /* Now remove the bad privilege endp points to */
 102                         q = strchr(endp, ',');
 103                         if (q == NULL)
 104                                 q = endp + strlen(endp);
 105 
 106                         if (*badp != '\0')
 107                                 (void) strlcat(badp, ",", len);
 108                         /* Memset above guarantees NUL termination */
 109                         /* LINTED */
 110                         (void) strncat(badp, endp, q - endp);
 111                         /* excise bad privilege; strtok ignores 2x sep */
 112                         (void) memmove((void *)endp, q, strlen(q) + 1);
 113                 }
 114         } while (tmp == NULL && *str != '\0');
 115 
 116         if (tmp == NULL) {
 117                 syslog(LOG_AUTH|LOG_ERR,
 118                     "pam_setcred: can't parse privilege specification: %m\n");
 119                 return (-1);
 120         } else if (*badp != '\0') {
 121                 syslog(LOG_AUTH|LOG_DEBUG,
 122                     "pam_setcred: unrecognized privilege(s): %s\n", badp);
 123         }
 124         *res = tmp;
 125         return (0);
 126 }
 127 
 128 typedef struct deflim {
 129         char *def;
 130         char *lim;
 131 } deflim_t;
 132 
 133 /*ARGSUSED*/
 134 static int
 135 finddeflim(const char *name, kva_t *kva, void *ctxt, void *pres)
 136 {
 137         deflim_t *pdef = pres;
 138         char *val;
 139 
 140         if (pdef->def == NULL) {
 141                 val = kva_match(kva, USERATTR_DFLTPRIV_KW);
 142                 if (val != NULL)
 143                         pdef->def = strdup(val);
 144         }
 145         if (pdef->lim == NULL) {
 146                 val = kva_match(kva, USERATTR_LIMPRIV_KW);
 147                 if (val != NULL)
 148                         pdef->lim = strdup(val);
 149         }
 150         return (pdef->lim != NULL && pdef->def != NULL);
 151 }
 152 
 153 /*
 154  *      unix_cred - pam_sm_setcred
 155  *
 156  *      Entry flags =   PAM_ESTABLISH_CRED, set up Solaris Unix cred.
 157  *                      PAM_DELETE_CRED, NOP, return PAM_SUCCESS.
 158  *                      PAM_REINITIALIZE_CRED, set up Solaris Unix cred,
 159  *                              or merge the current context with the new
 160  *                              user.
 161  *                      PAM_REFRESH_CRED, set up Solaris Unix cred.
 162  *                      PAM_SILENT, print no messages to user.
 163  *
 164  *      Returns PAM_SUCCESS, if all successful.
 165  *              PAM_CRED_ERR, if unable to set credentials.
 166  *              PAM_USER_UNKNOWN, if PAM_USER not set, or unable to find
 167  *                      user in databases.
 168  *              PAM_SYSTEM_ERR, if no valid flag, or unable to get/set
 169  *                      user's audit state.
 170  */
 171 
 172 int
 173 pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv)
 174 {
 175         int     i;
 176         int     debug = 0;
 177         uint_t  nowarn = flags & PAM_SILENT;
 178         int     ret = PAM_SUCCESS;
 179         char    *user;
 180         char    *auser;
 181         char    *rhost;
 182         char    *tty;
 183         au_id_t auid;
 184         adt_session_data_t *ah;
 185         adt_termid_t    *termid = NULL;
 186         priv_set_t      *lim, *def, *tset;
 187         char            messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
 188         char            buf[PROJECT_BUFSZ];
 189         struct project  proj, *pproj;
 190         int             error;
 191         char            *projname;
 192         char            *kvs;
 193         struct passwd   pwd;
 194         char            pwbuf[NSS_BUFLEN_PASSWD];
 195         deflim_t        deflim;
 196 
 197         for (i = 0; i < argc; i++) {
 198                 if (strcmp(argv[i], "debug") == 0)
 199                         debug = 1;
 200                 else if (strcmp(argv[i], "nowarn") == 0)
 201                         nowarn |= 1;
 202         }
 203 
 204         if (debug)
 205                 syslog(LOG_AUTH | LOG_DEBUG,
 206                     "pam_unix_cred: pam_sm_setcred(flags = %x, argc= %d)",
 207                     flags, argc);
 208 
 209         (void) pam_get_item(pamh, PAM_USER, (void **)&user);
 210 
 211         if (user == NULL || *user == '\0') {
 212                 syslog(LOG_AUTH | LOG_ERR,
 213                     "pam_unix_cred: USER NULL or empty!\n");
 214                 return (PAM_USER_UNKNOWN);
 215         }
 216         (void) pam_get_item(pamh, PAM_AUSER, (void **)&auser);
 217         (void) pam_get_item(pamh, PAM_RHOST, (void **)&rhost);
 218         (void) pam_get_item(pamh, PAM_TTY, (void **)&tty);
 219         if (debug)
 220                 syslog(LOG_AUTH | LOG_DEBUG,
 221                     "pam_unix_cred: user = %s, auser = %s, rhost = %s, "
 222                     "tty = %s", user,
 223                     (auser == NULL) ? "NULL" : (*auser == '\0') ? "ZERO" :
 224                     auser,
 225                     (rhost == NULL) ? "NULL" : (*rhost == '\0') ? "ZERO" :
 226                     rhost,
 227                     (tty == NULL) ? "NULL" : (*tty == '\0') ? "ZERO" :
 228                     tty);
 229 
 230         /* validate flags */
 231         switch (flags & (PAM_ESTABLISH_CRED | PAM_DELETE_CRED |
 232             PAM_REINITIALIZE_CRED | PAM_REFRESH_CRED)) {
 233         case 0:
 234                 /* set default flag */
 235                 flags |= PAM_ESTABLISH_CRED;
 236                 break;
 237         case PAM_ESTABLISH_CRED:
 238         case PAM_REINITIALIZE_CRED:
 239         case PAM_REFRESH_CRED:
 240                 break;
 241         case PAM_DELETE_CRED:
 242                 return (PAM_SUCCESS);
 243         default:
 244                 syslog(LOG_AUTH | LOG_ERR,
 245                     "pam_unix_cred: invalid flags %x", flags);
 246                 return (PAM_SYSTEM_ERR);
 247         }
 248 
 249         /*
 250          * if auditing on and process audit state not set,
 251          * setup audit context for process.
 252          */
 253         if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) {
 254                 syslog(LOG_AUTH | LOG_ERR,
 255                     "pam_unix_cred: cannot create start audit session %m");
 256                 return (PAM_SYSTEM_ERR);
 257         }
 258         adt_get_auid(ah, &auid);
 259         if (debug) {
 260                 int     auditstate;
 261 
 262                 if (auditon(A_GETCOND, (caddr_t)&auditstate,
 263                     sizeof (auditstate)) != 0) {
 264                         auditstate = AUC_DISABLED;
 265                 }
 266                 syslog(LOG_AUTH | LOG_DEBUG,
 267                     "pam_unix_cred: state = %d, auid = %d", auditstate,
 268                     auid);
 269         }
 270         if (getpwnam_r(user, &pwd, pwbuf, sizeof (pwbuf)) == NULL) {
 271                 syslog(LOG_AUTH | LOG_ERR,
 272                     "pam_unix_cred: cannot get passwd entry for user = %s",
 273                     user);
 274                 ret = PAM_USER_UNKNOWN;
 275                 goto adt_done;
 276         }
 277 
 278         if ((auid == AU_NOAUDITID) &&
 279             (flags & PAM_ESTABLISH_CRED)) {
 280                 struct passwd   apwd;
 281                 char    apwbuf[NSS_BUFLEN_PASSWD];
 282 
 283                 errno = 0;
 284                 if ((rhost == NULL || *rhost == '\0')) {
 285                         if (adt_load_ttyname(tty, &termid) != 0) {
 286                                 if (errno == ENETDOWN) {
 287                                         /*
 288                                          * tolerate not being able to
 289                                          * translate local hostname
 290                                          * to a termid -- it will be
 291                                          * "loopback".
 292                                          */
 293                                         syslog(LOG_AUTH | LOG_ERR,
 294                                             "pam_unix_cred: cannot load "
 295                                             "ttyname: %m, continuing.");
 296                                         goto adt_setuser;
 297                                 } else if (errno != 0) {
 298                                         syslog(LOG_AUTH | LOG_ERR,
 299                                             "pam_unix_cred: cannot load "
 300                                             "ttyname: %m.");
 301                                 } else {
 302                                         syslog(LOG_AUTH | LOG_ERR,
 303                                             "pam_unix_cred: cannot load "
 304                                             "ttyname.");
 305                                 }
 306                                 ret = PAM_SYSTEM_ERR;
 307                                 goto adt_done;
 308                         }
 309                 } else {
 310                         if (adt_load_hostname(rhost, &termid) != 0) {
 311                                 if (errno != 0) {
 312                                         syslog(LOG_AUTH | LOG_ERR,
 313                                             "pam_unix_cred: cannot load "
 314                                             "hostname: %m.");
 315                                 } else {
 316                                         syslog(LOG_AUTH | LOG_ERR,
 317                                             "pam_unix_cred: cannot load "
 318                                             "hostname.");
 319                                 }
 320                                 ret = PAM_SYSTEM_ERR;
 321                                 goto adt_done;
 322                         }
 323                 }
 324 adt_setuser:
 325                 if ((auser != NULL) && (*auser != '\0') &&
 326                     (getpwnam_r(auser, &apwd, apwbuf,
 327                     sizeof (apwbuf)) != NULL)) {
 328                         /*
 329                          * set up the initial audit for user coming
 330                          * from another user
 331                          */
 332                         if (adt_set_user(ah, apwd.pw_uid, apwd.pw_gid,
 333                             apwd.pw_uid, apwd.pw_gid, termid, ADT_NEW) != 0) {
 334                                 syslog(LOG_AUTH | LOG_ERR,
 335                                     "pam_unix_cred: cannot set auser audit "
 336                                     "%m");
 337                                 ret = PAM_SYSTEM_ERR;
 338                                 goto adt_done;
 339                         }
 340                         if (adt_set_user(ah, pwd.pw_uid, pwd.pw_gid,
 341                             pwd.pw_uid, pwd.pw_gid, NULL,
 342                             ADT_UPDATE) != 0) {
 343                                 syslog(LOG_AUTH | LOG_ERR,
 344                                     "pam_unix_cred: cannot merge user audit "
 345                                     "%m");
 346                                 ret = PAM_SYSTEM_ERR;
 347                                 goto adt_done;
 348                         }
 349                         if (debug) {
 350                                 syslog(LOG_AUTH | LOG_DEBUG,
 351                                     "pam_unix_cred: new audit set for %d:%d",
 352                                     apwd.pw_uid, pwd.pw_uid);
 353                         }
 354                 } else {
 355                         /*
 356                          * No authenticated user or authenticated user is
 357                          * not a local user, no remote attribution, set
 358                          * up the initial audit as for direct user login
 359                          */
 360                         if (adt_set_user(ah, pwd.pw_uid, pwd.pw_gid,
 361                             pwd.pw_uid, pwd.pw_gid, termid, ADT_NEW) != 0) {
 362                                 syslog(LOG_AUTH | LOG_ERR,
 363                                     "pam_unix_cred: cannot set user audit %m");
 364                                 ret = PAM_SYSTEM_ERR;
 365                                 goto adt_done;
 366                         }
 367                 }
 368                 if (adt_set_proc(ah) != 0) {
 369                         syslog(LOG_AUTH | LOG_ERR,
 370                             "pam_unix_cred: cannot set process audit %m");
 371                         ret = PAM_CRED_ERR;
 372                         goto adt_done;
 373                 }
 374                 if (debug) {
 375                         syslog(LOG_AUTH | LOG_DEBUG,
 376                             "pam_unix_cred: new audit set for %d",
 377                             pwd.pw_uid);
 378                 }
 379         } else if ((auid != AU_NOAUDITID) &&
 380             (flags & PAM_REINITIALIZE_CRED)) {
 381                 if (adt_set_user(ah, pwd.pw_uid, pwd.pw_gid, pwd.pw_uid,
 382                     pwd.pw_gid, NULL, ADT_UPDATE) != 0) {
 383                         syslog(LOG_AUTH | LOG_ERR,
 384                             "pam_unix_cred: cannot set user audit %m");
 385                         ret = PAM_SYSTEM_ERR;
 386                         goto adt_done;
 387                 }
 388                 if (adt_set_proc(ah) != 0) {
 389                         syslog(LOG_AUTH | LOG_ERR,
 390                             "pam_unix_cred: cannot set process audit %m");
 391                         ret = PAM_CRED_ERR;
 392                         goto adt_done;
 393                 }
 394                 if (debug) {
 395                         syslog(LOG_AUTH | LOG_DEBUG,
 396                             "pam_unix_cred: audit merged for %d:%d",
 397                             auid, pwd.pw_uid);
 398                 }
 399         } else if (debug) {
 400                 syslog(LOG_AUTH | LOG_DEBUG,
 401                     "pam_unix_cred: audit already set for %d", auid);
 402         }
 403 adt_done:
 404         if (termid != NULL)
 405                 free(termid);
 406         if (adt_end_session(ah) != 0) {
 407                 syslog(LOG_AUTH | LOG_ERR,
 408                     "pam_unix_cred: unable to end audit session");
 409         }
 410 
 411         if (ret != PAM_SUCCESS)
 412                 return (ret);
 413 
 414         /* Initialize the user's project */
 415         (void) pam_get_item(pamh, PAM_RESOURCE, (void **)&kvs);
 416         if (kvs != NULL) {
 417                 char *tmp, *lasts, *tok;
 418 
 419                 kvs = tmp = strdup(kvs);
 420                 if (kvs == NULL)
 421                         return (PAM_BUF_ERR);
 422 
 423                 while ((tok = strtok_r(tmp, ";", &lasts)) != NULL) {
 424                         if (strncmp(tok, PROJECT, PROJSZ) == 0) {
 425                                 projname = tok + PROJSZ;
 426                                 break;
 427                         }
 428                         tmp = NULL;
 429                 }
 430         } else {
 431                 projname = NULL;
 432         }
 433 
 434         if (projname == NULL || *projname == '\0') {
 435                 pproj = getdefaultproj(user, &proj, (void *)&buf,
 436                     PROJECT_BUFSZ);
 437         } else {
 438                 pproj = getprojbyname(projname, &proj, (void *)&buf,
 439                     PROJECT_BUFSZ);
 440         }
 441         /* projname points into kvs, so this is the first opportunity to free */
 442         if (kvs != NULL)
 443                 free(kvs);
 444         if (pproj == NULL) {
 445                 syslog(LOG_AUTH | LOG_ERR,
 446                     "pam_unix_cred: no default project for user %s", user);
 447                 if (!nowarn) {
 448                         (void) snprintf(messages[0], sizeof (messages[0]),
 449                             dgettext(TEXT_DOMAIN, "No default project!"));
 450                         (void) __pam_display_msg(pamh, PAM_ERROR_MSG,
 451                             1, messages, NULL);
 452                 }
 453                 return (PAM_SYSTEM_ERR);
 454         }
 455         if ((error = setproject(proj.pj_name, user, TASK_NORMAL)) != 0) {
 456                 kva_t *kv_array;
 457 
 458                 switch (error) {
 459                 case SETPROJ_ERR_TASK:
 460                         if (errno == EAGAIN) {
 461                                 syslog(LOG_AUTH | LOG_ERR,
 462                                     "pam_unix_cred: project \"%s\" resource "
 463                                     "control limit has been reached",
 464                                     proj.pj_name);
 465                                 (void) snprintf(messages[0],
 466                                     sizeof (messages[0]), dgettext(
 467                                     TEXT_DOMAIN,
 468                                     "Resource control limit has been "
 469                                     "reached"));
 470                         } else {
 471                                 syslog(LOG_AUTH | LOG_ERR,
 472                                     "pam_unix_cred: user %s could not join "
 473                                     "project \"%s\": %m", user, proj.pj_name);
 474                                 (void) snprintf(messages[0],
 475                                     sizeof (messages[0]), dgettext(
 476                                     TEXT_DOMAIN,
 477                                     "Could not join default project"));
 478                         }
 479                         if (!nowarn)
 480                                 (void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1,
 481                                     messages, NULL);
 482                         break;
 483                 case SETPROJ_ERR_POOL:
 484                         (void) snprintf(messages[0], sizeof (messages[0]),
 485                             dgettext(TEXT_DOMAIN,
 486                             "Could not bind to resource pool"));
 487                         switch (errno) {
 488                         case EACCES:
 489                                 syslog(LOG_AUTH | LOG_ERR,
 490                                     "pam_unix_cred: project \"%s\" could not "
 491                                     "bind to resource pool: No resource pool "
 492                                     "accepting default bindings exists",
 493                                     proj.pj_name);
 494                                 (void) snprintf(messages[1],
 495                                     sizeof (messages[1]),
 496                                     dgettext(TEXT_DOMAIN,
 497                                     "No resource pool accepting "
 498                                     "default bindings exists"));
 499                                 break;
 500                         case ESRCH:
 501                                 syslog(LOG_AUTH | LOG_ERR,
 502                                     "pam_unix_cred: project \"%s\" could not "
 503                                     "bind to resource pool: The resource pool "
 504                                     "is unknown", proj.pj_name);
 505                                 (void) snprintf(messages[1],
 506                                     sizeof (messages[1]),
 507                                     dgettext(TEXT_DOMAIN,
 508                                     "The specified resource pool "
 509                                     "is unknown"));
 510                                 break;
 511                         default:
 512                                 (void) snprintf(messages[1],
 513                                     sizeof (messages[1]),
 514                                     dgettext(TEXT_DOMAIN,
 515                                     "Failure during pool binding"));
 516                                 syslog(LOG_AUTH | LOG_ERR,
 517                                     "pam_unix_cred: project \"%s\" could not "
 518                                     "bind to resource pool: %m", proj.pj_name);
 519                         }
 520                         if (!nowarn)
 521                                 (void) __pam_display_msg(pamh, PAM_ERROR_MSG,
 522                                     2, messages, NULL);
 523                         break;
 524                 default:
 525                         /*
 526                          * Resource control assignment failed.  Unlike
 527                          * newtask(1m), we treat this as an error.
 528                          */
 529                         if (error < 0) {
 530                                 /*
 531                                  * This isn't supposed to happen, but in
 532                                  * case it does, this error message
 533                                  * doesn't use error as an index, like
 534                                  * the others might.
 535                                  */
 536                                 syslog(LOG_AUTH | LOG_ERR,
 537                                     "pam_unix_cred: unkwown error joining "
 538                                     "project \"%s\" (%d)", proj.pj_name, error);
 539                                 (void) snprintf(messages[0],
 540                                     sizeof (messages[0]),
 541                                     dgettext(TEXT_DOMAIN,
 542                                     "unkwown error joining project \"%s\""
 543                                     " (%d)"), proj.pj_name, error);
 544                         } else if ((kv_array = _str2kva(proj.pj_attr, KV_ASSIGN,
 545                             KV_DELIMITER)) != NULL) {
 546                                 syslog(LOG_AUTH | LOG_ERR,
 547                                     "pam_unix_cred: %s resource control "
 548                                     "assignment failed for project \"%s\"",
 549                                     kv_array->data[error - 1].key,
 550                                     proj.pj_name);
 551                                 (void) snprintf(messages[0],
 552                                     sizeof (messages[0]),
 553                                     dgettext(TEXT_DOMAIN,
 554                                     "%s resource control assignment failed for "
 555                                     "project \"%s\""),
 556                                     kv_array->data[error - 1].key,
 557                                     proj.pj_name);
 558                                 _kva_free(kv_array);
 559                         } else {
 560                                 syslog(LOG_AUTH | LOG_ERR,
 561                                     "pam_unix_cred: resource control "
 562                                     "assignment failed for project \"%s\""
 563                                     "attribute %d", proj.pj_name, error);
 564                                 (void) snprintf(messages[0],
 565                                     sizeof (messages[0]),
 566                                     dgettext(TEXT_DOMAIN,
 567                                     "resource control assignment failed for "
 568                                     "project \"%s\" attribute %d"),
 569                                     proj.pj_name, error);
 570                         }
 571                         if (!nowarn)
 572                                 (void) __pam_display_msg(pamh, PAM_ERROR_MSG,
 573                                     1, messages, NULL);
 574                 }
 575                 return (PAM_SYSTEM_ERR);
 576         }
 577 
 578         tset = def = lim = NULL;
 579         deflim.def = deflim.lim = NULL;
 580 
 581         (void) _enum_attrs(user, finddeflim, NULL, &deflim);
 582 
 583         if (getset(deflim.lim, &lim) != 0 || getset(deflim.def, &def) != 0) {
 584                 ret = PAM_SYSTEM_ERR;
 585                 goto out;
 586         }
 587 
 588         if (def == NULL) {
 589                 def = priv_allocset();
 590                 if (def == NULL) {
 591                         ret = PAM_SYSTEM_ERR;
 592                         goto out;
 593                 }
 594                 priv_basicset(def);
 595                 errno = 0;
 596                 if ((pathconf("/", _PC_CHOWN_RESTRICTED) == -1) && (errno == 0))
 597                         (void) priv_addset(def, PRIV_FILE_CHOWN_SELF);
 598         }
 599         /*
 600          * Silently limit the privileges to those actually available
 601          * in the current zone.
 602          */
 603         tset = priv_allocset();
 604         if (tset == NULL) {
 605                 ret = PAM_SYSTEM_ERR;
 606                 goto out;
 607         }
 608         if (getppriv(PRIV_PERMITTED, tset) != 0) {
 609                 ret = PAM_SYSTEM_ERR;
 610                 goto out;
 611         }
 612         if (!priv_issubset(def, tset))
 613                 priv_intersect(tset, def);
 614         /*
 615          * We set privilege awareness here so that I gets copied to
 616          * P & E when the final setuid(uid) happens.
 617          */
 618         (void) setpflags(PRIV_AWARE, 1);
 619         if (setppriv(PRIV_SET, PRIV_INHERITABLE, def) != 0) {
 620                 syslog(LOG_AUTH | LOG_ERR,
 621                     "pam_setcred: setppriv(defaultpriv) failed: %m");
 622                 ret = PAM_CRED_ERR;
 623         }
 624 
 625         if (lim != NULL) {
 626                 /*
 627                  * Silently limit the privileges to the limit set available.
 628                  */
 629                 if (getppriv(PRIV_LIMIT, tset) != 0) {
 630                         ret = PAM_SYSTEM_ERR;
 631                         goto out;
 632                 }
 633                 if (!priv_issubset(lim, tset))
 634                         priv_intersect(tset, lim);
 635                 if (setppriv(PRIV_SET, PRIV_LIMIT, lim) != 0) {
 636                         syslog(LOG_AUTH | LOG_ERR,
 637                             "pam_setcred: setppriv(limitpriv) failed: %m");
 638                         ret = PAM_CRED_ERR;
 639                         goto out;
 640                 }
 641                 /*
 642                  * In order not to surprise certain applications, we
 643                  * need to get rid of privilege awareness and thus we must
 644                  * set this flag which will cause a reset on set*uid().
 645                  */
 646                 (void) setpflags(PRIV_AWARE_RESET, 1);
 647         }
 648         /*
 649          * This may fail but we do not care as this will be reset later
 650          * when the uids are set to their final values.
 651          */
 652         (void) setpflags(PRIV_AWARE, 0);
 653         /*
 654          * Remove PRIV_PFEXEC; stop running as if we are under a profile
 655          * shell.  A user with a profile shell will set PRIV_PFEXEC.
 656          */
 657         (void) setpflags(PRIV_PFEXEC, 0);
 658 
 659 out:
 660         free(deflim.lim);
 661         free(deflim.def);
 662 
 663         if (lim != NULL)
 664                 priv_freeset(lim);
 665         if (def != NULL)
 666                 priv_freeset(def);
 667         if (tset != NULL)
 668                 priv_freeset(tset);
 669 
 670         return (ret);
 671 }