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) 1993, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
  24  */
  25 
  26 /*LINTLIBRARY*/
  27 
  28 #include <grp.h>
  29 #include <pwd.h>
  30 #include <string.h>
  31 #include <limits.h>
  32 #include <stdlib.h>
  33 #include <errno.h>
  34 #include <sys/param.h>
  35 #include <sys/types.h>
  36 #include <sys/stat.h>
  37 #include <sys/acl.h>
  38 #include <aclutils.h>
  39 #include <idmap.h>
  40 #include <synch.h>
  41 
  42 #define ID_STR_MAX      20      /* digits in LONG_MAX */
  43 
  44 #define APPENDED_ID_MAX ID_STR_MAX + 1          /* id + colon */
  45 /*
  46  * yyinteractive controls whether yyparse should print out
  47  * error messages to stderr, and whether or not id's should be
  48  * allowed from acl_fromtext().
  49  */
  50 int     yyinteractive;
  51 acl_t   *yyacl;
  52 char    *yybuf;
  53 mutex_t yymutex;
  54 
  55 extern acl_t *acl_alloc(enum acl_type);
  56 
  57 /*
  58  * dynamic string that will increase in size on an
  59  * as needed basis.
  60  */
  61 typedef struct dynaclstr {
  62         size_t d_bufsize;               /* current size of aclexport */
  63         char *d_aclexport;
  64         int d_pos;
  65 } dynaclstr_t;
  66 
  67 static int str_append(dynaclstr_t *, char *);
  68 static int aclent_perm_txt(dynaclstr_t *, o_mode_t);
  69 
  70 static void
  71 aclent_perms(int perm, char *txt_perms)
  72 {
  73         if (perm & S_IROTH)
  74                 txt_perms[0] = 'r';
  75         else
  76                 txt_perms[0] = '-';
  77         if (perm & S_IWOTH)
  78                 txt_perms[1] = 'w';
  79         else
  80                 txt_perms[1] = '-';
  81         if (perm & S_IXOTH)
  82                 txt_perms[2] = 'x';
  83         else
  84                 txt_perms[2] = '-';
  85         txt_perms[3] = '\0';
  86 }
  87 
  88 static char *
  89 pruname(uid_t uid, char *uidp, size_t buflen, int noresolve)
  90 {
  91         struct passwd   *passwdp = NULL;
  92 
  93         if (noresolve == 0)
  94                 passwdp = getpwuid(uid);
  95         if (passwdp == (struct passwd *)NULL) {
  96                 /* could not get passwd information: display uid instead */
  97                 (void) snprintf(uidp, buflen, "%u", uid);
  98         } else {
  99                 (void) strlcpy(uidp, passwdp->pw_name, buflen);
 100         }
 101         return (uidp);
 102 }
 103 
 104 static char *
 105 prgname(gid_t gid, char *gidp, size_t buflen, int noresolve)
 106 {
 107         struct group    *groupp = NULL;
 108 
 109         if (noresolve == 0)
 110                 groupp = getgrgid(gid);
 111         if (groupp == (struct group *)NULL) {
 112                 /* could not get group information: display gid instead */
 113                 (void) snprintf(gidp, buflen, "%u", gid);
 114         } else {
 115                 (void) strlcpy(gidp, groupp->gr_name, buflen);
 116         }
 117         return (gidp);
 118 }
 119 
 120 static int
 121 getsidname(uid_t who, boolean_t user, char **sidp, boolean_t noresolve)
 122 {
 123         idmap_get_handle_t *get_hdl = NULL;
 124         idmap_stat status;
 125         idmap_rid_t rid;
 126         int error = IDMAP_ERR_NORESULT;
 127         int len;
 128         char *domain = NULL;
 129 
 130         *sidp = NULL;
 131 
 132         /*
 133          * First try and get windows name
 134          */
 135 
 136         if (!noresolve) {
 137                 if (user)
 138                         error = idmap_getwinnamebyuid(who,
 139                             IDMAP_REQ_FLG_USE_CACHE, sidp, NULL);
 140                 else
 141                         error = idmap_getwinnamebygid(who,
 142                             IDMAP_REQ_FLG_USE_CACHE, sidp, NULL);
 143         }
 144         if (error != IDMAP_SUCCESS) {
 145                 if (idmap_get_create(&get_hdl) == IDMAP_SUCCESS) {
 146                         if (user)
 147                                 error = idmap_get_sidbyuid(get_hdl, who,
 148                                     IDMAP_REQ_FLG_USE_CACHE, &domain, &rid,
 149                                     &status);
 150                         else
 151                                 error = idmap_get_sidbygid(get_hdl, who,
 152                                     IDMAP_REQ_FLG_USE_CACHE, &domain, &rid,
 153                                     &status);
 154                         if (error == IDMAP_SUCCESS &&
 155                             idmap_get_mappings(get_hdl) == 0) {
 156                                 if (status == IDMAP_SUCCESS) {
 157                                         len = snprintf(NULL, 0,
 158                                             "%s-%d", domain, rid);
 159                                         if (*sidp = malloc(len + 1)) {
 160                                                 (void) snprintf(*sidp, len + 1,
 161                                                     "%s-%d", domain, rid);
 162                                         }
 163                                 }
 164                         }
 165                 }
 166                 if (get_hdl)
 167                         idmap_get_destroy(get_hdl);
 168         }
 169 
 170         free(domain);
 171 
 172         return (*sidp ? 0 : 1);
 173 }
 174 
 175 /*
 176  * sid_string_by_id() is an exposed interface via -lsec
 177  */
 178 int
 179 sid_string_by_id(uid_t who, boolean_t user, char **sidp, boolean_t noresolve)
 180 {
 181         return (getsidname(who, user, sidp, noresolve));
 182 }
 183 
 184 static void
 185 aclent_printacl(acl_t *aclp)
 186 {
 187         aclent_t *tp;
 188         int aclcnt;
 189         int mask;
 190         int slot = 0;
 191         char perm[4];
 192         char uidp[ID_STR_MAX];
 193         char gidp[ID_STR_MAX];
 194 
 195         /* display ACL: assume it is sorted. */
 196         aclcnt = aclp->acl_cnt;
 197         for (tp = aclp->acl_aclp; tp && aclcnt--; tp++) {
 198                 if (tp->a_type == CLASS_OBJ)
 199                         mask = tp->a_perm;
 200         }
 201         aclcnt = aclp->acl_cnt;
 202         for (tp = aclp->acl_aclp; aclcnt--; tp++) {
 203                 (void) printf("     %d:", slot++);
 204                 switch (tp->a_type) {
 205                 case USER:
 206                         aclent_perms(tp->a_perm, perm);
 207                         (void) printf("user:%s:%s\t\t",
 208                             pruname(tp->a_id, uidp, sizeof (uidp), 0), perm);
 209                         aclent_perms((tp->a_perm & mask), perm);
 210                         (void) printf("#effective:%s\n", perm);
 211                         break;
 212                 case USER_OBJ:
 213                         /* no need to display uid */
 214                         aclent_perms(tp->a_perm, perm);
 215                         (void) printf("user::%s\n", perm);
 216                         break;
 217                 case GROUP:
 218                         aclent_perms(tp->a_perm, perm);
 219                         (void) printf("group:%s:%s\t\t",
 220                             prgname(tp->a_id, gidp, sizeof (gidp), 0), perm);
 221                         aclent_perms(tp->a_perm & mask, perm);
 222                         (void) printf("#effective:%s\n", perm);
 223                         break;
 224                 case GROUP_OBJ:
 225                         aclent_perms(tp->a_perm, perm);
 226                         (void) printf("group::%s\t\t", perm);
 227                         aclent_perms(tp->a_perm & mask, perm);
 228                         (void) printf("#effective:%s\n", perm);
 229                         break;
 230                 case CLASS_OBJ:
 231                         aclent_perms(tp->a_perm, perm);
 232                         (void) printf("mask:%s\n", perm);
 233                         break;
 234                 case OTHER_OBJ:
 235                         aclent_perms(tp->a_perm, perm);
 236                         (void) printf("other:%s\n", perm);
 237                         break;
 238                 case DEF_USER:
 239                         aclent_perms(tp->a_perm, perm);
 240                         (void) printf("default:user:%s:%s\n",
 241                             pruname(tp->a_id, uidp, sizeof (uidp), 0), perm);
 242                         break;
 243                 case DEF_USER_OBJ:
 244                         aclent_perms(tp->a_perm, perm);
 245                         (void) printf("default:user::%s\n", perm);
 246                         break;
 247                 case DEF_GROUP:
 248                         aclent_perms(tp->a_perm, perm);
 249                         (void) printf("default:group:%s:%s\n",
 250                             prgname(tp->a_id, gidp, sizeof (gidp), 0), perm);
 251                         break;
 252                 case DEF_GROUP_OBJ:
 253                         aclent_perms(tp->a_perm, perm);
 254                         (void) printf("default:group::%s\n", perm);
 255                         break;
 256                 case DEF_CLASS_OBJ:
 257                         aclent_perms(tp->a_perm, perm);
 258                         (void) printf("default:mask:%s\n", perm);
 259                         break;
 260                 case DEF_OTHER_OBJ:
 261                         aclent_perms(tp->a_perm, perm);
 262                         (void) printf("default:other:%s\n", perm);
 263                         break;
 264                 default:
 265                         (void) fprintf(stderr,
 266                             dgettext(TEXT_DOMAIN, "unrecognized entry\n"));
 267                         break;
 268                 }
 269         }
 270 }
 271 
 272 static void
 273 split_line(char *str, int cols)
 274 {
 275         char *ptr;
 276         int len;
 277         int i;
 278         int last_split;
 279         char *pad = "";
 280         int pad_len;
 281 
 282         len = strlen(str);
 283         ptr = str;
 284         pad_len = 0;
 285 
 286         ptr = str;
 287         last_split = 0;
 288         for (i = 0; i != len; i++) {
 289                 if ((i + pad_len + 4) >= cols) {
 290                         (void) printf("%s%.*s\n", pad, last_split, ptr);
 291                         ptr = &ptr[last_split];
 292                         len = strlen(ptr);
 293                         i = 0;
 294                         pad_len = 4;
 295                         pad = "         ";
 296                 } else {
 297                         if (ptr[i] == '/' || ptr[i] == ':') {
 298                                 last_split = i;
 299                         }
 300                 }
 301         }
 302         if (i == len) {
 303                 (void) printf("%s%s\n", pad, ptr);
 304         }
 305 }
 306 
 307 /*
 308  * compute entry type string, such as user:joe, group:staff,...
 309  */
 310 static int
 311 aclent_type_txt(dynaclstr_t *dstr, aclent_t *aclp, int flags)
 312 {
 313         char idp[ID_STR_MAX];
 314         int error;
 315 
 316         switch (aclp->a_type) {
 317         case DEF_USER_OBJ:
 318         case USER_OBJ:
 319                 if (aclp->a_type == USER_OBJ)
 320                         error = str_append(dstr, "user::");
 321                 else
 322                         error = str_append(dstr, "defaultuser::");
 323                 break;
 324 
 325         case DEF_USER:
 326         case USER:
 327                 if (aclp->a_type == USER)
 328                         error = str_append(dstr, "user:");
 329                 else
 330                         error = str_append(dstr, "defaultuser:");
 331                 if (error)
 332                         break;
 333                 error = str_append(dstr, pruname(aclp->a_id, idp,
 334                     sizeof (idp), flags & ACL_NORESOLVE));
 335                 if (error == 0)
 336                         error = str_append(dstr, ":");
 337                 break;
 338 
 339         case DEF_GROUP_OBJ:
 340         case GROUP_OBJ:
 341                 if (aclp->a_type == GROUP_OBJ)
 342                         error = str_append(dstr, "group::");
 343                 else
 344                         error = str_append(dstr, "defaultgroup::");
 345                 break;
 346 
 347         case DEF_GROUP:
 348         case GROUP:
 349                 if (aclp->a_type == GROUP)
 350                         error = str_append(dstr, "group:");
 351                 else
 352                         error = str_append(dstr, "defaultgroup:");
 353                 if (error)
 354                         break;
 355                 error = str_append(dstr, prgname(aclp->a_id, idp,
 356                     sizeof (idp), flags & ACL_NORESOLVE));
 357                 if (error == 0)
 358                         error = str_append(dstr, ":");
 359                 break;
 360 
 361         case DEF_CLASS_OBJ:
 362         case CLASS_OBJ:
 363                 if (aclp->a_type == CLASS_OBJ)
 364                         error = str_append(dstr, "mask:");
 365                 else
 366                         error = str_append(dstr, "defaultmask:");
 367                 break;
 368 
 369         case DEF_OTHER_OBJ:
 370         case OTHER_OBJ:
 371                 if (aclp->a_type == OTHER_OBJ)
 372                         error = str_append(dstr, "other:");
 373                 else
 374                         error = str_append(dstr, "defaultother:");
 375                 break;
 376 
 377         default:
 378                 error = 1;
 379                 break;
 380         }
 381 
 382         return (error);
 383 }
 384 
 385 /*
 386  * compute entry type string such as, owner@:, user:joe, group:staff,...
 387  */
 388 static int
 389 ace_type_txt(dynaclstr_t *dynstr, ace_t *acep, int flags)
 390 {
 391         char idp[ID_STR_MAX];
 392         int error;
 393         char *sidp = NULL;
 394 
 395         switch (acep->a_flags & ACE_TYPE_FLAGS) {
 396         case ACE_OWNER:
 397                 error = str_append(dynstr, OWNERAT_TXT);
 398                 break;
 399 
 400         case ACE_GROUP|ACE_IDENTIFIER_GROUP:
 401                 error = str_append(dynstr, GROUPAT_TXT);
 402                 break;
 403 
 404         case ACE_IDENTIFIER_GROUP:
 405                 if ((flags & ACL_SID_FMT) && acep->a_who > MAXUID) {
 406                         if (error = str_append(dynstr,
 407                             GROUPSID_TXT))
 408                                 break;
 409                         if (error = getsidname(acep->a_who, B_FALSE,
 410                             &sidp, flags & ACL_NORESOLVE))
 411                                 break;
 412                         error = str_append(dynstr, sidp);
 413                 } else {
 414                         if (error = str_append(dynstr, GROUP_TXT))
 415                                 break;
 416                         error = str_append(dynstr, prgname(acep->a_who, idp,
 417                             sizeof (idp), flags & ACL_NORESOLVE));
 418                 }
 419                 if (error == 0)
 420                         error = str_append(dynstr, ":");
 421                 break;
 422 
 423         case ACE_EVERYONE:
 424                 error = str_append(dynstr, EVERYONEAT_TXT);
 425                 break;
 426 
 427         case 0:
 428                 if ((flags & ACL_SID_FMT) && acep->a_who > MAXUID &&
 429                     (flags & ACL_EPHEMERAL) == 0) {
 430                         if (error = str_append(dynstr, USERSID_TXT))
 431                                 break;
 432                         if (error = getsidname(acep->a_who, B_TRUE,
 433                             &sidp, flags & ACL_NORESOLVE))
 434                                 break;
 435                         error = str_append(dynstr, sidp);
 436                 } else {
 437                         flags &= ~ACL_NORESOLVE;
 438                         if (error = str_append(dynstr, USER_TXT))
 439                                 break;
 440                         error = str_append(dynstr, pruname(acep->a_who, idp,
 441                             sizeof (idp), flags & ACL_NORESOLVE));
 442                 }
 443                 if (error == 0)
 444                         error = str_append(dynstr, ":");
 445                 break;
 446         default:
 447                 error = 0;
 448                 break;
 449         }
 450 
 451         if (sidp)
 452                 free(sidp);
 453         return (error);
 454 }
 455 
 456 /*
 457  * compute string of permissions, such as read_data/write_data or
 458  * rwxp,...
 459  * The format depends on the flags field which indicates whether the compact
 460  * or verbose format should be used.
 461  */
 462 static int
 463 ace_perm_txt(dynaclstr_t *dstr, uint32_t mask,
 464     uint32_t iflags, int isdir, int flags)
 465 {
 466         int error = 0;
 467 
 468         if (flags & ACL_COMPACT_FMT) {
 469                 char buf[16];
 470 
 471                 if (mask & ACE_READ_DATA)
 472                         buf[0] = 'r';
 473                 else
 474                         buf[0] = '-';
 475                 if (mask & ACE_WRITE_DATA)
 476                         buf[1] = 'w';
 477                 else
 478                         buf[1] = '-';
 479                 if (mask & ACE_EXECUTE)
 480                         buf[2] = 'x';
 481                 else
 482                         buf[2] = '-';
 483                 if (mask & ACE_APPEND_DATA)
 484                         buf[3] = 'p';
 485                 else
 486                         buf[3] = '-';
 487                 if (mask & ACE_DELETE)
 488                         buf[4] = 'd';
 489                 else
 490                         buf[4] = '-';
 491                 if (mask & ACE_DELETE_CHILD)
 492                         buf[5] = 'D';
 493                 else
 494                         buf[5] = '-';
 495                 if (mask & ACE_READ_ATTRIBUTES)
 496                         buf[6] = 'a';
 497                 else
 498                         buf[6] = '-';
 499                 if (mask & ACE_WRITE_ATTRIBUTES)
 500                         buf[7] = 'A';
 501                 else
 502                         buf[7] = '-';
 503                 if (mask & ACE_READ_NAMED_ATTRS)
 504                         buf[8] = 'R';
 505                 else
 506                         buf[8] = '-';
 507                 if (mask & ACE_WRITE_NAMED_ATTRS)
 508                         buf[9] = 'W';
 509                 else
 510                         buf[9] = '-';
 511                 if (mask & ACE_READ_ACL)
 512                         buf[10] = 'c';
 513                 else
 514                         buf[10] = '-';
 515                 if (mask & ACE_WRITE_ACL)
 516                         buf[11] = 'C';
 517                 else
 518                         buf[11] = '-';
 519                 if (mask & ACE_WRITE_OWNER)
 520                         buf[12] = 'o';
 521                 else
 522                         buf[12] = '-';
 523                 if (mask & ACE_SYNCHRONIZE)
 524                         buf[13] = 's';
 525                 else
 526                         buf[13] = '-';
 527                 buf[14] = ':';
 528                 buf[15] = '\0';
 529                 error = str_append(dstr, buf);
 530         } else {
 531                 /*
 532                  * If ACE is a directory, but inheritance indicates its
 533                  * for a file then print permissions for file rather than
 534                  * dir.
 535                  */
 536                 if (isdir) {
 537                         if (mask & ACE_LIST_DIRECTORY) {
 538                                 if (iflags == ACE_FILE_INHERIT_ACE) {
 539                                         error = str_append(dstr,
 540                                             READ_DATA_TXT);
 541                                 } else {
 542                                         error =
 543                                             str_append(dstr, READ_DIR_TXT);
 544                                 }
 545                         }
 546                         if (error == 0 && (mask & ACE_ADD_FILE)) {
 547                                 if (iflags == ACE_FILE_INHERIT_ACE) {
 548                                         error =
 549                                             str_append(dstr, WRITE_DATA_TXT);
 550                                 } else {
 551                                         error =
 552                                             str_append(dstr, ADD_FILE_TXT);
 553                                 }
 554                         }
 555                         if (error == 0 && (mask & ACE_ADD_SUBDIRECTORY)) {
 556                                 if (iflags == ACE_FILE_INHERIT_ACE) {
 557                                         error = str_append(dstr,
 558                                             APPEND_DATA_TXT);
 559                                 } else {
 560                                         error = str_append(dstr,
 561                                             ADD_DIR_TXT);
 562                                 }
 563                         }
 564                 } else {
 565                         if (mask & ACE_READ_DATA) {
 566                                 error = str_append(dstr, READ_DATA_TXT);
 567                         }
 568                         if (error == 0 && (mask & ACE_WRITE_DATA)) {
 569                                 error = str_append(dstr, WRITE_DATA_TXT);
 570                         }
 571                         if (error == 0 && (mask & ACE_APPEND_DATA)) {
 572                                 error = str_append(dstr, APPEND_DATA_TXT);
 573                         }
 574                 }
 575                 if (error == 0 && (mask & ACE_READ_NAMED_ATTRS)) {
 576                         error = str_append(dstr, READ_XATTR_TXT);
 577                 }
 578                 if (error == 0 && (mask & ACE_WRITE_NAMED_ATTRS)) {
 579                         error = str_append(dstr, WRITE_XATTR_TXT);
 580                 }
 581                 if (error == 0 && (mask & ACE_EXECUTE)) {
 582                         error = str_append(dstr, EXECUTE_TXT);
 583                 }
 584                 if (error == 0 && (mask & ACE_DELETE_CHILD)) {
 585                         error = str_append(dstr, DELETE_CHILD_TXT);
 586                 }
 587                 if (error == 0 && (mask & ACE_READ_ATTRIBUTES)) {
 588                         error = str_append(dstr, READ_ATTRIBUTES_TXT);
 589                 }
 590                 if (error == 0 && (mask & ACE_WRITE_ATTRIBUTES)) {
 591                         error = str_append(dstr, WRITE_ATTRIBUTES_TXT);
 592                 }
 593                 if (error == 0 && (mask & ACE_DELETE)) {
 594                         error = str_append(dstr, DELETE_TXT);
 595                 }
 596                 if (error == 0 && (mask & ACE_READ_ACL)) {
 597                         error = str_append(dstr, READ_ACL_TXT);
 598                 }
 599                 if (error == 0 && (mask & ACE_WRITE_ACL)) {
 600                         error = str_append(dstr, WRITE_ACL_TXT);
 601                 }
 602                 if (error == 0 && (mask & ACE_WRITE_OWNER)) {
 603                         error = str_append(dstr, WRITE_OWNER_TXT);
 604                 }
 605                 if (error == 0 && (mask & ACE_SYNCHRONIZE)) {
 606                         error = str_append(dstr, SYNCHRONIZE_TXT);
 607                 }
 608                 if (error == 0 && dstr->d_aclexport[dstr->d_pos-1] == '/') {
 609                         dstr->d_aclexport[--dstr->d_pos] = '\0';
 610                 }
 611                 if (error == 0)
 612                         error = str_append(dstr, ":");
 613         }
 614         return (error);
 615 }
 616 
 617 /*
 618  * compute string of access type, such as allow, deny, ...
 619  */
 620 static int
 621 ace_access_txt(dynaclstr_t *dstr, int type)
 622 {
 623         int error;
 624 
 625         if (type == ACE_ACCESS_ALLOWED_ACE_TYPE)
 626                 error = str_append(dstr, ALLOW_TXT);
 627         else if (type == ACE_ACCESS_DENIED_ACE_TYPE)
 628                 error = str_append(dstr, DENY_TXT);
 629         else if (type == ACE_SYSTEM_AUDIT_ACE_TYPE)
 630                 error = str_append(dstr, AUDIT_TXT);
 631         else if (type == ACE_SYSTEM_ALARM_ACE_TYPE)
 632                 error = str_append(dstr, ALARM_TXT);
 633         else
 634                 error = str_append(dstr, UNKNOWN_TXT);
 635 
 636         return (error);
 637 }
 638 
 639 static int
 640 ace_inherit_txt(dynaclstr_t *dstr, uint32_t iflags, int flags)
 641 {
 642         int error = 0;
 643 
 644         if (flags & ACL_COMPACT_FMT) {
 645                 char buf[9];
 646 
 647                 if (iflags & ACE_FILE_INHERIT_ACE)
 648                         buf[0] = 'f';
 649                 else
 650                         buf[0] = '-';
 651                 if (iflags & ACE_DIRECTORY_INHERIT_ACE)
 652                         buf[1] = 'd';
 653                 else
 654                         buf[1] = '-';
 655                 if (iflags & ACE_INHERIT_ONLY_ACE)
 656                         buf[2] = 'i';
 657                 else
 658                         buf[2] = '-';
 659                 if (iflags & ACE_NO_PROPAGATE_INHERIT_ACE)
 660                         buf[3] = 'n';
 661                 else
 662                         buf[3] = '-';
 663                 if (iflags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG)
 664                         buf[4] = 'S';
 665                 else
 666                         buf[4] = '-';
 667                 if (iflags & ACE_FAILED_ACCESS_ACE_FLAG)
 668                         buf[5] = 'F';
 669                 else
 670                         buf[5] = '-';
 671                 if (iflags & ACE_INHERITED_ACE)
 672                         buf[6] = 'I';
 673                 else
 674                         buf[6] = '-';
 675                 buf[7] = ':';
 676                 buf[8] = '\0';
 677                 error = str_append(dstr, buf);
 678         } else {
 679                 if (iflags & ACE_FILE_INHERIT_ACE) {
 680                         error = str_append(dstr, FILE_INHERIT_TXT);
 681                 }
 682                 if (error == 0 && (iflags & ACE_DIRECTORY_INHERIT_ACE)) {
 683                         error = str_append(dstr, DIR_INHERIT_TXT);
 684                 }
 685                 if (error == 0 && (iflags & ACE_NO_PROPAGATE_INHERIT_ACE)) {
 686                         error = str_append(dstr, NO_PROPAGATE_TXT);
 687                 }
 688                 if (error == 0 && (iflags & ACE_INHERIT_ONLY_ACE)) {
 689                         error = str_append(dstr, INHERIT_ONLY_TXT);
 690                 }
 691                 if (error == 0 && (iflags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG)) {
 692                         error = str_append(dstr, SUCCESSFUL_ACCESS_TXT);
 693                 }
 694                 if (error == 0 && (iflags & ACE_FAILED_ACCESS_ACE_FLAG)) {
 695                         error = str_append(dstr, FAILED_ACCESS_TXT);
 696                 }
 697                 if (error == 0 && (iflags & ACE_INHERITED_ACE)) {
 698                         error = str_append(dstr, INHERITED_ACE_TXT);
 699                 }
 700                 if (error == 0 && dstr->d_aclexport[dstr->d_pos-1] == '/') {
 701                         dstr->d_aclexport[--dstr->d_pos] = '\0';
 702                         error = str_append(dstr, ":");
 703                 }
 704         }
 705 
 706         return (error);
 707 }
 708 
 709 /*
 710  * Convert internal acl representation to external representation.
 711  *
 712  * The length of a non-owning user name or non-owning group name ie entries
 713  * of type DEF_USER, USER, DEF_GROUP or GROUP, can exceed LOGNAME_MAX.  We
 714  * thus check the length of these entries, and if greater than LOGNAME_MAX,
 715  * we realloc() via increase_length().
 716  *
 717  * The LOGNAME_MAX, ENTRYTYPELEN and PERMS limits are otherwise always
 718  * adhered to.
 719  */
 720 
 721 /*
 722  * acltotext() converts each ACL entry to look like this:
 723  *
 724  *    entry_type:uid^gid^name:perms[:id]
 725  *
 726  * The maximum length of entry_type is 14 ("defaultgroup::" and
 727  * "defaultother::") hence ENTRYTYPELEN is set to 14.
 728  *
 729  * The max length of a uid^gid^name entry (in theory) is 8, hence we use,
 730  * however the ID could be a number so we therefore use ID_STR_MAX
 731  *
 732  * The length of a perms entry is 4 to allow for the comma appended to each
 733  * to each acl entry.  Hence PERMS is set to 4.
 734  */
 735 
 736 #define ENTRYTYPELEN    14
 737 #define PERMS           4
 738 #define ACL_ENTRY_SIZE  (ENTRYTYPELEN + ID_STR_MAX + PERMS + APPENDED_ID_MAX)
 739 
 740 char *
 741 aclent_acltotext(aclent_t  *aclp, int aclcnt, int flags)
 742 {
 743         dynaclstr_t     *dstr;
 744         char            *aclexport = NULL;
 745         int             i;
 746         int             error = 0;
 747 
 748         if (aclp == NULL)
 749                 return (NULL);
 750         if ((dstr = malloc(sizeof (dynaclstr_t))) == NULL)
 751                 return (NULL);
 752         dstr->d_bufsize = aclcnt * ACL_ENTRY_SIZE;
 753         if ((dstr->d_aclexport = malloc(dstr->d_bufsize)) == NULL) {
 754                 free(dstr);
 755                 return (NULL);
 756         }
 757         *dstr->d_aclexport = '\0';
 758         dstr->d_pos = 0;
 759 
 760         for (i = 0; i < aclcnt; i++, aclp++) {
 761                 if (error = aclent_type_txt(dstr, aclp, flags))
 762                         break;
 763                 if (error = aclent_perm_txt(dstr, aclp->a_perm))
 764                         break;
 765 
 766                 if ((flags & ACL_APPEND_ID) && ((aclp->a_type == USER) ||
 767                     (aclp->a_type == DEF_USER) || (aclp->a_type == GROUP) ||
 768                     (aclp->a_type == DEF_GROUP))) {
 769                         char id[ID_STR_MAX], *idstr;
 770 
 771                         if (error = str_append(dstr, ":"))
 772                                 break;
 773                         id[ID_STR_MAX - 1] = '\0'; /* null terminate buffer */
 774                         idstr = lltostr(aclp->a_id, &id[ID_STR_MAX - 1]);
 775                         if (error = str_append(dstr, idstr))
 776                                 break;
 777                 }
 778                 if (i < aclcnt - 1)
 779                         if (error = str_append(dstr, ","))
 780                                 break;
 781         }
 782         if (error) {
 783                 if (dstr->d_aclexport)
 784                         free(dstr->d_aclexport);
 785         } else {
 786                 aclexport = dstr->d_aclexport;
 787         }
 788         free(dstr);
 789         return (aclexport);
 790 }
 791 
 792 char *
 793 acltotext(aclent_t *aclp, int aclcnt)
 794 {
 795         return (aclent_acltotext(aclp, aclcnt, 0));
 796 }
 797 
 798 
 799 aclent_t *
 800 aclfromtext(char *aclstr, int *aclcnt)
 801 {
 802         acl_t *aclp;
 803         aclent_t *aclentp;
 804         int error;
 805 
 806         error = acl_fromtext(aclstr, &aclp);
 807         if (error)
 808                 return (NULL);
 809 
 810         aclentp = aclp->acl_aclp;
 811         aclp->acl_aclp = NULL;
 812         *aclcnt = aclp->acl_cnt;
 813 
 814         acl_free(aclp);
 815         return (aclentp);
 816 }
 817 
 818 
 819 /*
 820  * Append string onto dynaclstr_t.
 821  *
 822  * Return 0 on success, 1 for failure.
 823  */
 824 static int
 825 str_append(dynaclstr_t *dstr, char *newstr)
 826 {
 827         size_t len = strlen(newstr);
 828 
 829         if ((len + dstr->d_pos) >= dstr->d_bufsize) {
 830                 dstr->d_aclexport = realloc(dstr->d_aclexport,
 831                     dstr->d_bufsize + len + 1);
 832                 if (dstr->d_aclexport == NULL)
 833                         return (1);
 834                 dstr->d_bufsize += len;
 835         }
 836         (void) strcat(&dstr->d_aclexport[dstr->d_pos], newstr);
 837         dstr->d_pos += len;
 838         return (0);
 839 }
 840 
 841 static int
 842 aclent_perm_txt(dynaclstr_t *dstr, o_mode_t perm)
 843 {
 844         char buf[4];
 845 
 846         if (perm & S_IROTH)
 847                 buf[0] = 'r';
 848         else
 849                 buf[0] = '-';
 850         if (perm & S_IWOTH)
 851                 buf[1] = 'w';
 852         else
 853                 buf[1] = '-';
 854         if (perm & S_IXOTH)
 855                 buf[2] = 'x';
 856         else
 857                 buf[2] = '-';
 858         buf[3] = '\0';
 859         return (str_append(dstr, buf));
 860 }
 861 
 862 /*
 863  * ace_acltotext() convert each ace formatted acl to look like this:
 864  *
 865  * entry_type:uid^gid^name:perms[:flags]:<allow|deny>[:id][,]
 866  *
 867  * The maximum length of entry_type is 5 ("group")
 868  *
 869  * The max length of a uid^gid^name entry (in theory) is 8,
 870  * however id could be a number so we therefore use ID_STR_MAX
 871  *
 872  * The length of a perms entry is 144 i.e read_data/write_data...
 873  * to each acl entry.
 874  *
 875  * iflags: file_inherit/dir_inherit/inherit_only/no_propagate/successful_access
 876  *         /failed_access
 877  *
 878  */
 879 
 880 #define ACE_ENTRYTYPLEN         6
 881 #define IFLAGS_STR "file_inherit/dir_inherit/inherit_only/no_propagate/" \
 882         "successful_access/failed_access/inherited"
 883 #define IFLAGS_SIZE             (sizeof (IFLAGS_STR) - 1)
 884 #define ACCESS_TYPE_SIZE        7       /* if unknown */
 885 #define COLON_CNT               3
 886 #define PERMS_LEN               216
 887 #define ACE_ENTRY_SIZE  (ACE_ENTRYTYPLEN + ID_STR_MAX + PERMS_LEN + \
 888     ACCESS_TYPE_SIZE + IFLAGS_SIZE + COLON_CNT + APPENDED_ID_MAX)
 889 
 890 static char *
 891 ace_acltotext(acl_t *aceaclp, int flags)
 892 {
 893         ace_t           *aclp = aceaclp->acl_aclp;
 894         int             aclcnt = aceaclp->acl_cnt;
 895         int             i;
 896         int             error = 0;
 897         int             isdir = (aceaclp->acl_flags & ACL_IS_DIR);
 898         dynaclstr_t     *dstr;
 899         char            *aclexport = NULL;
 900         char            *rawsidp = NULL;
 901 
 902         if (aclp == NULL)
 903                 return (NULL);
 904 
 905         if ((dstr = malloc(sizeof (dynaclstr_t))) == NULL)
 906                 return (NULL);
 907         dstr->d_bufsize = aclcnt * ACL_ENTRY_SIZE;
 908         if ((dstr->d_aclexport = malloc(dstr->d_bufsize)) == NULL) {
 909                 free(dstr);
 910                 return (NULL);
 911         }
 912         *dstr->d_aclexport = '\0';
 913         dstr->d_pos = 0;
 914 
 915         for (i = 0; i < aclcnt; i++, aclp++) {
 916 
 917                 if (error = ace_type_txt(dstr, aclp, flags))
 918                         break;
 919                 if (error = ace_perm_txt(dstr, aclp->a_access_mask,
 920                     aclp->a_flags, isdir, flags))
 921                         break;
 922                 if (error = ace_inherit_txt(dstr, aclp->a_flags, flags))
 923                         break;
 924                 if (error = ace_access_txt(dstr, aclp->a_type))
 925                         break;
 926 
 927                 if ((flags & ACL_APPEND_ID) &&
 928                     (((aclp->a_flags & ACE_TYPE_FLAGS) == 0) ||
 929                     ((aclp->a_flags & ACE_TYPE_FLAGS) ==
 930                     ACE_IDENTIFIER_GROUP))) {
 931                         char id[ID_STR_MAX], *idstr;
 932 
 933                         if (error = str_append(dstr, ":"))
 934                                 break;
 935 
 936                         rawsidp = NULL;
 937                         id[ID_STR_MAX -1] = '\0'; /* null terminate */
 938                         if (aclp->a_who > MAXUID && (flags & ACL_SID_FMT)) {
 939 
 940                                 error = getsidname(aclp->a_who,
 941                                     ((aclp->a_flags & ACE_TYPE_FLAGS) == 0) ?
 942                                     B_TRUE : B_FALSE, &idstr, 1);
 943                                 rawsidp = idstr;
 944                                 if (error)
 945                                         break;
 946                         } else if (aclp->a_who > MAXUID &&
 947                             !(flags & ACL_NORESOLVE)) {
 948                                 idstr = lltostr(UID_NOBODY,
 949                                     &id[ID_STR_MAX - 1]);
 950                         } else {
 951                                 idstr = lltostr(aclp->a_who,
 952                                     &id[ID_STR_MAX - 1]);
 953                         }
 954                         if (error = str_append(dstr, idstr))
 955                                 break;
 956                         if (rawsidp) {
 957                                 free(rawsidp);
 958                                 rawsidp = NULL;
 959                         }
 960                 }
 961                 if (i < aclcnt - 1) {
 962                         if (error = str_append(dstr, ","))
 963                                 break;
 964                 }
 965         }
 966 
 967         if (rawsidp)
 968                 free(rawsidp);
 969         if (error) {
 970                 if (dstr->d_aclexport)
 971                         free(dstr->d_aclexport);
 972         } else {
 973                 aclexport = dstr->d_aclexport;
 974         }
 975         free(dstr);
 976         return (aclexport);
 977 }
 978 
 979 char *
 980 acl_totext(acl_t *aclp, int flags)
 981 {
 982         char *txtp;
 983 
 984         if (aclp == NULL)
 985                 return (NULL);
 986 
 987         switch (aclp->acl_type) {
 988         case ACE_T:
 989                 txtp = ace_acltotext(aclp, flags);
 990                 break;
 991         case ACLENT_T:
 992                 txtp = aclent_acltotext(aclp->acl_aclp, aclp->acl_cnt, flags);
 993                 break;
 994         }
 995 
 996         return (txtp);
 997 }
 998 
 999 int
1000 acl_fromtext(const char *acltextp, acl_t **ret_aclp)
1001 {
1002         int error;
1003         char *buf;
1004 
1005         buf = malloc(strlen(acltextp) + 2);
1006         if (buf == NULL)
1007                 return (EACL_MEM_ERROR);
1008         strcpy(buf, acltextp);
1009         strcat(buf, "\n");
1010 
1011         (void) mutex_lock(&yymutex);
1012         yybuf = buf;
1013         yyreset();
1014         error = yyparse();
1015         free(buf);
1016 
1017         if (yyacl) {
1018                 if (error == 0)
1019                         *ret_aclp = yyacl;
1020                 else {
1021                         acl_free(yyacl);
1022                 }
1023                 yyacl = NULL;
1024         }
1025         (void) mutex_unlock(&yymutex);
1026 
1027         return (error);
1028 }
1029 
1030 int
1031 acl_parse(const char *acltextp, acl_t **aclp)
1032 {
1033         int error;
1034 
1035         yyinteractive = 1;
1036         error = acl_fromtext(acltextp, aclp);
1037         yyinteractive = 0;
1038         return (error);
1039 }
1040 
1041 static void
1042 ace_compact_printacl(acl_t *aclp, int flgs)
1043 {
1044         int cnt;
1045         ace_t *acep;
1046         dynaclstr_t *dstr;
1047         int len;
1048 
1049         if ((dstr = malloc(sizeof (dynaclstr_t))) == NULL)
1050                 return;
1051         dstr->d_bufsize = ACE_ENTRY_SIZE;
1052         if ((dstr->d_aclexport = malloc(dstr->d_bufsize)) == NULL) {
1053                 free(dstr);
1054                 return;
1055         }
1056         *dstr->d_aclexport = '\0';
1057 
1058         dstr->d_pos = 0;
1059         for (cnt = 0, acep = aclp->acl_aclp;
1060             cnt != aclp->acl_cnt; cnt++, acep++) {
1061                 dstr->d_aclexport[0] = '\0';
1062                 dstr->d_pos = 0;
1063 
1064                 if (ace_type_txt(dstr, acep, flgs))
1065                         break;
1066                 len = strlen(&dstr->d_aclexport[0]);
1067                 if (ace_perm_txt(dstr, acep->a_access_mask, acep->a_flags,
1068                     aclp->acl_flags & ACL_IS_DIR, ACL_COMPACT_FMT))
1069                         break;
1070                 if (ace_inherit_txt(dstr, acep->a_flags, ACL_COMPACT_FMT))
1071                         break;
1072                 if (ace_access_txt(dstr, acep->a_type) == -1)
1073                         break;
1074                 (void) printf("    %20.*s%s\n", len, dstr->d_aclexport,
1075                     &dstr->d_aclexport[len]);
1076         }
1077 
1078         if (dstr->d_aclexport)
1079                 free(dstr->d_aclexport);
1080         free(dstr);
1081 }
1082 
1083 static void
1084 ace_printacl(acl_t *aclp, int cols, int flgs)
1085 {
1086         int  slot = 0;
1087         char *token;
1088         char *acltext;
1089 
1090         if (flgs & ACL_COMPACT_FMT) {
1091                 ace_compact_printacl(aclp, flgs);
1092                 return;
1093         }
1094 
1095         acltext = acl_totext(aclp, flgs);
1096 
1097         if (acltext == NULL)
1098                 return;
1099 
1100         token = strtok(acltext, ",");
1101         if (token == NULL) {
1102                 free(acltext);
1103                 return;
1104         }
1105 
1106         do {
1107                 (void) printf("     %d:", slot++);
1108                 split_line(token, cols - 5);
1109         } while (token = strtok(NULL, ","));
1110         free(acltext);
1111 }
1112 
1113 /*
1114  * pretty print an ACL.
1115  * For aclent_t ACL's the format is
1116  * similar to the old format used by getfacl,
1117  * with the addition of adding a "slot" number
1118  * before each entry.
1119  *
1120  * for ace_t ACL's the cols variable will break up
1121  * the long lines into multiple lines and will also
1122  * print a "slot" number.
1123  */
1124 void
1125 acl_printacl(acl_t *aclp, int cols, int flgs)
1126 {
1127 
1128         switch (aclp->acl_type) {
1129         case ACLENT_T:
1130                 aclent_printacl(aclp);
1131                 break;
1132         case ACE_T:
1133                 ace_printacl(aclp, cols, flgs);
1134                 break;
1135         }
1136 }
1137 
1138 typedef struct value_table {
1139         char            p_letter; /* perm letter such as 'r' */
1140         uint32_t        p_value; /* value for perm when pletter found */
1141 } value_table_t;
1142 
1143 /*
1144  * The permission tables are laid out in positional order
1145  * a '-' character will indicate a permission at a given
1146  * position is not specified.  The '-' is not part of the
1147  * table, but will be checked for in the permission computation
1148  * routine.
1149  */
1150 value_table_t ace_perm_table[] = {
1151         { 'r', ACE_READ_DATA},
1152         { 'w', ACE_WRITE_DATA},
1153         { 'x', ACE_EXECUTE},
1154         { 'p', ACE_APPEND_DATA},
1155         { 'd', ACE_DELETE},
1156         { 'D', ACE_DELETE_CHILD},
1157         { 'a', ACE_READ_ATTRIBUTES},
1158         { 'A', ACE_WRITE_ATTRIBUTES},
1159         { 'R', ACE_READ_NAMED_ATTRS},
1160         { 'W', ACE_WRITE_NAMED_ATTRS},
1161         { 'c', ACE_READ_ACL},
1162         { 'C', ACE_WRITE_ACL},
1163         { 'o', ACE_WRITE_OWNER},
1164         { 's', ACE_SYNCHRONIZE}
1165 };
1166 
1167 #define ACE_PERM_COUNT (sizeof (ace_perm_table) / sizeof (value_table_t))
1168 
1169 value_table_t aclent_perm_table[] = {
1170         { 'r', S_IROTH},
1171         { 'w', S_IWOTH},
1172         { 'x', S_IXOTH}
1173 };
1174 
1175 #define ACLENT_PERM_COUNT (sizeof (aclent_perm_table) / sizeof (value_table_t))
1176 
1177 value_table_t inherit_table[] = {
1178         {'f', ACE_FILE_INHERIT_ACE},
1179         {'d', ACE_DIRECTORY_INHERIT_ACE},
1180         {'i', ACE_INHERIT_ONLY_ACE},
1181         {'n', ACE_NO_PROPAGATE_INHERIT_ACE},
1182         {'S', ACE_SUCCESSFUL_ACCESS_ACE_FLAG},
1183         {'F', ACE_FAILED_ACCESS_ACE_FLAG},
1184         {'I', ACE_INHERITED_ACE}
1185 };
1186 
1187 #define IFLAG_COUNT (sizeof (inherit_table) / sizeof (value_table_t))
1188 #define IFLAG_COUNT_V1 6 /* Older version compatibility */
1189 
1190 /*
1191  * compute value from a permission table or inheritance table
1192  * based on string passed in.  If positional is set then
1193  * string must match order in permtab, otherwise any order
1194  * is allowed.
1195  */
1196 int
1197 compute_values(value_table_t *permtab, int count,
1198     char *permstr, int positional, uint32_t *mask)
1199 {
1200         uint32_t perm_val = 0;
1201         char *pstr;
1202         int i, found;
1203 
1204         if (count < 0)
1205                 return (1);
1206 
1207         if (positional) {
1208                 for (i = 0, pstr = permstr; i != count && pstr &&
1209                     *pstr; i++, pstr++) {
1210                         if (*pstr == permtab[i].p_letter) {
1211                                 perm_val |= permtab[i].p_value;
1212                         } else if (*pstr != '-') {
1213                                 return (1);
1214                         }
1215                 }
1216         } else {  /* random order single letters with no '-' */
1217                 for (pstr = permstr; pstr && *pstr; pstr++) {
1218                         for (found = 0, i = 0; i != count; i++) {
1219                                 if (*pstr == permtab[i].p_letter) {
1220                                         perm_val |= permtab[i].p_value;
1221                                         found = 1;
1222                                         break;
1223                                 }
1224                         }
1225                         if (found == 0)
1226                                 return (1);
1227                 }
1228         }
1229 
1230         *mask = perm_val;
1231         return (0);
1232 }
1233 
1234 
1235 int
1236 ace_inherit_helper(char *str, uint32_t *imask, int table_length)
1237 {
1238         int rc = 0;
1239 
1240         if (strlen(str) == table_length) {
1241                 /*
1242                  * If the string == table_length then first check to see it's
1243                  * in positional format.  If that fails then see if it's in
1244                  * non-positional format.
1245                  */
1246                 if (compute_values(inherit_table, table_length, str,
1247                     1, imask) && compute_values(inherit_table,
1248                     table_length, str, 0, imask)) {
1249                         rc = 1;
1250                 }
1251         } else {
1252                 rc = compute_values(inherit_table, table_length, str, 0, imask);
1253         }
1254 
1255         return (rc ? EACL_INHERIT_ERROR : 0);
1256 }
1257 
1258 /*
1259  * compute value for inheritance flags.
1260  */
1261 int
1262 compute_ace_inherit(char *str, uint32_t *imask)
1263 {
1264         int rc = 0;
1265 
1266         rc = ace_inherit_helper(str, imask, IFLAG_COUNT);
1267 
1268         if (rc && strlen(str) != IFLAG_COUNT) {
1269 
1270                 /* is it an old formatted inherit string? */
1271                 rc = ace_inherit_helper(str, imask, IFLAG_COUNT_V1);
1272         }
1273 
1274         return (rc);
1275 }
1276 
1277 
1278 /*
1279  * compute value for ACE permissions.
1280  */
1281 int
1282 compute_ace_perms(char *str, uint32_t *mask)
1283 {
1284         int positional = 0;
1285         int error;
1286 
1287         if (strlen(str) == ACE_PERM_COUNT)
1288                 positional = 1;
1289 
1290         error = compute_values(ace_perm_table, ACE_PERM_COUNT,
1291             str, positional, mask);
1292 
1293         if (error && positional) {
1294                 /*
1295                  * If positional was set, then make sure permissions
1296                  * aren't actually valid in non positional case where
1297                  * all permissions are specified, just in random order.
1298                  */
1299                 error = compute_values(ace_perm_table,
1300                     ACE_PERM_COUNT, str, 0, mask);
1301         }
1302         if (error)
1303                 error = EACL_PERM_MASK_ERROR;
1304 
1305         return (error);
1306 }
1307 
1308 
1309 
1310 /*
1311  * compute values for aclent permissions.
1312  */
1313 int
1314 compute_aclent_perms(char *str, o_mode_t *mask)
1315 {
1316         int error;
1317         uint32_t pmask;
1318 
1319         if (strlen(str) != ACLENT_PERM_COUNT)
1320                 return (EACL_PERM_MASK_ERROR);
1321 
1322         *mask = 0;
1323         error = compute_values(aclent_perm_table, ACLENT_PERM_COUNT,
1324             str, 1, &pmask);
1325         if (error == 0) {
1326                 *mask = (o_mode_t)pmask;
1327         } else
1328                 error = EACL_PERM_MASK_ERROR;
1329         return (error);
1330 }
1331 
1332 /*
1333  * determine ACE permissions.
1334  */
1335 int
1336 ace_perm_mask(struct acl_perm_type *aclperm, uint32_t *mask)
1337 {
1338         int error;
1339 
1340         if (aclperm->perm_style == PERM_TYPE_EMPTY) {
1341                 *mask = 0;
1342                 return (0);
1343         }
1344 
1345         if (aclperm->perm_style == PERM_TYPE_ACE) {
1346                 *mask = aclperm->perm_val;
1347                 return (0);
1348         }
1349 
1350         error = compute_ace_perms(aclperm->perm_str, mask);
1351         if (error) {
1352                 acl_error(dgettext(TEXT_DOMAIN,
1353                     "Invalid permission(s) '%s' specified\n"),
1354                     aclperm->perm_str);
1355                 return (EACL_PERM_MASK_ERROR);
1356         }
1357 
1358         return (0);
1359 }