17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*ee519a1fSgjelinek * Common Development and Distribution License (the "License"). 6*ee519a1fSgjelinek * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 225a5eeccaSmarks * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate /*LINTLIBRARY*/ 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #include <grp.h> 307c478bd9Sstevel@tonic-gate #include <pwd.h> 317c478bd9Sstevel@tonic-gate #include <string.h> 327c478bd9Sstevel@tonic-gate #include <limits.h> 337c478bd9Sstevel@tonic-gate #include <stdlib.h> 34fa9e4066Sahrens #include <errno.h> 357c478bd9Sstevel@tonic-gate #include <sys/param.h> 367c478bd9Sstevel@tonic-gate #include <sys/types.h> 375a5eeccaSmarks #include <sys/stat.h> 387c478bd9Sstevel@tonic-gate #include <sys/acl.h> 39fa9e4066Sahrens #include <aclutils.h> 40fa9e4066Sahrens 415a5eeccaSmarks #define ID_STR_MAX 20 /* digits in LONG_MAX */ 425a5eeccaSmarks 435a5eeccaSmarks #define APPENDED_ID_MAX ID_STR_MAX + 1 /* id + colon */ 445a5eeccaSmarks /* 455a5eeccaSmarks * yyinteractive controls whether yyparse should print out 465a5eeccaSmarks * error messages to stderr, and whether or not id's should be 475a5eeccaSmarks * allowed from acl_fromtext(). 485a5eeccaSmarks */ 495a5eeccaSmarks int yyinteractive; 505a5eeccaSmarks acl_t *yyacl; 515a5eeccaSmarks char *yybuf; 52fa9e4066Sahrens 53fa9e4066Sahrens extern acl_t *acl_alloc(enum acl_type); 547c478bd9Sstevel@tonic-gate 5511e32170Shm123892 567c478bd9Sstevel@tonic-gate struct dynaclstr { 577c478bd9Sstevel@tonic-gate size_t bufsize; /* current size of aclexport */ 587c478bd9Sstevel@tonic-gate char *aclexport; 597c478bd9Sstevel@tonic-gate }; 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate static char *strappend(char *, char *); 627c478bd9Sstevel@tonic-gate static char *convert_perm(char *, o_mode_t); 637c478bd9Sstevel@tonic-gate static int increase_length(struct dynaclstr *, size_t); 647c478bd9Sstevel@tonic-gate 655a5eeccaSmarks static void 665a5eeccaSmarks aclent_perms(int perm, char *txt_perms) 67fa9e4066Sahrens { 685a5eeccaSmarks if (perm & S_IROTH) 695a5eeccaSmarks txt_perms[0] = 'r'; 705a5eeccaSmarks else 715a5eeccaSmarks txt_perms[0] = '-'; 725a5eeccaSmarks if (perm & S_IWOTH) 735a5eeccaSmarks txt_perms[1] = 'w'; 745a5eeccaSmarks else 755a5eeccaSmarks txt_perms[1] = '-'; 765a5eeccaSmarks if (perm & S_IXOTH) 775a5eeccaSmarks txt_perms[2] = 'x'; 785a5eeccaSmarks else 795a5eeccaSmarks txt_perms[2] = '-'; 805a5eeccaSmarks txt_perms[3] = '\0'; 815a5eeccaSmarks } 82fa9e4066Sahrens 835a5eeccaSmarks static char * 845a5eeccaSmarks pruname(uid_t uid, char *uidp) 855a5eeccaSmarks { 865a5eeccaSmarks struct passwd *passwdp; 87fa9e4066Sahrens 885a5eeccaSmarks passwdp = getpwuid(uid); 895a5eeccaSmarks if (passwdp == (struct passwd *)NULL) { 905a5eeccaSmarks /* could not get passwd information: display uid instead */ 915a5eeccaSmarks (void) sprintf(uidp, "%ld", (long)uid); 925a5eeccaSmarks return (uidp); 935a5eeccaSmarks } else 945a5eeccaSmarks return (passwdp->pw_name); 955a5eeccaSmarks } 96fa9e4066Sahrens 975a5eeccaSmarks static char * 985a5eeccaSmarks prgname(gid_t gid, char *gidp) 995a5eeccaSmarks { 1005a5eeccaSmarks struct group *groupp; 101fa9e4066Sahrens 1025a5eeccaSmarks groupp = getgrgid(gid); 1035a5eeccaSmarks if (groupp == (struct group *)NULL) { 1045a5eeccaSmarks /* could not get group information: display gid instead */ 1055a5eeccaSmarks (void) sprintf(gidp, "%ld", (long)gid); 1065a5eeccaSmarks return (gidp); 1075a5eeccaSmarks } else 1085a5eeccaSmarks return (groupp->gr_name); 1095a5eeccaSmarks } 1105a5eeccaSmarks static void 1115a5eeccaSmarks aclent_printacl(acl_t *aclp) 1125a5eeccaSmarks { 1135a5eeccaSmarks aclent_t *tp; 1145a5eeccaSmarks int aclcnt; 1155a5eeccaSmarks int mask; 1165a5eeccaSmarks int slot = 0; 1175a5eeccaSmarks char perm[4]; 1185a5eeccaSmarks char uidp[10]; 1195a5eeccaSmarks char gidp[10]; 1205a5eeccaSmarks 1215a5eeccaSmarks /* display ACL: assume it is sorted. */ 1225a5eeccaSmarks aclcnt = aclp->acl_cnt; 1235a5eeccaSmarks for (tp = aclp->acl_aclp; tp && aclcnt--; tp++) { 1245a5eeccaSmarks if (tp->a_type == CLASS_OBJ) 1255a5eeccaSmarks mask = tp->a_perm; 1265a5eeccaSmarks } 1275a5eeccaSmarks aclcnt = aclp->acl_cnt; 1285a5eeccaSmarks for (tp = aclp->acl_aclp; aclcnt--; tp++) { 1295a5eeccaSmarks (void) printf(" %d:", slot++); 1305a5eeccaSmarks switch (tp->a_type) { 1315a5eeccaSmarks case USER: 1325a5eeccaSmarks aclent_perms(tp->a_perm, perm); 1335a5eeccaSmarks (void) printf("user:%s:%s\t\t", 1345a5eeccaSmarks pruname(tp->a_id, uidp), perm); 1355a5eeccaSmarks aclent_perms((tp->a_perm & mask), perm); 1365a5eeccaSmarks (void) printf("#effective:%s\n", perm); 1375a5eeccaSmarks break; 1385a5eeccaSmarks case USER_OBJ: 1395a5eeccaSmarks /* no need to display uid */ 1405a5eeccaSmarks aclent_perms(tp->a_perm, perm); 1415a5eeccaSmarks (void) printf("user::%s\n", perm); 1425a5eeccaSmarks break; 1435a5eeccaSmarks case GROUP: 1445a5eeccaSmarks aclent_perms(tp->a_perm, perm); 1455a5eeccaSmarks (void) printf("group:%s:%s\t\t", 1465a5eeccaSmarks prgname(tp->a_id, gidp), perm); 1475a5eeccaSmarks aclent_perms(tp->a_perm & mask, perm); 1485a5eeccaSmarks (void) printf("#effective:%s\n", perm); 1495a5eeccaSmarks break; 1505a5eeccaSmarks case GROUP_OBJ: 1515a5eeccaSmarks aclent_perms(tp->a_perm, perm); 1525a5eeccaSmarks (void) printf("group::%s\t\t", perm); 1535a5eeccaSmarks aclent_perms(tp->a_perm & mask, perm); 1545a5eeccaSmarks (void) printf("#effective:%s\n", perm); 1555a5eeccaSmarks break; 1565a5eeccaSmarks case CLASS_OBJ: 1575a5eeccaSmarks aclent_perms(tp->a_perm, perm); 1585a5eeccaSmarks (void) printf("mask:%s\n", perm); 1595a5eeccaSmarks break; 1605a5eeccaSmarks case OTHER_OBJ: 1615a5eeccaSmarks aclent_perms(tp->a_perm, perm); 1625a5eeccaSmarks (void) printf("other:%s\n", perm); 1635a5eeccaSmarks break; 1645a5eeccaSmarks case DEF_USER: 1655a5eeccaSmarks aclent_perms(tp->a_perm, perm); 1665a5eeccaSmarks (void) printf("default:user:%s:%s\n", 1675a5eeccaSmarks pruname(tp->a_id, uidp), perm); 1685a5eeccaSmarks break; 1695a5eeccaSmarks case DEF_USER_OBJ: 1705a5eeccaSmarks aclent_perms(tp->a_perm, perm); 1715a5eeccaSmarks (void) printf("default:user::%s\n", perm); 1725a5eeccaSmarks break; 1735a5eeccaSmarks case DEF_GROUP: 1745a5eeccaSmarks aclent_perms(tp->a_perm, perm); 1755a5eeccaSmarks (void) printf("default:group:%s:%s\n", 1765a5eeccaSmarks prgname(tp->a_id, gidp), perm); 1775a5eeccaSmarks break; 1785a5eeccaSmarks case DEF_GROUP_OBJ: 1795a5eeccaSmarks aclent_perms(tp->a_perm, perm); 1805a5eeccaSmarks (void) printf("default:group::%s\n", perm); 1815a5eeccaSmarks break; 1825a5eeccaSmarks case DEF_CLASS_OBJ: 1835a5eeccaSmarks aclent_perms(tp->a_perm, perm); 1845a5eeccaSmarks (void) printf("default:mask:%s\n", perm); 1855a5eeccaSmarks break; 1865a5eeccaSmarks case DEF_OTHER_OBJ: 1875a5eeccaSmarks aclent_perms(tp->a_perm, perm); 1885a5eeccaSmarks (void) printf("default:other:%s\n", perm); 1895a5eeccaSmarks break; 1905a5eeccaSmarks default: 1915a5eeccaSmarks (void) fprintf(stderr, 1925a5eeccaSmarks gettext("unrecognized entry\n")); 1935a5eeccaSmarks break; 1945a5eeccaSmarks } 1955a5eeccaSmarks } 1965a5eeccaSmarks } 1975a5eeccaSmarks 1985a5eeccaSmarks static void 1995a5eeccaSmarks split_line(char *str, int cols) 2005a5eeccaSmarks { 2015a5eeccaSmarks char *ptr; 2025a5eeccaSmarks int len; 2035a5eeccaSmarks int i; 2045a5eeccaSmarks int last_split; 2055a5eeccaSmarks char *pad = ""; 2065a5eeccaSmarks int pad_len; 2075a5eeccaSmarks 2085a5eeccaSmarks len = strlen(str); 2095a5eeccaSmarks ptr = str; 2105a5eeccaSmarks pad_len = 0; 2115a5eeccaSmarks 2125a5eeccaSmarks ptr = str; 2135a5eeccaSmarks last_split = 0; 2145a5eeccaSmarks for (i = 0; i != len; i++) { 2155a5eeccaSmarks if ((i + pad_len + 4) >= cols) { 2165a5eeccaSmarks (void) printf("%s%.*s\n", pad, last_split, ptr); 2175a5eeccaSmarks ptr = &ptr[last_split]; 2185a5eeccaSmarks len = strlen(ptr); 2195a5eeccaSmarks i = 0; 2205a5eeccaSmarks pad_len = 4; 2215a5eeccaSmarks pad = " "; 2225a5eeccaSmarks } else { 2235a5eeccaSmarks if (ptr[i] == '/' || ptr[i] == ':') { 2245a5eeccaSmarks last_split = i; 2255a5eeccaSmarks } 2265a5eeccaSmarks } 2275a5eeccaSmarks } 2285a5eeccaSmarks if (i == len) { 2295a5eeccaSmarks (void) printf("%s%s\n", pad, ptr); 2305a5eeccaSmarks } 2315a5eeccaSmarks } 2325a5eeccaSmarks 2335a5eeccaSmarks #define OWNERAT_TXT "owner@" 2345a5eeccaSmarks #define GROUPAT_TXT "group@" 2355a5eeccaSmarks #define EVERYONEAT_TXT "everyone@" 2365a5eeccaSmarks #define GROUP_TXT "group:" 2375a5eeccaSmarks #define USER_TXT "user:" 2385a5eeccaSmarks 2395a5eeccaSmarks char * 2405a5eeccaSmarks ace_type_txt(char *buf, char **endp, ace_t *acep) 2415a5eeccaSmarks { 2425a5eeccaSmarks 2435a5eeccaSmarks char idp[10]; 2445a5eeccaSmarks 2455a5eeccaSmarks if (buf == NULL) 2465a5eeccaSmarks return (NULL); 2475a5eeccaSmarks 2485a5eeccaSmarks switch (acep->a_flags & ACE_TYPE_FLAGS) { 2495a5eeccaSmarks case ACE_OWNER: 2505a5eeccaSmarks strcpy(buf, OWNERAT_TXT); 2515a5eeccaSmarks *endp = buf + sizeof (OWNERAT_TXT) - 1; 2525a5eeccaSmarks break; 2535a5eeccaSmarks 2545a5eeccaSmarks case ACE_GROUP|ACE_IDENTIFIER_GROUP: 2555a5eeccaSmarks strcpy(buf, GROUPAT_TXT); 2565a5eeccaSmarks *endp = buf + sizeof (GROUPAT_TXT) - 1; 2575a5eeccaSmarks break; 2585a5eeccaSmarks 2595a5eeccaSmarks case ACE_IDENTIFIER_GROUP: 2605a5eeccaSmarks strcpy(buf, GROUP_TXT); 2615a5eeccaSmarks strcat(buf, prgname(acep->a_who, idp)); 2625a5eeccaSmarks *endp = buf + strlen(buf); 2635a5eeccaSmarks break; 2645a5eeccaSmarks 2655a5eeccaSmarks case ACE_EVERYONE: 2665a5eeccaSmarks strcpy(buf, EVERYONEAT_TXT); 2675a5eeccaSmarks *endp = buf + sizeof (EVERYONEAT_TXT) - 1; 2685a5eeccaSmarks break; 2695a5eeccaSmarks 2705a5eeccaSmarks case 0: 2715a5eeccaSmarks strcpy(buf, USER_TXT); 2725a5eeccaSmarks strcat(buf, pruname(acep->a_who, idp)); 2735a5eeccaSmarks *endp = buf + strlen(buf); 2745a5eeccaSmarks break; 2755a5eeccaSmarks } 2765a5eeccaSmarks 2775a5eeccaSmarks return (buf); 2785a5eeccaSmarks } 2795a5eeccaSmarks 2805a5eeccaSmarks #define READ_DATA_TXT "read_data/" 2815a5eeccaSmarks #define WRITE_DATA_TXT "write_data/" 2825a5eeccaSmarks #define EXECUTE_TXT "execute/" 2835a5eeccaSmarks #define READ_XATTR_TXT "read_xattr/" 2845a5eeccaSmarks #define WRITE_XATTR_TXT "write_xattr/" 2855a5eeccaSmarks #define READ_ATTRIBUTES_TXT "read_attributes/" 2865a5eeccaSmarks #define WRITE_ATTRIBUTES_TXT "write_attributes/" 2875a5eeccaSmarks #define DELETE_TXT "delete/" 2885a5eeccaSmarks #define DELETE_CHILD_TXT "delete_child/" 2895a5eeccaSmarks #define WRITE_OWNER_TXT "write_owner/" 2905a5eeccaSmarks #define READ_ACL_TXT "read_acl/" 2915a5eeccaSmarks #define WRITE_ACL_TXT "write_acl/" 2925a5eeccaSmarks #define APPEND_DATA_TXT "append_data/" 2935a5eeccaSmarks #define READ_DIR_TXT "list_directory/read_data/" 2945a5eeccaSmarks #define ADD_DIR_TXT "add_subdirectory/append_data/" 2955a5eeccaSmarks #define ADD_FILE_TXT "add_file/write_data/" 2965a5eeccaSmarks #define SYNCHRONIZE_TXT "synchronize" /* not slash on this one */ 2975a5eeccaSmarks 2985a5eeccaSmarks char * 2995a5eeccaSmarks ace_perm_txt(char *buf, char **endp, uint32_t mask, 3005a5eeccaSmarks uint32_t iflags, int isdir, int flags) 3015a5eeccaSmarks { 3025a5eeccaSmarks char *lend = buf; /* local end */ 3035a5eeccaSmarks 3045a5eeccaSmarks if (buf == NULL) 3055a5eeccaSmarks return (NULL); 3065a5eeccaSmarks 3075a5eeccaSmarks if (flags & ACL_COMPACT_FMT) { 3085a5eeccaSmarks 3095a5eeccaSmarks if (mask & ACE_READ_DATA) 3105a5eeccaSmarks buf[0] = 'r'; 3115a5eeccaSmarks else 3125a5eeccaSmarks buf[0] = '-'; 3135a5eeccaSmarks if (mask & ACE_WRITE_DATA) 3145a5eeccaSmarks buf[1] = 'w'; 3155a5eeccaSmarks else 3165a5eeccaSmarks buf[1] = '-'; 3175a5eeccaSmarks if (mask & ACE_EXECUTE) 3185a5eeccaSmarks buf[2] = 'x'; 3195a5eeccaSmarks else 3205a5eeccaSmarks buf[2] = '-'; 3215a5eeccaSmarks if (mask & ACE_APPEND_DATA) 3225a5eeccaSmarks buf[3] = 'p'; 3235a5eeccaSmarks else 3245a5eeccaSmarks buf[3] = '-'; 3255a5eeccaSmarks if (mask & ACE_DELETE) 3265a5eeccaSmarks buf[4] = 'd'; 3275a5eeccaSmarks else 3285a5eeccaSmarks buf[4] = '-'; 3295a5eeccaSmarks if (mask & ACE_DELETE_CHILD) 3305a5eeccaSmarks buf[5] = 'D'; 3315a5eeccaSmarks else 3325a5eeccaSmarks buf[5] = '-'; 3335a5eeccaSmarks if (mask & ACE_READ_ATTRIBUTES) 3345a5eeccaSmarks buf[6] = 'a'; 3355a5eeccaSmarks else 3365a5eeccaSmarks buf[6] = '-'; 3375a5eeccaSmarks if (mask & ACE_WRITE_ATTRIBUTES) 3385a5eeccaSmarks buf[7] = 'A'; 3395a5eeccaSmarks else 3405a5eeccaSmarks buf[7] = '-'; 3415a5eeccaSmarks if (mask & ACE_READ_NAMED_ATTRS) 3425a5eeccaSmarks buf[8] = 'R'; 3435a5eeccaSmarks else 3445a5eeccaSmarks buf[8] = '-'; 3455a5eeccaSmarks if (mask & ACE_WRITE_NAMED_ATTRS) 3465a5eeccaSmarks buf[9] = 'W'; 3475a5eeccaSmarks else 3485a5eeccaSmarks buf[9] = '-'; 3495a5eeccaSmarks if (mask & ACE_READ_ACL) 3505a5eeccaSmarks buf[10] = 'c'; 3515a5eeccaSmarks else 3525a5eeccaSmarks buf[10] = '-'; 3535a5eeccaSmarks if (mask & ACE_WRITE_ACL) 3545a5eeccaSmarks buf[11] = 'C'; 3555a5eeccaSmarks else 3565a5eeccaSmarks buf[11] = '-'; 3575a5eeccaSmarks if (mask & ACE_WRITE_OWNER) 3585a5eeccaSmarks buf[12] = 'o'; 3595a5eeccaSmarks else 3605a5eeccaSmarks buf[12] = '-'; 3615a5eeccaSmarks if (mask & ACE_SYNCHRONIZE) 3625a5eeccaSmarks buf[13] = 's'; 3635a5eeccaSmarks else 3645a5eeccaSmarks buf[13] = '-'; 3655a5eeccaSmarks buf[14] = '\0'; 3665a5eeccaSmarks *endp = buf + 14; 3675a5eeccaSmarks return (buf); 3685a5eeccaSmarks } else { 3695a5eeccaSmarks /* 3705a5eeccaSmarks * If ACE is a directory, but inheritance indicates its 3715a5eeccaSmarks * for a file then print permissions for file rather than 3725a5eeccaSmarks * dir. 3735a5eeccaSmarks */ 3745a5eeccaSmarks if (isdir) { 3755a5eeccaSmarks if (mask & ACE_LIST_DIRECTORY) { 3765a5eeccaSmarks if (iflags == ACE_FILE_INHERIT_ACE) { 3775a5eeccaSmarks strcpy(lend, READ_DATA_TXT); 3785a5eeccaSmarks lend += sizeof (READ_DATA_TXT) - 1; 3795a5eeccaSmarks } else { 3805a5eeccaSmarks strcpy(lend, READ_DIR_TXT); 3815a5eeccaSmarks lend += sizeof (READ_DIR_TXT) - 1; 3825a5eeccaSmarks } 3835a5eeccaSmarks } 3845a5eeccaSmarks if (mask & ACE_ADD_FILE) { 3855a5eeccaSmarks if (iflags == ACE_FILE_INHERIT_ACE) { 3865a5eeccaSmarks strcpy(lend, WRITE_DATA_TXT); 3875a5eeccaSmarks lend += sizeof (WRITE_DATA_TXT) - 1; 3885a5eeccaSmarks } else { 3895a5eeccaSmarks strcpy(lend, ADD_FILE_TXT); 3905a5eeccaSmarks lend += 3915a5eeccaSmarks sizeof (ADD_FILE_TXT) -1; 3925a5eeccaSmarks } 3935a5eeccaSmarks } 3945a5eeccaSmarks if (mask & ACE_ADD_SUBDIRECTORY) { 3955a5eeccaSmarks if (iflags == ACE_FILE_INHERIT_ACE) { 3965a5eeccaSmarks strcpy(lend, APPEND_DATA_TXT); 3975a5eeccaSmarks lend += sizeof (APPEND_DATA_TXT) - 1; 3985a5eeccaSmarks } else { 3995a5eeccaSmarks strcpy(lend, ADD_DIR_TXT); 4005a5eeccaSmarks lend += sizeof (ADD_DIR_TXT) - 1; 4015a5eeccaSmarks } 4025a5eeccaSmarks } 4035a5eeccaSmarks } else { 4045a5eeccaSmarks if (mask & ACE_READ_DATA) { 4055a5eeccaSmarks strcpy(lend, READ_DATA_TXT); 4065a5eeccaSmarks lend += sizeof (READ_DATA_TXT) - 1; 4075a5eeccaSmarks } 4085a5eeccaSmarks if (mask & ACE_WRITE_DATA) { 4095a5eeccaSmarks strcpy(lend, WRITE_DATA_TXT); 4105a5eeccaSmarks lend += sizeof (WRITE_DATA_TXT) - 1; 4115a5eeccaSmarks } 4125a5eeccaSmarks if (mask & ACE_APPEND_DATA) { 4135a5eeccaSmarks strcpy(lend, APPEND_DATA_TXT); 4145a5eeccaSmarks lend += sizeof (APPEND_DATA_TXT) - 1; 4155a5eeccaSmarks } 4165a5eeccaSmarks } 4175a5eeccaSmarks if (mask & ACE_READ_NAMED_ATTRS) { 4185a5eeccaSmarks strcpy(lend, READ_XATTR_TXT); 4195a5eeccaSmarks lend += sizeof (READ_XATTR_TXT) - 1; 4205a5eeccaSmarks } 4215a5eeccaSmarks if (mask & ACE_WRITE_NAMED_ATTRS) { 4225a5eeccaSmarks strcpy(lend, WRITE_XATTR_TXT); 4235a5eeccaSmarks lend += sizeof (WRITE_XATTR_TXT) - 1; 4245a5eeccaSmarks } 4255a5eeccaSmarks if (mask & ACE_EXECUTE) { 4265a5eeccaSmarks strcpy(lend, EXECUTE_TXT); 4275a5eeccaSmarks lend += sizeof (EXECUTE_TXT) - 1; 4285a5eeccaSmarks } 4295a5eeccaSmarks if (mask & ACE_DELETE_CHILD) { 4305a5eeccaSmarks strcpy(lend, DELETE_CHILD_TXT); 4315a5eeccaSmarks lend += sizeof (DELETE_CHILD_TXT) - 1; 4325a5eeccaSmarks } 4335a5eeccaSmarks if (mask & ACE_READ_ATTRIBUTES) { 4345a5eeccaSmarks strcpy(lend, READ_ATTRIBUTES_TXT); 4355a5eeccaSmarks lend += sizeof (READ_ATTRIBUTES_TXT) - 1; 4365a5eeccaSmarks } 4375a5eeccaSmarks if (mask & ACE_WRITE_ATTRIBUTES) { 4385a5eeccaSmarks strcpy(lend, WRITE_ATTRIBUTES_TXT); 4395a5eeccaSmarks lend += sizeof (WRITE_ATTRIBUTES_TXT) - 1; 4405a5eeccaSmarks } 4415a5eeccaSmarks if (mask & ACE_DELETE) { 4425a5eeccaSmarks strcpy(lend, DELETE_TXT); 4435a5eeccaSmarks lend += sizeof (DELETE_TXT) - 1; 4445a5eeccaSmarks } 4455a5eeccaSmarks if (mask & ACE_READ_ACL) { 4465a5eeccaSmarks strcpy(lend, READ_ACL_TXT); 4475a5eeccaSmarks lend += sizeof (READ_ACL_TXT) - 1; 4485a5eeccaSmarks } 4495a5eeccaSmarks if (mask & ACE_WRITE_ACL) { 4505a5eeccaSmarks strcpy(lend, WRITE_ACL_TXT); 4515a5eeccaSmarks lend += sizeof (WRITE_ACL_TXT) - 1; 4525a5eeccaSmarks } 4535a5eeccaSmarks if (mask & ACE_WRITE_OWNER) { 4545a5eeccaSmarks strcpy(lend, WRITE_OWNER_TXT); 4555a5eeccaSmarks lend += sizeof (WRITE_OWNER_TXT) - 1; 4565a5eeccaSmarks } 4575a5eeccaSmarks if (mask & ACE_SYNCHRONIZE) { 4585a5eeccaSmarks strcpy(lend, SYNCHRONIZE_TXT); 4595a5eeccaSmarks lend += sizeof (SYNCHRONIZE_TXT) - 1; 4605a5eeccaSmarks } 4615a5eeccaSmarks 4625a5eeccaSmarks if (*(lend - 1) == '/') 4635a5eeccaSmarks *--lend = '\0'; 4645a5eeccaSmarks } 4655a5eeccaSmarks 4665a5eeccaSmarks *endp = lend; 4675a5eeccaSmarks return (buf); 4685a5eeccaSmarks } 4695a5eeccaSmarks 4705a5eeccaSmarks #define ALLOW_TXT "allow" 4715a5eeccaSmarks #define DENY_TXT "deny" 4725a5eeccaSmarks #define ALARM_TXT "alarm" 4735a5eeccaSmarks #define AUDIT_TXT "audit" 4745a5eeccaSmarks #define UNKNOWN_TXT "unknown" 4755a5eeccaSmarks char * 4765a5eeccaSmarks ace_access_txt(char *buf, char **endp, int type) 4775a5eeccaSmarks { 4785a5eeccaSmarks 4795a5eeccaSmarks if (buf == NULL) 4805a5eeccaSmarks return (NULL); 4815a5eeccaSmarks 4825a5eeccaSmarks if (type == ACE_ACCESS_ALLOWED_ACE_TYPE) { 4835a5eeccaSmarks strcpy(buf, ALLOW_TXT); 4845a5eeccaSmarks *endp += sizeof (ALLOW_TXT) - 1; 4855a5eeccaSmarks } else if (type == ACE_ACCESS_DENIED_ACE_TYPE) { 4865a5eeccaSmarks strcpy(buf, DENY_TXT); 4875a5eeccaSmarks *endp += sizeof (DENY_TXT) - 1; 4885a5eeccaSmarks } else if (type == ACE_SYSTEM_AUDIT_ACE_TYPE) { 4895a5eeccaSmarks strcpy(buf, AUDIT_TXT); 4905a5eeccaSmarks *endp += sizeof (AUDIT_TXT) - 1; 4915a5eeccaSmarks } else if (type == ACE_SYSTEM_ALARM_ACE_TYPE) { 4925a5eeccaSmarks strcpy(buf, ALARM_TXT); 4935a5eeccaSmarks *endp += sizeof (ALARM_TXT) - 1; 4945a5eeccaSmarks } else { 4955a5eeccaSmarks strcpy(buf, UNKNOWN_TXT); 4965a5eeccaSmarks *endp += sizeof (UNKNOWN_TXT) - 1; 4975a5eeccaSmarks } 4985a5eeccaSmarks 4995a5eeccaSmarks return (buf); 5005a5eeccaSmarks } 5015a5eeccaSmarks 5025a5eeccaSmarks static char * 5035a5eeccaSmarks ace_inherit_txt(char *buf, char **endp, uint32_t iflags, int flags) 5045a5eeccaSmarks { 5055a5eeccaSmarks 5065a5eeccaSmarks char *lend = buf; 5075a5eeccaSmarks 5085a5eeccaSmarks if (buf == NULL) { 5095a5eeccaSmarks return (NULL); 5105a5eeccaSmarks } 5115a5eeccaSmarks 5125a5eeccaSmarks if (flags & ACL_COMPACT_FMT) { 5135a5eeccaSmarks if (iflags & ACE_FILE_INHERIT_ACE) 5145a5eeccaSmarks buf[0] = 'f'; 5155a5eeccaSmarks else 5165a5eeccaSmarks buf[0] = '-'; 5175a5eeccaSmarks if (iflags & ACE_DIRECTORY_INHERIT_ACE) 5185a5eeccaSmarks buf[1] = 'd'; 5195a5eeccaSmarks else 5205a5eeccaSmarks buf[1] = '-'; 5215a5eeccaSmarks if (iflags & ACE_INHERIT_ONLY_ACE) 5225a5eeccaSmarks buf[2] = 'i'; 5235a5eeccaSmarks else 5245a5eeccaSmarks buf[2] = '-'; 5255a5eeccaSmarks if (iflags & ACE_NO_PROPAGATE_INHERIT_ACE) 5265a5eeccaSmarks buf[3] = 'n'; 5275a5eeccaSmarks else 5285a5eeccaSmarks buf[3] = '-'; 5295a5eeccaSmarks if (iflags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG) 5305a5eeccaSmarks buf[4] = 'S'; 5315a5eeccaSmarks else 5325a5eeccaSmarks buf[4] = '-'; 5335a5eeccaSmarks if (iflags & ACE_FAILED_ACCESS_ACE_FLAG) 5345a5eeccaSmarks buf[5] = 'F'; 5355a5eeccaSmarks else 5365a5eeccaSmarks buf[5] = '-'; 5375a5eeccaSmarks buf[6] = '\0'; 5385a5eeccaSmarks *endp = buf + 6; 5395a5eeccaSmarks } else { 5405a5eeccaSmarks if (iflags & ACE_FILE_INHERIT_ACE) { 5415a5eeccaSmarks strcpy(lend, "file_inherit/"); 5425a5eeccaSmarks lend += sizeof ("file_inherit/") - 1; 5435a5eeccaSmarks } 5445a5eeccaSmarks if (iflags & ACE_DIRECTORY_INHERIT_ACE) { 5455a5eeccaSmarks strcpy(lend, "dir_inherit/"); 5465a5eeccaSmarks lend += sizeof ("dir_inherit/") - 1; 5475a5eeccaSmarks } 5485a5eeccaSmarks if (iflags & ACE_NO_PROPAGATE_INHERIT_ACE) { 5495a5eeccaSmarks strcpy(lend, "no_propagate/"); 5505a5eeccaSmarks lend += sizeof ("no_propagate/") - 1; 5515a5eeccaSmarks } 5525a5eeccaSmarks if (iflags & ACE_INHERIT_ONLY_ACE) { 5535a5eeccaSmarks strcpy(lend, "inherit_only/"); 5545a5eeccaSmarks lend += sizeof ("inherit_only/") - 1; 5555a5eeccaSmarks } 5565a5eeccaSmarks 5575a5eeccaSmarks if (*(lend - 1) == '/') 5585a5eeccaSmarks *--lend = '\0'; 5595a5eeccaSmarks *endp = lend; 5605a5eeccaSmarks } 5615a5eeccaSmarks 5625a5eeccaSmarks return (buf); 563fa9e4066Sahrens } 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate /* 5667c478bd9Sstevel@tonic-gate * Convert internal acl representation to external representation. 5677c478bd9Sstevel@tonic-gate * 5687c478bd9Sstevel@tonic-gate * The length of a non-owning user name or non-owning group name ie entries 5697c478bd9Sstevel@tonic-gate * of type DEF_USER, USER, DEF_GROUP or GROUP, can exceed LOGNAME_MAX. We 5707c478bd9Sstevel@tonic-gate * thus check the length of these entries, and if greater than LOGNAME_MAX, 5717c478bd9Sstevel@tonic-gate * we realloc() via increase_length(). 5727c478bd9Sstevel@tonic-gate * 5737c478bd9Sstevel@tonic-gate * The LOGNAME_MAX, ENTRYTYPELEN and PERMS limits are otherwise always 5747c478bd9Sstevel@tonic-gate * adhered to. 5757c478bd9Sstevel@tonic-gate */ 5765a5eeccaSmarks 5775a5eeccaSmarks /* 5785a5eeccaSmarks * acltotext() converts each ACL entry to look like this: 5795a5eeccaSmarks * 5805a5eeccaSmarks * entry_type:uid^gid^name:perms[:id] 5815a5eeccaSmarks * 5825a5eeccaSmarks * The maximum length of entry_type is 14 ("defaultgroup::" and 5835a5eeccaSmarks * "defaultother::") hence ENTRYTYPELEN is set to 14. 5845a5eeccaSmarks * 5855a5eeccaSmarks * The max length of a uid^gid^name entry (in theory) is 8, hence we use, 5865a5eeccaSmarks * however the ID could be a number so we therefore use ID_STR_MAX 5875a5eeccaSmarks * 5885a5eeccaSmarks * The length of a perms entry is 4 to allow for the comma appended to each 5895a5eeccaSmarks * to each acl entry. Hence PERMS is set to 4. 5905a5eeccaSmarks */ 5915a5eeccaSmarks 5925a5eeccaSmarks #define ENTRYTYPELEN 14 5935a5eeccaSmarks #define PERMS 4 5945a5eeccaSmarks #define ACL_ENTRY_SIZE (ENTRYTYPELEN + ID_STR_MAX + PERMS + APPENDED_ID_MAX) 5955a5eeccaSmarks #define UPDATE_WHERE where = dstr->aclexport + strlen(dstr->aclexport) 5965a5eeccaSmarks 5977c478bd9Sstevel@tonic-gate char * 5985a5eeccaSmarks aclent_acltotext(aclent_t *aclp, int aclcnt, int flags) 5997c478bd9Sstevel@tonic-gate { 6007c478bd9Sstevel@tonic-gate char *aclexport; 6017c478bd9Sstevel@tonic-gate char *where; 602*ee519a1fSgjelinek struct group *groupp = NULL; 603*ee519a1fSgjelinek struct passwd *passwdp = NULL; 6047c478bd9Sstevel@tonic-gate struct dynaclstr *dstr; 6057c478bd9Sstevel@tonic-gate int i, rtn; 6067c478bd9Sstevel@tonic-gate size_t excess = 0; 6075a5eeccaSmarks char id[20], *idstr; 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate if (aclp == NULL) 6107c478bd9Sstevel@tonic-gate return (NULL); 6117c478bd9Sstevel@tonic-gate if ((dstr = malloc(sizeof (struct dynaclstr))) == NULL) 6127c478bd9Sstevel@tonic-gate return (NULL); 6137c478bd9Sstevel@tonic-gate dstr->bufsize = aclcnt * ACL_ENTRY_SIZE; 6147c478bd9Sstevel@tonic-gate if ((dstr->aclexport = malloc(dstr->bufsize)) == NULL) { 6157c478bd9Sstevel@tonic-gate free(dstr); 6167c478bd9Sstevel@tonic-gate return (NULL); 6177c478bd9Sstevel@tonic-gate } 6187c478bd9Sstevel@tonic-gate *dstr->aclexport = '\0'; 6197c478bd9Sstevel@tonic-gate where = dstr->aclexport; 6207c478bd9Sstevel@tonic-gate 6217c478bd9Sstevel@tonic-gate for (i = 0; i < aclcnt; i++, aclp++) { 6227c478bd9Sstevel@tonic-gate switch (aclp->a_type) { 6237c478bd9Sstevel@tonic-gate case DEF_USER_OBJ: 6247c478bd9Sstevel@tonic-gate case USER_OBJ: 6257c478bd9Sstevel@tonic-gate if (aclp->a_type == USER_OBJ) 6267c478bd9Sstevel@tonic-gate where = strappend(where, "user::"); 6277c478bd9Sstevel@tonic-gate else 6287c478bd9Sstevel@tonic-gate where = strappend(where, "defaultuser::"); 6297c478bd9Sstevel@tonic-gate where = convert_perm(where, aclp->a_perm); 6307c478bd9Sstevel@tonic-gate break; 6317c478bd9Sstevel@tonic-gate case DEF_USER: 6327c478bd9Sstevel@tonic-gate case USER: 6337c478bd9Sstevel@tonic-gate if (aclp->a_type == USER) 6347c478bd9Sstevel@tonic-gate where = strappend(where, "user:"); 6357c478bd9Sstevel@tonic-gate else 6367c478bd9Sstevel@tonic-gate where = strappend(where, "defaultuser:"); 637*ee519a1fSgjelinek if ((flags & ACL_NORESOLVE) == 0) 6387c478bd9Sstevel@tonic-gate passwdp = getpwuid(aclp->a_id); 6397c478bd9Sstevel@tonic-gate if (passwdp == (struct passwd *)NULL) { 6407c478bd9Sstevel@tonic-gate /* put in uid instead */ 6417c478bd9Sstevel@tonic-gate (void) sprintf(where, "%d", aclp->a_id); 64211e32170Shm123892 UPDATE_WHERE; 6437c478bd9Sstevel@tonic-gate } else { 6447c478bd9Sstevel@tonic-gate excess = strlen(passwdp->pw_name) - LOGNAME_MAX; 6457c478bd9Sstevel@tonic-gate if (excess > 0) { 6467c478bd9Sstevel@tonic-gate rtn = increase_length(dstr, excess); 6477c478bd9Sstevel@tonic-gate if (rtn == 1) { 64811e32170Shm123892 UPDATE_WHERE; 6497c478bd9Sstevel@tonic-gate } else { 6507c478bd9Sstevel@tonic-gate free(dstr->aclexport); 6517c478bd9Sstevel@tonic-gate free(dstr); 6527c478bd9Sstevel@tonic-gate return (NULL); 6537c478bd9Sstevel@tonic-gate } 6547c478bd9Sstevel@tonic-gate } 6557c478bd9Sstevel@tonic-gate where = strappend(where, passwdp->pw_name); 6567c478bd9Sstevel@tonic-gate } 6577c478bd9Sstevel@tonic-gate where = strappend(where, ":"); 6587c478bd9Sstevel@tonic-gate where = convert_perm(where, aclp->a_perm); 6597c478bd9Sstevel@tonic-gate break; 6607c478bd9Sstevel@tonic-gate case DEF_GROUP_OBJ: 6617c478bd9Sstevel@tonic-gate case GROUP_OBJ: 6627c478bd9Sstevel@tonic-gate if (aclp->a_type == GROUP_OBJ) 6637c478bd9Sstevel@tonic-gate where = strappend(where, "group::"); 6647c478bd9Sstevel@tonic-gate else 6657c478bd9Sstevel@tonic-gate where = strappend(where, "defaultgroup::"); 6667c478bd9Sstevel@tonic-gate where = convert_perm(where, aclp->a_perm); 6677c478bd9Sstevel@tonic-gate break; 6687c478bd9Sstevel@tonic-gate case DEF_GROUP: 6697c478bd9Sstevel@tonic-gate case GROUP: 6707c478bd9Sstevel@tonic-gate if (aclp->a_type == GROUP) 6717c478bd9Sstevel@tonic-gate where = strappend(where, "group:"); 6727c478bd9Sstevel@tonic-gate else 6737c478bd9Sstevel@tonic-gate where = strappend(where, "defaultgroup:"); 674*ee519a1fSgjelinek if ((flags & ACL_NORESOLVE) == 0) 6757c478bd9Sstevel@tonic-gate groupp = getgrgid(aclp->a_id); 6767c478bd9Sstevel@tonic-gate if (groupp == (struct group *)NULL) { 6777c478bd9Sstevel@tonic-gate /* put in gid instead */ 6787c478bd9Sstevel@tonic-gate (void) sprintf(where, "%d", aclp->a_id); 67911e32170Shm123892 UPDATE_WHERE; 6807c478bd9Sstevel@tonic-gate } else { 6817c478bd9Sstevel@tonic-gate excess = strlen(groupp->gr_name) - LOGNAME_MAX; 6827c478bd9Sstevel@tonic-gate if (excess > 0) { 6837c478bd9Sstevel@tonic-gate rtn = increase_length(dstr, excess); 6847c478bd9Sstevel@tonic-gate if (rtn == 1) { 68511e32170Shm123892 UPDATE_WHERE; 6867c478bd9Sstevel@tonic-gate } else { 6877c478bd9Sstevel@tonic-gate free(dstr->aclexport); 6887c478bd9Sstevel@tonic-gate free(dstr); 6897c478bd9Sstevel@tonic-gate return (NULL); 6907c478bd9Sstevel@tonic-gate } 6917c478bd9Sstevel@tonic-gate } 6927c478bd9Sstevel@tonic-gate where = strappend(where, groupp->gr_name); 6937c478bd9Sstevel@tonic-gate } 6947c478bd9Sstevel@tonic-gate where = strappend(where, ":"); 6957c478bd9Sstevel@tonic-gate where = convert_perm(where, aclp->a_perm); 6967c478bd9Sstevel@tonic-gate break; 6977c478bd9Sstevel@tonic-gate case DEF_CLASS_OBJ: 6987c478bd9Sstevel@tonic-gate case CLASS_OBJ: 6997c478bd9Sstevel@tonic-gate if (aclp->a_type == CLASS_OBJ) 7007c478bd9Sstevel@tonic-gate where = strappend(where, "mask:"); 7017c478bd9Sstevel@tonic-gate else 7027c478bd9Sstevel@tonic-gate where = strappend(where, "defaultmask:"); 7037c478bd9Sstevel@tonic-gate where = convert_perm(where, aclp->a_perm); 7047c478bd9Sstevel@tonic-gate break; 7057c478bd9Sstevel@tonic-gate case DEF_OTHER_OBJ: 7067c478bd9Sstevel@tonic-gate case OTHER_OBJ: 7077c478bd9Sstevel@tonic-gate if (aclp->a_type == OTHER_OBJ) 7087c478bd9Sstevel@tonic-gate where = strappend(where, "other:"); 7097c478bd9Sstevel@tonic-gate else 7107c478bd9Sstevel@tonic-gate where = strappend(where, "defaultother:"); 7117c478bd9Sstevel@tonic-gate where = convert_perm(where, aclp->a_perm); 7127c478bd9Sstevel@tonic-gate break; 7137c478bd9Sstevel@tonic-gate default: 7147c478bd9Sstevel@tonic-gate free(dstr->aclexport); 7157c478bd9Sstevel@tonic-gate free(dstr); 7167c478bd9Sstevel@tonic-gate return (NULL); 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate } 7195a5eeccaSmarks 7205a5eeccaSmarks if ((flags & ACL_APPEND_ID) && ((aclp->a_type == USER) || 7215a5eeccaSmarks (aclp->a_type == DEF_USER) || (aclp->a_type == GROUP) || 7225a5eeccaSmarks (aclp->a_type == DEF_GROUP))) { 7235a5eeccaSmarks where = strappend(where, ":"); 7245a5eeccaSmarks id[ID_STR_MAX - 1] = '\0'; /* null terminate buffer */ 7255a5eeccaSmarks idstr = lltostr(aclp->a_id, &id[ID_STR_MAX - 1]); 7265a5eeccaSmarks where = strappend(where, idstr); 7275a5eeccaSmarks } 7287c478bd9Sstevel@tonic-gate if (i < aclcnt - 1) 7297c478bd9Sstevel@tonic-gate where = strappend(where, ","); 7307c478bd9Sstevel@tonic-gate } 7317c478bd9Sstevel@tonic-gate aclexport = dstr->aclexport; 7327c478bd9Sstevel@tonic-gate free(dstr); 7337c478bd9Sstevel@tonic-gate return (aclexport); 7345a5eeccaSmarks 7355a5eeccaSmarks 7365a5eeccaSmarks 7375a5eeccaSmarks 7387c478bd9Sstevel@tonic-gate } 7397c478bd9Sstevel@tonic-gate 7405a5eeccaSmarks char * 7415a5eeccaSmarks acltotext(aclent_t *aclp, int aclcnt) 7427c478bd9Sstevel@tonic-gate { 7435a5eeccaSmarks return (aclent_acltotext(aclp, aclcnt, 0)); 744fa9e4066Sahrens } 745fa9e4066Sahrens 7467c478bd9Sstevel@tonic-gate 747fa9e4066Sahrens aclent_t * 748fa9e4066Sahrens aclfromtext(char *aclstr, int *aclcnt) 749fa9e4066Sahrens { 750fa9e4066Sahrens acl_t *aclp; 751fa9e4066Sahrens aclent_t *aclentp; 752fa9e4066Sahrens int error; 753fa9e4066Sahrens 7545a5eeccaSmarks error = acl_fromtext(aclstr, &aclp); 755fa9e4066Sahrens if (error) 756fa9e4066Sahrens return (NULL); 757fa9e4066Sahrens 758fa9e4066Sahrens aclentp = aclp->acl_aclp; 759fa9e4066Sahrens aclp->acl_aclp = NULL; 760fa9e4066Sahrens *aclcnt = aclp->acl_cnt; 7615a5eeccaSmarks 7625a5eeccaSmarks acl_free(aclp); 763fa9e4066Sahrens return (aclentp); 764fa9e4066Sahrens } 765fa9e4066Sahrens 766fa9e4066Sahrens 7677c478bd9Sstevel@tonic-gate static char * 7687c478bd9Sstevel@tonic-gate strappend(char *where, char *newstr) 7697c478bd9Sstevel@tonic-gate { 7707c478bd9Sstevel@tonic-gate (void) strcat(where, newstr); 7717c478bd9Sstevel@tonic-gate return (where + strlen(newstr)); 7727c478bd9Sstevel@tonic-gate } 7737c478bd9Sstevel@tonic-gate 7747c478bd9Sstevel@tonic-gate static char * 7757c478bd9Sstevel@tonic-gate convert_perm(char *where, o_mode_t perm) 7767c478bd9Sstevel@tonic-gate { 7775a5eeccaSmarks if (perm & S_IROTH) 7787c478bd9Sstevel@tonic-gate where = strappend(where, "r"); 7797c478bd9Sstevel@tonic-gate else 7807c478bd9Sstevel@tonic-gate where = strappend(where, "-"); 7815a5eeccaSmarks if (perm & S_IWOTH) 7827c478bd9Sstevel@tonic-gate where = strappend(where, "w"); 7837c478bd9Sstevel@tonic-gate else 7847c478bd9Sstevel@tonic-gate where = strappend(where, "-"); 7855a5eeccaSmarks if (perm & S_IXOTH) 7867c478bd9Sstevel@tonic-gate where = strappend(where, "x"); 7877c478bd9Sstevel@tonic-gate else 7887c478bd9Sstevel@tonic-gate where = strappend(where, "-"); 7897c478bd9Sstevel@tonic-gate /* perm is the last field */ 7907c478bd9Sstevel@tonic-gate return (where); 7917c478bd9Sstevel@tonic-gate } 7927c478bd9Sstevel@tonic-gate 7937c478bd9Sstevel@tonic-gate /* 7947c478bd9Sstevel@tonic-gate * Callers should check the return code as this routine may change the string 7957c478bd9Sstevel@tonic-gate * pointer in dynaclstr. 7967c478bd9Sstevel@tonic-gate */ 7977c478bd9Sstevel@tonic-gate static int 7987c478bd9Sstevel@tonic-gate increase_length(struct dynaclstr *dacl, size_t increase) 7997c478bd9Sstevel@tonic-gate { 8007c478bd9Sstevel@tonic-gate char *tptr; 8017c478bd9Sstevel@tonic-gate size_t newsize; 8027c478bd9Sstevel@tonic-gate 8037c478bd9Sstevel@tonic-gate newsize = dacl->bufsize + increase; 8047c478bd9Sstevel@tonic-gate tptr = realloc(dacl->aclexport, newsize); 8057c478bd9Sstevel@tonic-gate if (tptr != NULL) { 8067c478bd9Sstevel@tonic-gate dacl->aclexport = tptr; 8077c478bd9Sstevel@tonic-gate dacl->bufsize = newsize; 8087c478bd9Sstevel@tonic-gate return (1); 8097c478bd9Sstevel@tonic-gate } else 8107c478bd9Sstevel@tonic-gate return (0); 8117c478bd9Sstevel@tonic-gate } 812fa9e4066Sahrens 813fa9e4066Sahrens /* 8145a5eeccaSmarks * ace_acltotext() convert each ace formatted acl to look like this: 815fa9e4066Sahrens * 8165a5eeccaSmarks * entry_type:uid^gid^name:perms[:flags]:<allow|deny>[:id][,] 817fa9e4066Sahrens * 818fa9e4066Sahrens * The maximum length of entry_type is 5 ("group") 819fa9e4066Sahrens * 8205a5eeccaSmarks * The max length of a uid^gid^name entry (in theory) is 8, 8215a5eeccaSmarks * however id could be a number so we therefore use ID_STR_MAX 822fa9e4066Sahrens * 823fa9e4066Sahrens * The length of a perms entry is 144 i.e read_data/write_data... 824fa9e4066Sahrens * to each acl entry. 825fa9e4066Sahrens * 826fa9e4066Sahrens * iflags: file_inherit/dir_inherit/inherit_only/no_propagate 827fa9e4066Sahrens * 828fa9e4066Sahrens */ 829fa9e4066Sahrens 830fa9e4066Sahrens #define ACE_ENTRYTYPLEN 6 831fa9e4066Sahrens #define IFLAGS_SIZE 51 8325a5eeccaSmarks #define ACCESS_TYPE_SIZE 7 /* if unknown */ 833fa9e4066Sahrens #define COLON_CNT 3 834fa9e4066Sahrens #define PERMS_LEN 216 8355a5eeccaSmarks #define ACE_ENTRY_SIZE (ACE_ENTRYTYPLEN + ID_STR_MAX + PERMS_LEN +\ 8365a5eeccaSmarks ACCESS_TYPE_SIZE + IFLAGS_SIZE + COLON_CNT + APPENDED_ID_MAX) 837fa9e4066Sahrens 838fa9e4066Sahrens static char * 8395a5eeccaSmarks ace_acltotext(acl_t *aceaclp, int flags) 840fa9e4066Sahrens { 841fa9e4066Sahrens ace_t *aclp = aceaclp->acl_aclp; 842fa9e4066Sahrens int aclcnt = aceaclp->acl_cnt; 843fa9e4066Sahrens char *aclexport; 8445a5eeccaSmarks char *endp; 8455a5eeccaSmarks int i; 8465a5eeccaSmarks char id[ID_STR_MAX], *idstr; 847fa9e4066Sahrens int isdir = (aceaclp->acl_flags & ACL_IS_DIR); 848fa9e4066Sahrens 849fa9e4066Sahrens if (aclp == NULL) 850fa9e4066Sahrens return (NULL); 8515a5eeccaSmarks if ((aclexport = malloc(aclcnt * ACE_ENTRY_SIZE)) == NULL) 852fa9e4066Sahrens return (NULL); 853fa9e4066Sahrens 8545a5eeccaSmarks aclexport[0] = '\0'; 8555a5eeccaSmarks endp = aclexport; 856fa9e4066Sahrens for (i = 0; i < aclcnt; i++, aclp++) { 857fa9e4066Sahrens 8585a5eeccaSmarks (void) ace_type_txt(endp, &endp, aclp); 8595a5eeccaSmarks *endp++ = ':'; 8605a5eeccaSmarks *endp = '\0'; 8615a5eeccaSmarks (void) ace_perm_txt(endp, &endp, aclp->a_access_mask, 8625a5eeccaSmarks aclp->a_flags, isdir, flags); 8635a5eeccaSmarks *endp++ = ':'; 8645a5eeccaSmarks *endp = '\0'; 8655a5eeccaSmarks (void) ace_inherit_txt(endp, &endp, aclp->a_flags, flags); 8665a5eeccaSmarks if (flags & ACL_COMPACT_FMT || aclp->a_flags & 8675a5eeccaSmarks (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE | 8685a5eeccaSmarks (ACE_INHERIT_ONLY_ACE | ACE_NO_PROPAGATE_INHERIT_ACE))) { 8695a5eeccaSmarks *endp++ = ':'; 8705a5eeccaSmarks *endp = '\0'; 871fa9e4066Sahrens } 8725a5eeccaSmarks (void) ace_access_txt(endp, &endp, aclp->a_type); 873fa9e4066Sahrens 8745a5eeccaSmarks if ((flags & ACL_APPEND_ID) && 8755a5eeccaSmarks (((aclp->a_flags & ACE_TYPE_FLAGS) == 0) || 8765a5eeccaSmarks ((aclp->a_flags & ACE_TYPE_FLAGS) == 8775a5eeccaSmarks ACE_IDENTIFIER_GROUP))) { 8785a5eeccaSmarks *endp++ = ':'; 8795a5eeccaSmarks *endp = '\0'; 8805a5eeccaSmarks id[ID_STR_MAX -1] = '\0'; /* null terminate buffer */ 8815a5eeccaSmarks idstr = lltostr(aclp->a_who, &id[ID_STR_MAX - 1]); 8825a5eeccaSmarks strcpy(endp, idstr); 8835a5eeccaSmarks endp += strlen(idstr); 8845a5eeccaSmarks } 8855a5eeccaSmarks if (i < aclcnt - 1) { 8865a5eeccaSmarks *endp++ = ','; 8875a5eeccaSmarks *(endp + 1) = '\0'; 888fa9e4066Sahrens } 889fa9e4066Sahrens } 890fa9e4066Sahrens return (aclexport); 891fa9e4066Sahrens } 892fa9e4066Sahrens 8935a5eeccaSmarks char * 8945a5eeccaSmarks acl_totext(acl_t *aclp, int flags) 895fa9e4066Sahrens { 896fa9e4066Sahrens 8975a5eeccaSmarks char *txtp; 898fa9e4066Sahrens 899fa9e4066Sahrens if (aclp == NULL) 900fa9e4066Sahrens return (NULL); 901fa9e4066Sahrens 902fa9e4066Sahrens switch (aclp->acl_type) { 903fa9e4066Sahrens case ACE_T: 9045a5eeccaSmarks txtp = ace_acltotext(aclp, flags); 9055a5eeccaSmarks break; 906fa9e4066Sahrens case ACLENT_T: 9075a5eeccaSmarks txtp = aclent_acltotext(aclp->acl_aclp, aclp->acl_cnt, flags); 9085a5eeccaSmarks break; 909fa9e4066Sahrens } 9105a5eeccaSmarks 9115a5eeccaSmarks return (txtp); 912fa9e4066Sahrens } 913fa9e4066Sahrens 914fa9e4066Sahrens int 915fa9e4066Sahrens acl_fromtext(const char *acltextp, acl_t **ret_aclp) 916fa9e4066Sahrens { 9175a5eeccaSmarks int error; 9185a5eeccaSmarks char *buf; 9195a5eeccaSmarks 9205a5eeccaSmarks buf = malloc(strlen(acltextp) + 2); 9215a5eeccaSmarks if (buf == NULL) 9225a5eeccaSmarks return (EACL_MEM_ERROR); 9235a5eeccaSmarks strcpy(buf, acltextp); 9245a5eeccaSmarks strcat(buf, "\n"); 9255a5eeccaSmarks yybuf = buf; 9265a5eeccaSmarks yyreset(); 9275a5eeccaSmarks error = yyparse(); 9285a5eeccaSmarks free(buf); 9295a5eeccaSmarks 9305a5eeccaSmarks if (yyacl) { 9315a5eeccaSmarks if (error == 0) 9325a5eeccaSmarks *ret_aclp = yyacl; 9335a5eeccaSmarks else { 9345a5eeccaSmarks acl_free(yyacl); 9355a5eeccaSmarks } 9365a5eeccaSmarks yyacl = NULL; 9375a5eeccaSmarks } 9385a5eeccaSmarks return (error); 9395a5eeccaSmarks } 9405a5eeccaSmarks 9415a5eeccaSmarks int 9425a5eeccaSmarks acl_parse(const char *acltextp, acl_t **aclp) 9435a5eeccaSmarks { 944fa9e4066Sahrens int error; 945fa9e4066Sahrens 9465a5eeccaSmarks yyinteractive = 1; 9475a5eeccaSmarks error = acl_fromtext(acltextp, aclp); 9485a5eeccaSmarks yyinteractive = 0; 949fa9e4066Sahrens return (error); 950fa9e4066Sahrens } 9515a5eeccaSmarks 9525a5eeccaSmarks static void 9535a5eeccaSmarks ace_compact_printacl(acl_t *aclp) 9545a5eeccaSmarks { 9555a5eeccaSmarks int cnt; 9565a5eeccaSmarks ace_t *acep; 9575a5eeccaSmarks char *endp; 9585a5eeccaSmarks char buf[ACE_ENTRY_SIZE]; 9595a5eeccaSmarks 9605a5eeccaSmarks for (cnt = 0, acep = aclp->acl_aclp; 9615a5eeccaSmarks cnt != aclp->acl_cnt; cnt++, acep++) { 9625a5eeccaSmarks buf[0] = '\0'; 9635a5eeccaSmarks (void) printf(" %14s:", ace_type_txt(buf, &endp, acep)); 9645a5eeccaSmarks (void) printf("%s:", ace_perm_txt(endp, &endp, 9655a5eeccaSmarks acep->a_access_mask, acep->a_flags, 9665a5eeccaSmarks aclp->acl_flags & ACL_IS_DIR, ACL_COMPACT_FMT)); 9675a5eeccaSmarks (void) printf("%s:", 9685a5eeccaSmarks ace_inherit_txt(endp, &endp, acep->a_flags, 9695a5eeccaSmarks ACL_COMPACT_FMT)); 9705a5eeccaSmarks (void) printf("%s\n", ace_access_txt(endp, &endp, 9715a5eeccaSmarks acep->a_type)); 9725a5eeccaSmarks } 9735a5eeccaSmarks } 9745a5eeccaSmarks 9755a5eeccaSmarks static void 9765a5eeccaSmarks ace_printacl(acl_t *aclp, int cols, int compact) 9775a5eeccaSmarks { 9785a5eeccaSmarks int slot = 0; 9795a5eeccaSmarks char *token; 9805a5eeccaSmarks char *acltext; 9815a5eeccaSmarks 9825a5eeccaSmarks if (compact) { 9835a5eeccaSmarks ace_compact_printacl(aclp); 9845a5eeccaSmarks return; 9855a5eeccaSmarks } 9865a5eeccaSmarks 9875a5eeccaSmarks acltext = acl_totext(aclp, 0); 9885a5eeccaSmarks 9895a5eeccaSmarks if (acltext == NULL) 9905a5eeccaSmarks return; 9915a5eeccaSmarks 9925a5eeccaSmarks token = strtok(acltext, ","); 9935a5eeccaSmarks if (token == NULL) { 9945a5eeccaSmarks free(acltext); 9955a5eeccaSmarks return; 9965a5eeccaSmarks } 9975a5eeccaSmarks 9985a5eeccaSmarks do { 9995a5eeccaSmarks (void) printf(" %d:", slot++); 10005a5eeccaSmarks split_line(token, cols - 5); 10015a5eeccaSmarks } while (token = strtok(NULL, ",")); 10025a5eeccaSmarks free(acltext); 10035a5eeccaSmarks } 10045a5eeccaSmarks 10055a5eeccaSmarks /* 10065a5eeccaSmarks * pretty print an ACL. 10075a5eeccaSmarks * For aclent_t ACL's the format is 10085a5eeccaSmarks * similar to the old format used by getfacl, 10095a5eeccaSmarks * with the addition of adding a "slot" number 10105a5eeccaSmarks * before each entry. 10115a5eeccaSmarks * 10125a5eeccaSmarks * for ace_t ACL's the cols variable will break up 10135a5eeccaSmarks * the long lines into multiple lines and will also 10145a5eeccaSmarks * print a "slot" number. 10155a5eeccaSmarks */ 10165a5eeccaSmarks void 10175a5eeccaSmarks acl_printacl(acl_t *aclp, int cols, int compact) 10185a5eeccaSmarks { 10195a5eeccaSmarks 10205a5eeccaSmarks switch (aclp->acl_type) { 10215a5eeccaSmarks case ACLENT_T: 10225a5eeccaSmarks aclent_printacl(aclp); 10235a5eeccaSmarks break; 10245a5eeccaSmarks case ACE_T: 10255a5eeccaSmarks ace_printacl(aclp, cols, compact); 10265a5eeccaSmarks break; 10275a5eeccaSmarks } 10285a5eeccaSmarks } 10295a5eeccaSmarks 10305a5eeccaSmarks typedef struct value_table { 10315a5eeccaSmarks char p_letter; /* perm letter such as 'r' */ 10325a5eeccaSmarks uint32_t p_value; /* value for perm when pletter found */ 10335a5eeccaSmarks } value_table_t; 10345a5eeccaSmarks 10355a5eeccaSmarks #define ACE_PERM_COUNT 14 10365a5eeccaSmarks 10375a5eeccaSmarks /* 10385a5eeccaSmarks * The permission tables are layed out in positional order 10395a5eeccaSmarks * a '-' character will indicate a permission at a given 10405a5eeccaSmarks * position is not specified. The '-' is not part of the 10415a5eeccaSmarks * table, but will be checked for in the permission computation 10425a5eeccaSmarks * routine. 10435a5eeccaSmarks */ 10445a5eeccaSmarks value_table_t ace_perm_table[ACE_PERM_COUNT] = { 10455a5eeccaSmarks { 'r', ACE_READ_DATA}, 10465a5eeccaSmarks { 'w', ACE_WRITE_DATA}, 10475a5eeccaSmarks { 'x', ACE_EXECUTE}, 10485a5eeccaSmarks { 'p', ACE_APPEND_DATA}, 10495a5eeccaSmarks { 'd', ACE_DELETE}, 10505a5eeccaSmarks { 'D', ACE_DELETE_CHILD}, 10515a5eeccaSmarks { 'a', ACE_READ_ATTRIBUTES}, 10525a5eeccaSmarks { 'A', ACE_WRITE_ATTRIBUTES}, 10535a5eeccaSmarks { 'R', ACE_READ_NAMED_ATTRS}, 10545a5eeccaSmarks { 'W', ACE_WRITE_NAMED_ATTRS}, 10555a5eeccaSmarks { 'c', ACE_READ_ACL}, 10565a5eeccaSmarks { 'C', ACE_WRITE_ACL}, 10575a5eeccaSmarks { 'o', ACE_WRITE_OWNER}, 10585a5eeccaSmarks { 's', ACE_SYNCHRONIZE} 10595a5eeccaSmarks }; 10605a5eeccaSmarks 10615a5eeccaSmarks #define ACLENT_PERM_COUNT 3 10625a5eeccaSmarks 10635a5eeccaSmarks value_table_t aclent_perm_table[ACLENT_PERM_COUNT] = { 10645a5eeccaSmarks { 'r', S_IROTH}, 10655a5eeccaSmarks { 'w', S_IWOTH}, 10665a5eeccaSmarks { 'x', S_IXOTH} 10675a5eeccaSmarks }; 10685a5eeccaSmarks 10695a5eeccaSmarks #define IFLAG_COUNT 6 10705a5eeccaSmarks value_table_t inherit_table[IFLAG_COUNT] = { 10715a5eeccaSmarks {'f', ACE_FILE_INHERIT_ACE}, 10725a5eeccaSmarks {'d', ACE_DIRECTORY_INHERIT_ACE}, 10735a5eeccaSmarks {'i', ACE_INHERIT_ONLY_ACE}, 10745a5eeccaSmarks {'n', ACE_NO_PROPAGATE_INHERIT_ACE}, 10755a5eeccaSmarks {'S', ACE_SUCCESSFUL_ACCESS_ACE_FLAG}, 10765a5eeccaSmarks {'F', ACE_FAILED_ACCESS_ACE_FLAG} 10775a5eeccaSmarks }; 10785a5eeccaSmarks 10795a5eeccaSmarks /* 10805a5eeccaSmarks * compute value from a permission table or inheritance table 10815a5eeccaSmarks * based on string passed in. If positional is set then 10825a5eeccaSmarks * string must match order in permtab, otherwise any order 10835a5eeccaSmarks * is allowed. 10845a5eeccaSmarks */ 10855a5eeccaSmarks int 10865a5eeccaSmarks compute_values(value_table_t *permtab, int count, 10875a5eeccaSmarks char *permstr, int positional, uint32_t *mask) 10885a5eeccaSmarks { 10895a5eeccaSmarks uint32_t perm_val = 0; 10905a5eeccaSmarks char *pstr; 10915a5eeccaSmarks int i, found; 10925a5eeccaSmarks 10935a5eeccaSmarks if (count < 0) 10945a5eeccaSmarks return (1); 10955a5eeccaSmarks 10965a5eeccaSmarks if (positional) { 10975a5eeccaSmarks for (i = 0, pstr = permstr; i != count && pstr && 10985a5eeccaSmarks *pstr; i++, pstr++) { 10995a5eeccaSmarks if (*pstr == permtab[i].p_letter) { 11005a5eeccaSmarks perm_val |= permtab[i].p_value; 11015a5eeccaSmarks } else if (*pstr != '-') { 11025a5eeccaSmarks return (1); 11035a5eeccaSmarks } 11045a5eeccaSmarks } 11055a5eeccaSmarks } else { /* random order single letters with no '-' */ 11065a5eeccaSmarks for (pstr = permstr; pstr && *pstr; pstr++) { 11075a5eeccaSmarks for (found = 0, i = 0; i != count; i++) { 11085a5eeccaSmarks if (*pstr == permtab[i].p_letter) { 11095a5eeccaSmarks perm_val |= permtab[i].p_value; 11105a5eeccaSmarks found = 1; 11115a5eeccaSmarks break; 11125a5eeccaSmarks } 11135a5eeccaSmarks } 11145a5eeccaSmarks if (found == 0) 11155a5eeccaSmarks return (1); 11165a5eeccaSmarks } 11175a5eeccaSmarks } 11185a5eeccaSmarks 11195a5eeccaSmarks *mask = perm_val; 11205a5eeccaSmarks return (0); 11215a5eeccaSmarks } 11225a5eeccaSmarks 11235a5eeccaSmarks /* 11245a5eeccaSmarks * compute value for inheritance flags. 11255a5eeccaSmarks */ 11265a5eeccaSmarks int 11275a5eeccaSmarks compute_ace_inherit(char *str, uint32_t *imask) 11285a5eeccaSmarks { 11295a5eeccaSmarks int error; 11305a5eeccaSmarks int positional = 0; 11315a5eeccaSmarks 11325a5eeccaSmarks if (strlen(str) == IFLAG_COUNT) 11335a5eeccaSmarks positional = 1; 11345a5eeccaSmarks 11355a5eeccaSmarks error = compute_values(inherit_table, IFLAG_COUNT, 11365a5eeccaSmarks str, positional, imask); 11375a5eeccaSmarks 11385a5eeccaSmarks if (error) 11395a5eeccaSmarks return (EACL_INHERIT_ERROR); 11405a5eeccaSmarks 11415a5eeccaSmarks return (error); 11425a5eeccaSmarks } 11435a5eeccaSmarks 11445a5eeccaSmarks 11455a5eeccaSmarks /* 11465a5eeccaSmarks * compute value for ACE permissions. 11475a5eeccaSmarks */ 11485a5eeccaSmarks int 11495a5eeccaSmarks compute_ace_perms(char *str, uint32_t *mask) 11505a5eeccaSmarks { 11515a5eeccaSmarks int positional = 0; 11525a5eeccaSmarks int error; 11535a5eeccaSmarks 11545a5eeccaSmarks if (strlen(str) == ACE_PERM_COUNT) 11555a5eeccaSmarks positional = 1; 11565a5eeccaSmarks 11575a5eeccaSmarks error = compute_values(ace_perm_table, ACE_PERM_COUNT, 11585a5eeccaSmarks str, positional, mask); 11595a5eeccaSmarks 11605a5eeccaSmarks if (error && positional) { 11615a5eeccaSmarks /* 11625a5eeccaSmarks * If positional was set, then make sure permissions 11635a5eeccaSmarks * aren't actually valid in non positional case where 11645a5eeccaSmarks * all permissions are specified, just in random order. 11655a5eeccaSmarks */ 11665a5eeccaSmarks error = compute_values(ace_perm_table, 11675a5eeccaSmarks ACE_PERM_COUNT, str, 0, mask); 11685a5eeccaSmarks } 11695a5eeccaSmarks if (error) 11705a5eeccaSmarks error = EACL_PERM_MASK_ERROR; 11715a5eeccaSmarks 11725a5eeccaSmarks return (error); 11735a5eeccaSmarks } 11745a5eeccaSmarks 11755a5eeccaSmarks 11765a5eeccaSmarks 11775a5eeccaSmarks /* 11785a5eeccaSmarks * compute values for aclent permissions. 11795a5eeccaSmarks */ 11805a5eeccaSmarks int 11815a5eeccaSmarks compute_aclent_perms(char *str, o_mode_t *mask) 11825a5eeccaSmarks { 11835a5eeccaSmarks int error; 11845a5eeccaSmarks uint32_t pmask; 11855a5eeccaSmarks 11865a5eeccaSmarks if (strlen(str) != ACLENT_PERM_COUNT) 11875a5eeccaSmarks return (EACL_PERM_MASK_ERROR); 11885a5eeccaSmarks 11895a5eeccaSmarks *mask = 0; 11905a5eeccaSmarks error = compute_values(aclent_perm_table, ACLENT_PERM_COUNT, 11915a5eeccaSmarks str, 1, &pmask); 11925a5eeccaSmarks if (error == 0) { 11935a5eeccaSmarks *mask = (o_mode_t)pmask; 11945a5eeccaSmarks } else 11955a5eeccaSmarks error = EACL_PERM_MASK_ERROR; 11965a5eeccaSmarks return (error); 11975a5eeccaSmarks } 11985a5eeccaSmarks 11995a5eeccaSmarks /* 12005a5eeccaSmarks * determine ACE permissions. 12015a5eeccaSmarks */ 12025a5eeccaSmarks int 12035a5eeccaSmarks ace_perm_mask(struct acl_perm_type *aclperm, uint32_t *mask) 12045a5eeccaSmarks { 12055a5eeccaSmarks int error; 12065a5eeccaSmarks 12075a5eeccaSmarks if (aclperm->perm_style == PERM_TYPE_EMPTY) { 12085a5eeccaSmarks *mask = 0; 12095a5eeccaSmarks return (0); 12105a5eeccaSmarks } 12115a5eeccaSmarks 12125a5eeccaSmarks if (aclperm->perm_style == PERM_TYPE_ACE) { 12135a5eeccaSmarks *mask = aclperm->perm_val; 12145a5eeccaSmarks return (0); 12155a5eeccaSmarks } 12165a5eeccaSmarks 12175a5eeccaSmarks error = compute_ace_perms(aclperm->perm_str, mask); 12185a5eeccaSmarks if (error) { 12195a5eeccaSmarks acl_error(gettext("Invalid permission(s) '%s' specified\n"), 12205a5eeccaSmarks aclperm->perm_str); 12215a5eeccaSmarks return (EACL_PERM_MASK_ERROR); 12225a5eeccaSmarks } 12235a5eeccaSmarks 12245a5eeccaSmarks return (0); 12255a5eeccaSmarks } 1226