10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 230Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate /*LINTLIBRARY*/ 290Sstevel@tonic-gate 300Sstevel@tonic-gate #include <grp.h> 310Sstevel@tonic-gate #include <pwd.h> 320Sstevel@tonic-gate #include <string.h> 330Sstevel@tonic-gate #include <limits.h> 340Sstevel@tonic-gate #include <stdlib.h> 35*789Sahrens #include <errno.h> 360Sstevel@tonic-gate #include <sys/param.h> 370Sstevel@tonic-gate #include <sys/types.h> 380Sstevel@tonic-gate #include <sys/acl.h> 39*789Sahrens #include <aclutils.h> 40*789Sahrens #include <libintl.h> 41*789Sahrens 42*789Sahrens 43*789Sahrens extern acl_t *acl_alloc(enum acl_type); 440Sstevel@tonic-gate 450Sstevel@tonic-gate /* 460Sstevel@tonic-gate * acltotext() converts each ACL entry to look like this: 470Sstevel@tonic-gate * 480Sstevel@tonic-gate * entry_type:uid^gid^name:perms 490Sstevel@tonic-gate * 500Sstevel@tonic-gate * The maximum length of entry_type is 14 ("defaultgroup::" and 510Sstevel@tonic-gate * "defaultother::") hence ENTRYTYPELEN is set to 14. 520Sstevel@tonic-gate * 530Sstevel@tonic-gate * The max length of a uid^gid^name entry (in theory) is 8, hence we use 540Sstevel@tonic-gate * LOGNAME_MAX. 550Sstevel@tonic-gate * 560Sstevel@tonic-gate * The length of a perms entry is 4 to allow for the comma appended to each 570Sstevel@tonic-gate * to each acl entry. Hence PERMS is set to 4. 580Sstevel@tonic-gate */ 590Sstevel@tonic-gate 600Sstevel@tonic-gate #define ENTRYTYPELEN 14 610Sstevel@tonic-gate #define PERMS 4 620Sstevel@tonic-gate #define ACL_ENTRY_SIZE (ENTRYTYPELEN + LOGNAME_MAX + PERMS) 630Sstevel@tonic-gate 640Sstevel@tonic-gate struct dynaclstr { 650Sstevel@tonic-gate size_t bufsize; /* current size of aclexport */ 660Sstevel@tonic-gate char *aclexport; 670Sstevel@tonic-gate }; 680Sstevel@tonic-gate 690Sstevel@tonic-gate static char *strappend(char *, char *); 700Sstevel@tonic-gate static char *convert_perm(char *, o_mode_t); 710Sstevel@tonic-gate static int increase_length(struct dynaclstr *, size_t); 720Sstevel@tonic-gate 73*789Sahrens static int 74*789Sahrens acl_str_to_id(char *str, int *id) 75*789Sahrens { 76*789Sahrens char *end; 77*789Sahrens uid_t value; 78*789Sahrens 79*789Sahrens value = strtol(str, &end, 10); 80*789Sahrens 81*789Sahrens if (errno != 0 || *end != '\0') 82*789Sahrens return (EACL_INVALID_USER_GROUP); 83*789Sahrens 84*789Sahrens *id = value; 85*789Sahrens 86*789Sahrens return (0); 87*789Sahrens } 880Sstevel@tonic-gate 890Sstevel@tonic-gate /* 900Sstevel@tonic-gate * Convert internal acl representation to external representation. 910Sstevel@tonic-gate * 920Sstevel@tonic-gate * The length of a non-owning user name or non-owning group name ie entries 930Sstevel@tonic-gate * of type DEF_USER, USER, DEF_GROUP or GROUP, can exceed LOGNAME_MAX. We 940Sstevel@tonic-gate * thus check the length of these entries, and if greater than LOGNAME_MAX, 950Sstevel@tonic-gate * we realloc() via increase_length(). 960Sstevel@tonic-gate * 970Sstevel@tonic-gate * The LOGNAME_MAX, ENTRYTYPELEN and PERMS limits are otherwise always 980Sstevel@tonic-gate * adhered to. 990Sstevel@tonic-gate */ 1000Sstevel@tonic-gate char * 1010Sstevel@tonic-gate acltotext(aclent_t *aclp, int aclcnt) 1020Sstevel@tonic-gate { 1030Sstevel@tonic-gate char *aclexport; 1040Sstevel@tonic-gate char *where; 1050Sstevel@tonic-gate struct group *groupp; 1060Sstevel@tonic-gate struct passwd *passwdp; 1070Sstevel@tonic-gate struct dynaclstr *dstr; 1080Sstevel@tonic-gate int i, rtn; 1090Sstevel@tonic-gate size_t excess = 0; 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate if (aclp == NULL) 1120Sstevel@tonic-gate return (NULL); 1130Sstevel@tonic-gate if ((dstr = malloc(sizeof (struct dynaclstr))) == NULL) 1140Sstevel@tonic-gate return (NULL); 1150Sstevel@tonic-gate dstr->bufsize = aclcnt * ACL_ENTRY_SIZE; 1160Sstevel@tonic-gate if ((dstr->aclexport = malloc(dstr->bufsize)) == NULL) { 1170Sstevel@tonic-gate free(dstr); 1180Sstevel@tonic-gate return (NULL); 1190Sstevel@tonic-gate } 1200Sstevel@tonic-gate *dstr->aclexport = '\0'; 1210Sstevel@tonic-gate where = dstr->aclexport; 1220Sstevel@tonic-gate 1230Sstevel@tonic-gate for (i = 0; i < aclcnt; i++, aclp++) { 1240Sstevel@tonic-gate switch (aclp->a_type) { 1250Sstevel@tonic-gate case DEF_USER_OBJ: 1260Sstevel@tonic-gate case USER_OBJ: 1270Sstevel@tonic-gate if (aclp->a_type == USER_OBJ) 1280Sstevel@tonic-gate where = strappend(where, "user::"); 1290Sstevel@tonic-gate else 1300Sstevel@tonic-gate where = strappend(where, "defaultuser::"); 1310Sstevel@tonic-gate where = convert_perm(where, aclp->a_perm); 1320Sstevel@tonic-gate break; 1330Sstevel@tonic-gate case DEF_USER: 1340Sstevel@tonic-gate case USER: 1350Sstevel@tonic-gate if (aclp->a_type == USER) 1360Sstevel@tonic-gate where = strappend(where, "user:"); 1370Sstevel@tonic-gate else 1380Sstevel@tonic-gate where = strappend(where, "defaultuser:"); 1390Sstevel@tonic-gate passwdp = getpwuid(aclp->a_id); 1400Sstevel@tonic-gate if (passwdp == (struct passwd *)NULL) { 1410Sstevel@tonic-gate /* put in uid instead */ 1420Sstevel@tonic-gate (void) sprintf(where, "%d", aclp->a_id); 1430Sstevel@tonic-gate } else { 1440Sstevel@tonic-gate excess = strlen(passwdp->pw_name) - LOGNAME_MAX; 1450Sstevel@tonic-gate if (excess > 0) { 1460Sstevel@tonic-gate rtn = increase_length(dstr, excess); 1470Sstevel@tonic-gate if (rtn == 1) { 1480Sstevel@tonic-gate /* reset where */ 1490Sstevel@tonic-gate where = dstr->aclexport + 1500Sstevel@tonic-gate strlen(dstr->aclexport); 1510Sstevel@tonic-gate } else { 1520Sstevel@tonic-gate free(dstr->aclexport); 1530Sstevel@tonic-gate free(dstr); 1540Sstevel@tonic-gate return (NULL); 1550Sstevel@tonic-gate } 1560Sstevel@tonic-gate } 1570Sstevel@tonic-gate where = strappend(where, passwdp->pw_name); 1580Sstevel@tonic-gate } 1590Sstevel@tonic-gate where = strappend(where, ":"); 1600Sstevel@tonic-gate where = convert_perm(where, aclp->a_perm); 1610Sstevel@tonic-gate break; 1620Sstevel@tonic-gate case DEF_GROUP_OBJ: 1630Sstevel@tonic-gate case GROUP_OBJ: 1640Sstevel@tonic-gate if (aclp->a_type == GROUP_OBJ) 1650Sstevel@tonic-gate where = strappend(where, "group::"); 1660Sstevel@tonic-gate else 1670Sstevel@tonic-gate where = strappend(where, "defaultgroup::"); 1680Sstevel@tonic-gate where = convert_perm(where, aclp->a_perm); 1690Sstevel@tonic-gate break; 1700Sstevel@tonic-gate case DEF_GROUP: 1710Sstevel@tonic-gate case GROUP: 1720Sstevel@tonic-gate if (aclp->a_type == GROUP) 1730Sstevel@tonic-gate where = strappend(where, "group:"); 1740Sstevel@tonic-gate else 1750Sstevel@tonic-gate where = strappend(where, "defaultgroup:"); 1760Sstevel@tonic-gate groupp = getgrgid(aclp->a_id); 1770Sstevel@tonic-gate if (groupp == (struct group *)NULL) { 1780Sstevel@tonic-gate /* put in gid instead */ 1790Sstevel@tonic-gate (void) sprintf(where, "%d", aclp->a_id); 1800Sstevel@tonic-gate } else { 1810Sstevel@tonic-gate excess = strlen(groupp->gr_name) - LOGNAME_MAX; 1820Sstevel@tonic-gate if (excess > 0) { 1830Sstevel@tonic-gate rtn = increase_length(dstr, excess); 1840Sstevel@tonic-gate if (rtn == 1) { 1850Sstevel@tonic-gate /* reset where */ 1860Sstevel@tonic-gate where = dstr->aclexport + 1870Sstevel@tonic-gate strlen(dstr->aclexport); 1880Sstevel@tonic-gate } else { 1890Sstevel@tonic-gate free(dstr->aclexport); 1900Sstevel@tonic-gate free(dstr); 1910Sstevel@tonic-gate return (NULL); 1920Sstevel@tonic-gate } 1930Sstevel@tonic-gate } 1940Sstevel@tonic-gate where = strappend(where, groupp->gr_name); 1950Sstevel@tonic-gate } 1960Sstevel@tonic-gate where = strappend(where, ":"); 1970Sstevel@tonic-gate where = convert_perm(where, aclp->a_perm); 1980Sstevel@tonic-gate break; 1990Sstevel@tonic-gate case DEF_CLASS_OBJ: 2000Sstevel@tonic-gate case CLASS_OBJ: 2010Sstevel@tonic-gate if (aclp->a_type == CLASS_OBJ) 2020Sstevel@tonic-gate where = strappend(where, "mask:"); 2030Sstevel@tonic-gate else 2040Sstevel@tonic-gate where = strappend(where, "defaultmask:"); 2050Sstevel@tonic-gate where = convert_perm(where, aclp->a_perm); 2060Sstevel@tonic-gate break; 2070Sstevel@tonic-gate case DEF_OTHER_OBJ: 2080Sstevel@tonic-gate case OTHER_OBJ: 2090Sstevel@tonic-gate if (aclp->a_type == OTHER_OBJ) 2100Sstevel@tonic-gate where = strappend(where, "other:"); 2110Sstevel@tonic-gate else 2120Sstevel@tonic-gate where = strappend(where, "defaultother:"); 2130Sstevel@tonic-gate where = convert_perm(where, aclp->a_perm); 2140Sstevel@tonic-gate break; 2150Sstevel@tonic-gate default: 2160Sstevel@tonic-gate free(dstr->aclexport); 2170Sstevel@tonic-gate free(dstr); 2180Sstevel@tonic-gate return (NULL); 2190Sstevel@tonic-gate 2200Sstevel@tonic-gate } 2210Sstevel@tonic-gate if (i < aclcnt - 1) 2220Sstevel@tonic-gate where = strappend(where, ","); 2230Sstevel@tonic-gate } 2240Sstevel@tonic-gate aclexport = dstr->aclexport; 2250Sstevel@tonic-gate free(dstr); 2260Sstevel@tonic-gate return (aclexport); 2270Sstevel@tonic-gate } 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate /* 2300Sstevel@tonic-gate * Convert external acl representation to internal representation. 2310Sstevel@tonic-gate * The accepted syntax is: <acl_entry>[,<acl_entry>]*[,] 2320Sstevel@tonic-gate * The comma at the end is not prescribed by the man pages. 2330Sstevel@tonic-gate * But it is needed not to break the old programs. 2340Sstevel@tonic-gate */ 235*789Sahrens static int 236*789Sahrens aclent_aclfromtext(char *aclstr, acl_t **ret_aclp) 2370Sstevel@tonic-gate { 2380Sstevel@tonic-gate char *fieldp; 2390Sstevel@tonic-gate char *tp; 2400Sstevel@tonic-gate char *nextp; 2410Sstevel@tonic-gate char *allocp; 2420Sstevel@tonic-gate char *aclimport; 2430Sstevel@tonic-gate int entry_type; 2440Sstevel@tonic-gate int id; 2450Sstevel@tonic-gate int len; 246*789Sahrens int error; 2470Sstevel@tonic-gate o_mode_t perm; 2480Sstevel@tonic-gate aclent_t *tmpaclp; 249*789Sahrens acl_t *aclp; 2500Sstevel@tonic-gate struct group *groupp; 2510Sstevel@tonic-gate struct passwd *passwdp; 2520Sstevel@tonic-gate 2530Sstevel@tonic-gate aclp = NULL; 2540Sstevel@tonic-gate 2550Sstevel@tonic-gate if (! aclstr) 2560Sstevel@tonic-gate return (NULL); 2570Sstevel@tonic-gate 258*789Sahrens aclp = acl_alloc(ACLENT_T); 259*789Sahrens if (aclp == NULL) { 260*789Sahrens return (EACL_MEM_ERROR); 261*789Sahrens } 262*789Sahrens 263*789Sahrens *ret_aclp = NULL; 264*789Sahrens 2650Sstevel@tonic-gate len = strlen(aclstr); 2660Sstevel@tonic-gate 2670Sstevel@tonic-gate if ((aclimport = allocp = strdup(aclstr)) == NULL) { 268*789Sahrens return (EACL_MEM_ERROR); 2690Sstevel@tonic-gate } 2700Sstevel@tonic-gate 2710Sstevel@tonic-gate if (aclimport[len - 1] == ',') 2720Sstevel@tonic-gate aclimport[len - 1] = '\0'; 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate for (; aclimport; ) { 2750Sstevel@tonic-gate /* look for an ACL entry */ 2760Sstevel@tonic-gate tp = strchr(aclimport, ','); 2770Sstevel@tonic-gate if (tp == NULL) { 2780Sstevel@tonic-gate nextp = NULL; 2790Sstevel@tonic-gate } else { 2800Sstevel@tonic-gate *tp = '\0'; 2810Sstevel@tonic-gate nextp = tp + 1; 2820Sstevel@tonic-gate } 2830Sstevel@tonic-gate 284*789Sahrens aclp->acl_cnt += 1; 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate /* 2870Sstevel@tonic-gate * get additional memory: 2880Sstevel@tonic-gate * can be more efficient by allocating a bigger block 2890Sstevel@tonic-gate * each time. 2900Sstevel@tonic-gate */ 291*789Sahrens if (aclp->acl_cnt > 1) 292*789Sahrens tmpaclp = (aclent_t *)realloc(aclp->acl_aclp, 293*789Sahrens sizeof (aclent_t) * (aclp->acl_cnt)); 2940Sstevel@tonic-gate else 2950Sstevel@tonic-gate tmpaclp = (aclent_t *)malloc(sizeof (aclent_t)); 2960Sstevel@tonic-gate if (tmpaclp == NULL) { 2970Sstevel@tonic-gate free(allocp); 298*789Sahrens acl_free(aclp); 299*789Sahrens return (EACL_MEM_ERROR); 3000Sstevel@tonic-gate } 301*789Sahrens aclp->acl_aclp = tmpaclp; 302*789Sahrens tmpaclp = (aclent_t *)aclp->acl_aclp + (aclp->acl_cnt - 1); 3030Sstevel@tonic-gate 3040Sstevel@tonic-gate /* look for entry type field */ 3050Sstevel@tonic-gate tp = strchr(aclimport, ':'); 3060Sstevel@tonic-gate if (tp == NULL) { 307*789Sahrens free(allocp); 308*789Sahrens if (aclp) 309*789Sahrens acl_free(aclp); 310*789Sahrens return (EACL_ENTRY_ERROR); 3110Sstevel@tonic-gate } else 3120Sstevel@tonic-gate *tp = '\0'; 3130Sstevel@tonic-gate if (strcmp(aclimport, "user") == 0) { 3140Sstevel@tonic-gate if (*(tp+1) == ':') 3150Sstevel@tonic-gate entry_type = USER_OBJ; 3160Sstevel@tonic-gate else 3170Sstevel@tonic-gate entry_type = USER; 3180Sstevel@tonic-gate } else if (strcmp(aclimport, "group") == 0) { 3190Sstevel@tonic-gate if (*(tp+1) == ':') 3200Sstevel@tonic-gate entry_type = GROUP_OBJ; 3210Sstevel@tonic-gate else 3220Sstevel@tonic-gate entry_type = GROUP; 3230Sstevel@tonic-gate } else if (strcmp(aclimport, "other") == 0) 3240Sstevel@tonic-gate entry_type = OTHER_OBJ; 3250Sstevel@tonic-gate else if (strcmp(aclimport, "mask") == 0) 3260Sstevel@tonic-gate entry_type = CLASS_OBJ; 3270Sstevel@tonic-gate else if (strcmp(aclimport, "defaultuser") == 0) { 3280Sstevel@tonic-gate if (*(tp+1) == ':') 3290Sstevel@tonic-gate entry_type = DEF_USER_OBJ; 3300Sstevel@tonic-gate else 3310Sstevel@tonic-gate entry_type = DEF_USER; 3320Sstevel@tonic-gate } else if (strcmp(aclimport, "defaultgroup") == 0) { 3330Sstevel@tonic-gate if (*(tp+1) == ':') 3340Sstevel@tonic-gate entry_type = DEF_GROUP_OBJ; 3350Sstevel@tonic-gate else 3360Sstevel@tonic-gate entry_type = DEF_GROUP; 3370Sstevel@tonic-gate } else if (strcmp(aclimport, "defaultmask") == 0) 3380Sstevel@tonic-gate entry_type = DEF_CLASS_OBJ; 3390Sstevel@tonic-gate else if (strcmp(aclimport, "defaultother") == 0) 3400Sstevel@tonic-gate entry_type = DEF_OTHER_OBJ; 3410Sstevel@tonic-gate else { 342*789Sahrens free(allocp); 343*789Sahrens acl_free(aclp); 344*789Sahrens return (EACL_ENTRY_ERROR); 3450Sstevel@tonic-gate } 3460Sstevel@tonic-gate 3470Sstevel@tonic-gate /* look for user/group name */ 3480Sstevel@tonic-gate if (entry_type != CLASS_OBJ && entry_type != OTHER_OBJ && 3490Sstevel@tonic-gate entry_type != DEF_CLASS_OBJ && 3500Sstevel@tonic-gate entry_type != DEF_OTHER_OBJ) { 3510Sstevel@tonic-gate fieldp = tp + 1; 3520Sstevel@tonic-gate tp = strchr(fieldp, ':'); 3530Sstevel@tonic-gate if (tp == NULL) { 354*789Sahrens free(allocp); 355*789Sahrens acl_free(aclp); 356*789Sahrens return (EACL_INVALID_USER_GROUP); 3570Sstevel@tonic-gate } else 3580Sstevel@tonic-gate *tp = '\0'; 3590Sstevel@tonic-gate if (fieldp != tp) { 3600Sstevel@tonic-gate /* 3610Sstevel@tonic-gate * The second field could be empty. We only care 3620Sstevel@tonic-gate * when the field has user/group name. 3630Sstevel@tonic-gate */ 3640Sstevel@tonic-gate if (entry_type == USER || 3650Sstevel@tonic-gate entry_type == DEF_USER) { 3660Sstevel@tonic-gate /* 3670Sstevel@tonic-gate * The reentrant interface getpwnam_r() 3680Sstevel@tonic-gate * is uncommitted and subject to 3690Sstevel@tonic-gate * change. Use the friendlier interface 3700Sstevel@tonic-gate * getpwnam(). 3710Sstevel@tonic-gate */ 372*789Sahrens error = 0; 3730Sstevel@tonic-gate passwdp = getpwnam(fieldp); 3740Sstevel@tonic-gate if (passwdp == NULL) { 375*789Sahrens error = acl_str_to_id(fieldp, 376*789Sahrens &id); 377*789Sahrens } else { 378*789Sahrens id = passwdp->pw_uid; 3790Sstevel@tonic-gate } 380*789Sahrens 381*789Sahrens if (error) { 382*789Sahrens free(allocp); 383*789Sahrens acl_free(aclp); 384*789Sahrens return (error); 385*789Sahrens } 386*789Sahrens 3870Sstevel@tonic-gate } else { 388*789Sahrens error = 0; 3890Sstevel@tonic-gate if (entry_type == GROUP || 3900Sstevel@tonic-gate entry_type == DEF_GROUP) { 3910Sstevel@tonic-gate groupp = getgrnam(fieldp); 3920Sstevel@tonic-gate if (groupp == NULL) { 393*789Sahrens error = acl_str_to_id( 394*789Sahrens fieldp, &id); 3950Sstevel@tonic-gate } 396*789Sahrens if (error == 0) 3970Sstevel@tonic-gate id = groupp->gr_gid; 398*789Sahrens } 399*789Sahrens if (error) { 400*789Sahrens free(allocp); 401*789Sahrens acl_free(aclp); 402*789Sahrens return (error); 4030Sstevel@tonic-gate } 4040Sstevel@tonic-gate } 4050Sstevel@tonic-gate } else { 4060Sstevel@tonic-gate /* 4070Sstevel@tonic-gate * The second field is empty. 4080Sstevel@tonic-gate * Treat it as undefined (-1) 4090Sstevel@tonic-gate */ 4100Sstevel@tonic-gate id = -1; 4110Sstevel@tonic-gate } 4120Sstevel@tonic-gate } else { 4130Sstevel@tonic-gate /* 4140Sstevel@tonic-gate * Let's not break the old applications 4150Sstevel@tonic-gate * that use mask::rwx, other::rwx format, 4160Sstevel@tonic-gate * though they violate the man pages. 4170Sstevel@tonic-gate */ 4180Sstevel@tonic-gate if (*(tp + 1) == ':') 4190Sstevel@tonic-gate *++tp = 0; 4200Sstevel@tonic-gate } 4210Sstevel@tonic-gate 4220Sstevel@tonic-gate /* next field: permission */ 4230Sstevel@tonic-gate fieldp = tp + 1; 4240Sstevel@tonic-gate if (strlen(fieldp) != 3) { 4250Sstevel@tonic-gate /* not "rwx" format */ 426*789Sahrens free(allocp); 427*789Sahrens acl_free(aclp); 428*789Sahrens return (EACL_PERM_MASK_ERROR); 4290Sstevel@tonic-gate } else { 4300Sstevel@tonic-gate char s[] = "rwx"; 4310Sstevel@tonic-gate int mask = 0x04; 4320Sstevel@tonic-gate int i; 4330Sstevel@tonic-gate perm = 0; 4340Sstevel@tonic-gate 4350Sstevel@tonic-gate for (i = 0; i < 3; i++, mask /= 2) { 4360Sstevel@tonic-gate if (fieldp[i] == s[i]) 4370Sstevel@tonic-gate perm |= mask; 4380Sstevel@tonic-gate else if (fieldp[i] != '-') { 439*789Sahrens free(allocp); 440*789Sahrens acl_free(aclp); 441*789Sahrens return (EACL_PERM_MASK_ERROR); 4420Sstevel@tonic-gate } 4430Sstevel@tonic-gate } 4440Sstevel@tonic-gate } 4450Sstevel@tonic-gate 4460Sstevel@tonic-gate tmpaclp->a_type = entry_type; 4470Sstevel@tonic-gate tmpaclp->a_id = id; 4480Sstevel@tonic-gate tmpaclp->a_perm = perm; 4490Sstevel@tonic-gate aclimport = nextp; 4500Sstevel@tonic-gate } 4510Sstevel@tonic-gate free(allocp); 452*789Sahrens *ret_aclp = aclp; 453*789Sahrens return (0); 4540Sstevel@tonic-gate } 4550Sstevel@tonic-gate 456*789Sahrens aclent_t * 457*789Sahrens aclfromtext(char *aclstr, int *aclcnt) 458*789Sahrens { 459*789Sahrens acl_t *aclp; 460*789Sahrens aclent_t *aclentp; 461*789Sahrens int error; 462*789Sahrens 463*789Sahrens error = aclent_aclfromtext(aclstr, &aclp); 464*789Sahrens if (error) 465*789Sahrens return (NULL); 466*789Sahrens 467*789Sahrens aclentp = aclp->acl_aclp; 468*789Sahrens aclp->acl_aclp = NULL; 469*789Sahrens acl_free(aclp); 470*789Sahrens 471*789Sahrens *aclcnt = aclp->acl_cnt; 472*789Sahrens return (aclentp); 473*789Sahrens } 474*789Sahrens 475*789Sahrens 4760Sstevel@tonic-gate static char * 4770Sstevel@tonic-gate strappend(char *where, char *newstr) 4780Sstevel@tonic-gate { 4790Sstevel@tonic-gate (void) strcat(where, newstr); 4800Sstevel@tonic-gate return (where + strlen(newstr)); 4810Sstevel@tonic-gate } 4820Sstevel@tonic-gate 4830Sstevel@tonic-gate static char * 4840Sstevel@tonic-gate convert_perm(char *where, o_mode_t perm) 4850Sstevel@tonic-gate { 4860Sstevel@tonic-gate if (perm & 04) 4870Sstevel@tonic-gate where = strappend(where, "r"); 4880Sstevel@tonic-gate else 4890Sstevel@tonic-gate where = strappend(where, "-"); 4900Sstevel@tonic-gate if (perm & 02) 4910Sstevel@tonic-gate where = strappend(where, "w"); 4920Sstevel@tonic-gate else 4930Sstevel@tonic-gate where = strappend(where, "-"); 4940Sstevel@tonic-gate if (perm & 01) 4950Sstevel@tonic-gate where = strappend(where, "x"); 4960Sstevel@tonic-gate else 4970Sstevel@tonic-gate where = strappend(where, "-"); 4980Sstevel@tonic-gate /* perm is the last field */ 4990Sstevel@tonic-gate return (where); 5000Sstevel@tonic-gate } 5010Sstevel@tonic-gate 502*789Sahrens static char * 503*789Sahrens ace_convert_perm(char *where, mode_t perm, int isdir, int iflags) 504*789Sahrens { 505*789Sahrens char *start = where; 506*789Sahrens 507*789Sahrens /* 508*789Sahrens * The following mneumonics all have the 509*789Sahrens * same value. The only difference is the 510*789Sahrens * first value is for files and second for directories 511*789Sahrens * ACE_READ_DATA/ACE_LIST_DIRECTORY 512*789Sahrens * ACE_WRITE_DATA/ACE_ADD_FILE 513*789Sahrens * ACE_APPEND_DATA/ACE_ADD_SUBDIRECTORY 514*789Sahrens */ 515*789Sahrens 516*789Sahrens /* 517*789Sahrens * If ACE is a directory, but inheritance indicates its 518*789Sahrens * for a file then print permissions for file rather than 519*789Sahrens * dir. 520*789Sahrens */ 521*789Sahrens if (isdir) { 522*789Sahrens if (perm & ACE_LIST_DIRECTORY) { 523*789Sahrens if (iflags == ACE_FILE_INHERIT_ACE) 524*789Sahrens where = strappend(where, "read_data/"); 525*789Sahrens else 526*789Sahrens where = strappend(where, 527*789Sahrens "list_directory/read_data/"); 528*789Sahrens } 529*789Sahrens if (perm & ACE_ADD_FILE) { 530*789Sahrens if (iflags == ACE_FILE_INHERIT_ACE) 531*789Sahrens where = strappend(where, "write_data/"); 532*789Sahrens else 533*789Sahrens where = strappend(where, 534*789Sahrens "add_file/write_data/"); 535*789Sahrens } 536*789Sahrens if (perm & ACE_ADD_SUBDIRECTORY) { 537*789Sahrens if (iflags == ACE_FILE_INHERIT_ACE) 538*789Sahrens where = strappend(where, "append_data/"); 539*789Sahrens else 540*789Sahrens where = strappend(where, 541*789Sahrens "add_subdirectory/append_data/"); 542*789Sahrens } 543*789Sahrens } else { 544*789Sahrens if (perm & ACE_READ_DATA) 545*789Sahrens where = strappend(where, "read_data/"); 546*789Sahrens if (perm & ACE_WRITE_DATA) 547*789Sahrens where = strappend(where, "write_data/"); 548*789Sahrens if (perm & ACE_APPEND_DATA) 549*789Sahrens where = strappend(where, "append_data/"); 550*789Sahrens } 551*789Sahrens if (perm & ACE_READ_NAMED_ATTRS) 552*789Sahrens where = strappend(where, "read_xattr/"); 553*789Sahrens if (perm & ACE_WRITE_NAMED_ATTRS) 554*789Sahrens where = strappend(where, "write_xattr/"); 555*789Sahrens if (perm & ACE_EXECUTE) 556*789Sahrens where = strappend(where, "execute/"); 557*789Sahrens if (perm & ACE_DELETE_CHILD) 558*789Sahrens where = strappend(where, "delete_child/"); 559*789Sahrens if (perm & ACE_READ_ATTRIBUTES) 560*789Sahrens where = strappend(where, "read_attributes/"); 561*789Sahrens if (perm & ACE_WRITE_ATTRIBUTES) 562*789Sahrens where = strappend(where, "write_attributes/"); 563*789Sahrens if (perm & ACE_DELETE) 564*789Sahrens where = strappend(where, "delete/"); 565*789Sahrens if (perm & ACE_READ_ACL) 566*789Sahrens where = strappend(where, "read_acl/"); 567*789Sahrens if (perm & ACE_WRITE_ACL) 568*789Sahrens where = strappend(where, "write_acl/"); 569*789Sahrens if (perm & ACE_WRITE_OWNER) 570*789Sahrens where = strappend(where, "write_owner/"); 571*789Sahrens if (perm & ACE_SYNCHRONIZE) 572*789Sahrens where = strappend(where, "synchronize"); 573*789Sahrens 574*789Sahrens if (start[strlen(start) - 1] == '/') { 575*789Sahrens start[strlen(start) - 1] = '\0'; 576*789Sahrens where = start + strlen(start); 577*789Sahrens } 578*789Sahrens return (where); 579*789Sahrens } 580*789Sahrens 581*789Sahrens int 582*789Sahrens ace_permask(char *perm_tok, int *perm) 583*789Sahrens { 584*789Sahrens if (strcmp(perm_tok, "read_data") == 0) 585*789Sahrens *perm |= ACE_READ_DATA; 586*789Sahrens else if (strcmp(perm_tok, "list_directory") == 0) 587*789Sahrens *perm |= ACE_LIST_DIRECTORY; 588*789Sahrens else if (strcmp(perm_tok, "write_data") == 0) 589*789Sahrens *perm |= ACE_WRITE_DATA; 590*789Sahrens else if (strcmp(perm_tok, "add_file") == 0) 591*789Sahrens *perm |= ACE_ADD_FILE; 592*789Sahrens else if (strcmp(perm_tok, "append_data") == 0) 593*789Sahrens *perm |= ACE_APPEND_DATA; 594*789Sahrens else if (strcmp(perm_tok, "add_subdirectory") == 0) 595*789Sahrens *perm |= ACE_ADD_SUBDIRECTORY; 596*789Sahrens else if (strcmp(perm_tok, "read_xattr") == 0) 597*789Sahrens *perm |= ACE_READ_NAMED_ATTRS; 598*789Sahrens else if (strcmp(perm_tok, "write_xattr") == 0) 599*789Sahrens *perm |= ACE_WRITE_NAMED_ATTRS; 600*789Sahrens else if (strcmp(perm_tok, "execute") == 0) 601*789Sahrens *perm |= ACE_EXECUTE; 602*789Sahrens else if (strcmp(perm_tok, "delete_child") == 0) 603*789Sahrens *perm |= ACE_DELETE_CHILD; 604*789Sahrens else if (strcmp(perm_tok, "read_attributes") == 0) 605*789Sahrens *perm |= ACE_READ_ATTRIBUTES; 606*789Sahrens else if (strcmp(perm_tok, "write_attributes") == 0) 607*789Sahrens *perm |= ACE_WRITE_ATTRIBUTES; 608*789Sahrens else if (strcmp(perm_tok, "delete") == 0) 609*789Sahrens *perm |= ACE_DELETE; 610*789Sahrens else if (strcmp(perm_tok, "read_acl") == 0) 611*789Sahrens *perm |= ACE_READ_ACL; 612*789Sahrens else if (strcmp(perm_tok, "write_acl") == 0) 613*789Sahrens *perm |= ACE_WRITE_ACL; 614*789Sahrens else if (strcmp(perm_tok, "write_owner") == 0) 615*789Sahrens *perm |= ACE_WRITE_OWNER; 616*789Sahrens else if (strcmp(perm_tok, "synchronize") == 0) 617*789Sahrens *perm |= ACE_SYNCHRONIZE; 618*789Sahrens else { 619*789Sahrens return (1); 620*789Sahrens } 621*789Sahrens 622*789Sahrens return (0); 623*789Sahrens } 624*789Sahrens 6250Sstevel@tonic-gate /* 6260Sstevel@tonic-gate * Callers should check the return code as this routine may change the string 6270Sstevel@tonic-gate * pointer in dynaclstr. 6280Sstevel@tonic-gate */ 6290Sstevel@tonic-gate static int 6300Sstevel@tonic-gate increase_length(struct dynaclstr *dacl, size_t increase) 6310Sstevel@tonic-gate { 6320Sstevel@tonic-gate char *tptr; 6330Sstevel@tonic-gate size_t newsize; 6340Sstevel@tonic-gate 6350Sstevel@tonic-gate newsize = dacl->bufsize + increase; 6360Sstevel@tonic-gate tptr = realloc(dacl->aclexport, newsize); 6370Sstevel@tonic-gate if (tptr != NULL) { 6380Sstevel@tonic-gate dacl->aclexport = tptr; 6390Sstevel@tonic-gate dacl->bufsize = newsize; 6400Sstevel@tonic-gate return (1); 6410Sstevel@tonic-gate } else 6420Sstevel@tonic-gate return (0); 6430Sstevel@tonic-gate } 644*789Sahrens 645*789Sahrens /* 646*789Sahrens * ace_acltotext() conver each ace formatted acl to look like this: 647*789Sahrens * 648*789Sahrens * entry_type:uid^gid^name:perms:allow^deny[:flags][,] 649*789Sahrens * 650*789Sahrens * The maximum length of entry_type is 5 ("group") 651*789Sahrens * 652*789Sahrens * The max length of a uid^gid^name entry (in theory) is 8, hence we use 653*789Sahrens * LOGNAME_MAX. 654*789Sahrens * 655*789Sahrens * The length of a perms entry is 144 i.e read_data/write_data... 656*789Sahrens * to each acl entry. 657*789Sahrens * 658*789Sahrens * iflags: file_inherit/dir_inherit/inherit_only/no_propagate 659*789Sahrens * 660*789Sahrens */ 661*789Sahrens 662*789Sahrens #define ACE_ENTRYTYPLEN 6 663*789Sahrens #define IFLAGS_SIZE 51 664*789Sahrens #define ACCESS_TYPE_SIZE 5 665*789Sahrens #define COLON_CNT 3 666*789Sahrens #define PERMS_LEN 216 667*789Sahrens #define ACE_ENTRY_SIZE (ACE_ENTRYTYPLEN + LOGNAME_MAX + PERMS_LEN +\ 668*789Sahrens ACCESS_TYPE_SIZE + IFLAGS_SIZE + COLON_CNT) 669*789Sahrens 670*789Sahrens static char * 671*789Sahrens ace_acltotext(acl_t *aceaclp) 672*789Sahrens { 673*789Sahrens ace_t *aclp = aceaclp->acl_aclp; 674*789Sahrens int aclcnt = aceaclp->acl_cnt; 675*789Sahrens char *aclexport; 676*789Sahrens char *where; 677*789Sahrens char *start; 678*789Sahrens struct group *groupp; 679*789Sahrens struct passwd *passwdp; 680*789Sahrens struct dynaclstr *dstr; 681*789Sahrens int i, rtn; 682*789Sahrens int isdir = (aceaclp->acl_flags & ACL_IS_DIR); 683*789Sahrens size_t excess = 0; 684*789Sahrens 685*789Sahrens if (aclp == NULL) 686*789Sahrens return (NULL); 687*789Sahrens if ((dstr = malloc(sizeof (struct dynaclstr))) == NULL) 688*789Sahrens return (NULL); 689*789Sahrens dstr->bufsize = aclcnt * ACE_ENTRY_SIZE; 690*789Sahrens if ((dstr->aclexport = malloc(dstr->bufsize)) == NULL) 691*789Sahrens return (NULL); 692*789Sahrens *dstr->aclexport = '\0'; 693*789Sahrens where = dstr->aclexport; 694*789Sahrens 695*789Sahrens for (i = 0; i < aclcnt; i++, aclp++) { 696*789Sahrens switch (aclp->a_flags & 0xf040) { 697*789Sahrens case ACE_OWNER: 698*789Sahrens case 0: 699*789Sahrens if ((aclp->a_flags & 0xf040) == ACE_OWNER) 700*789Sahrens where = strappend(where, "owner@"); 701*789Sahrens else 702*789Sahrens where = strappend(where, "user:"); 703*789Sahrens if ((aclp->a_flags & 0xf040) == 0) { 704*789Sahrens passwdp = getpwuid(aclp->a_who); 705*789Sahrens if (passwdp == (struct passwd *)NULL) { 706*789Sahrens /* put in uid instead */ 707*789Sahrens (void) sprintf(where, "%d", 708*789Sahrens aclp->a_who); 709*789Sahrens } else { 710*789Sahrens excess = strlen(passwdp->pw_name) - 711*789Sahrens LOGNAME_MAX; 712*789Sahrens if (excess > 0) { 713*789Sahrens rtn = increase_length(dstr, 714*789Sahrens excess); 715*789Sahrens if (rtn == 1) 716*789Sahrens /* reset where */ 717*789Sahrens where = 718*789Sahrens dstr->aclexport + 719*789Sahrens strlen( 720*789Sahrens dstr->aclexport); 721*789Sahrens else 722*789Sahrens return (NULL); 723*789Sahrens } 724*789Sahrens where = strappend(where, 725*789Sahrens passwdp->pw_name); 726*789Sahrens } 727*789Sahrens } else { 728*789Sahrens where = strappend(where, ""); 729*789Sahrens } 730*789Sahrens where = strappend(where, ":"); 731*789Sahrens break; 732*789Sahrens case ACE_GROUP|ACE_IDENTIFIER_GROUP: 733*789Sahrens case ACE_IDENTIFIER_GROUP: 734*789Sahrens if ((aclp->a_flags & 0xf040) == 735*789Sahrens (ACE_GROUP | ACE_IDENTIFIER_GROUP)) 736*789Sahrens where = strappend(where, "group@"); 737*789Sahrens else 738*789Sahrens where = strappend(where, "group:"); 739*789Sahrens if (!(aclp->a_flags & ACE_GROUP)) { 740*789Sahrens groupp = getgrgid(aclp->a_who); 741*789Sahrens if (groupp == (struct group *)NULL) { 742*789Sahrens /* put in gid instead */ 743*789Sahrens (void) sprintf(where, 744*789Sahrens "%d", aclp->a_who); 745*789Sahrens } else { 746*789Sahrens excess = strlen(groupp->gr_name) - 747*789Sahrens LOGNAME_MAX; 748*789Sahrens if (excess > 0) { 749*789Sahrens rtn = increase_length(dstr, 750*789Sahrens excess); 751*789Sahrens if (rtn == 1) 752*789Sahrens /* reset where */ 753*789Sahrens where = 754*789Sahrens dstr->aclexport + 755*789Sahrens strlen( 756*789Sahrens dstr->aclexport); 757*789Sahrens else 758*789Sahrens return (NULL); 759*789Sahrens } 760*789Sahrens where = strappend(where, 761*789Sahrens groupp->gr_name); 762*789Sahrens } 763*789Sahrens } else { 764*789Sahrens where = strappend(where, ""); 765*789Sahrens } 766*789Sahrens where = strappend(where, ":"); 767*789Sahrens break; 768*789Sahrens case ACE_EVERYONE: 769*789Sahrens where = strappend(where, "everyone@:"); 770*789Sahrens break; 771*789Sahrens default: 772*789Sahrens free(dstr->aclexport); 773*789Sahrens free(dstr); 774*789Sahrens return (NULL); 775*789Sahrens 776*789Sahrens } 777*789Sahrens where = ace_convert_perm(where, aclp->a_access_mask, 778*789Sahrens isdir, (aclp->a_flags & 779*789Sahrens (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE))); 780*789Sahrens where = strappend(where, 781*789Sahrens (aclp->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) ? 782*789Sahrens ":allow" : ":deny"); 783*789Sahrens 784*789Sahrens /* 785*789Sahrens * slap on inheritance flags if we have any 786*789Sahrens */ 787*789Sahrens 788*789Sahrens if (aclp->a_flags & 0xf) { 789*789Sahrens where = strappend(where, ":"); 790*789Sahrens start = where; 791*789Sahrens if (aclp->a_flags & ACE_FILE_INHERIT_ACE) 792*789Sahrens where = strappend(where, "file_inherit/"); 793*789Sahrens if (aclp->a_flags & ACE_DIRECTORY_INHERIT_ACE) 794*789Sahrens where = strappend(where, "dir_inherit/"); 795*789Sahrens if (aclp->a_flags & ACE_NO_PROPAGATE_INHERIT_ACE) 796*789Sahrens where = strappend(where, "no_propagate/"); 797*789Sahrens if (aclp->a_flags & ACE_INHERIT_ONLY_ACE) 798*789Sahrens where = strappend(where, "inherit_only"); 799*789Sahrens 800*789Sahrens /* 801*789Sahrens * chop off trailing slash, if present 802*789Sahrens */ 803*789Sahrens if (start[strlen(start) - 1] == '/') { 804*789Sahrens start[strlen(start) - 1] = '\0'; 805*789Sahrens where = start + strlen(start); 806*789Sahrens } 807*789Sahrens } 808*789Sahrens if (i < aclcnt - 1) 809*789Sahrens where = strappend(where, ","); 810*789Sahrens } 811*789Sahrens aclexport = dstr->aclexport; 812*789Sahrens free(dstr); 813*789Sahrens return (aclexport); 814*789Sahrens } 815*789Sahrens 816*789Sahrens static int 817*789Sahrens build_iflags(char *str, int *iflags) 818*789Sahrens { 819*789Sahrens 820*789Sahrens char *tok; 821*789Sahrens *iflags = 0; 822*789Sahrens 823*789Sahrens tok = strtok(str, "/"); 824*789Sahrens 825*789Sahrens if (tok == NULL) 826*789Sahrens return (1); 827*789Sahrens 828*789Sahrens do { 829*789Sahrens if (strcmp(tok, "file_inherit") == 0) 830*789Sahrens *iflags |= ACE_FILE_INHERIT_ACE; 831*789Sahrens else if (strcmp(tok, "dir_inherit") == 0) 832*789Sahrens *iflags |= ACE_DIRECTORY_INHERIT_ACE; 833*789Sahrens else if (strcmp(tok, "inherit_only") == 0) 834*789Sahrens *iflags |= ACE_INHERIT_ONLY_ACE; 835*789Sahrens else if (strcmp(tok, "no_propagate") == 0) 836*789Sahrens *iflags |= ACE_NO_PROPAGATE_INHERIT_ACE; 837*789Sahrens else 838*789Sahrens return (1); 839*789Sahrens } while (tok = strtok(NULL, "/")); 840*789Sahrens return (0); 841*789Sahrens } 842*789Sahrens 843*789Sahrens /* 844*789Sahrens * Convert external acl representation to internal representation. 845*789Sahrens * The accepted syntax is: <acl_entry>[,<acl_entry>]*[,] 846*789Sahrens * The comma at the end is not prescribed by the man pages. 847*789Sahrens * But it is needed not to break the old programs. 848*789Sahrens */ 849*789Sahrens 850*789Sahrens int 851*789Sahrens ace_aclfromtext(char *aclstr, acl_t **ret_aclp) 852*789Sahrens { 853*789Sahrens char *fieldp; 854*789Sahrens char *tp; 855*789Sahrens char *nextp; 856*789Sahrens char *allocp; 857*789Sahrens char *aclimport; 858*789Sahrens char *str; 859*789Sahrens char *perm_tok; 860*789Sahrens int entry_type; 861*789Sahrens int id; 862*789Sahrens int type; 863*789Sahrens int iflags; 864*789Sahrens int len; 865*789Sahrens int error; 866*789Sahrens int32_t perm; 867*789Sahrens ace_t *tmpaclp; 868*789Sahrens acl_t *aclp; 869*789Sahrens struct group *groupp; 870*789Sahrens struct passwd *passwdp; 871*789Sahrens 872*789Sahrens if (! aclstr) 873*789Sahrens return (EACL_INVALID_STR); 874*789Sahrens 875*789Sahrens len = strlen(aclstr); 876*789Sahrens 877*789Sahrens aclp = acl_alloc(ACE_T); 878*789Sahrens if (aclp == NULL) { 879*789Sahrens return (EACL_MEM_ERROR); 880*789Sahrens } 881*789Sahrens 882*789Sahrens *ret_aclp = NULL; 883*789Sahrens 884*789Sahrens if ((aclimport = allocp = strdup(aclstr)) == NULL) { 885*789Sahrens return (EACL_MEM_ERROR); 886*789Sahrens } 887*789Sahrens 888*789Sahrens 889*789Sahrens if (aclimport[len - 1] == ',') 890*789Sahrens aclimport[len - 1] = '\0'; 891*789Sahrens 892*789Sahrens for (; aclimport; ) { 893*789Sahrens /* look for an ACL entry */ 894*789Sahrens tp = strchr(aclimport, ','); 895*789Sahrens if (tp == NULL) { 896*789Sahrens nextp = NULL; 897*789Sahrens } else { 898*789Sahrens *tp = '\0'; 899*789Sahrens nextp = tp + 1; 900*789Sahrens } 901*789Sahrens 902*789Sahrens aclp->acl_cnt += 1; 903*789Sahrens 904*789Sahrens /* 905*789Sahrens * get additional memory: 906*789Sahrens * can be more efficient by allocating a bigger block 907*789Sahrens * each time. 908*789Sahrens */ 909*789Sahrens if (aclp->acl_cnt > 1) 910*789Sahrens tmpaclp = (ace_t *)realloc(aclp->acl_aclp, 911*789Sahrens sizeof (ace_t) * (aclp->acl_cnt)); 912*789Sahrens else 913*789Sahrens tmpaclp = (ace_t *)malloc(sizeof (ace_t)); 914*789Sahrens if (tmpaclp == NULL) { 915*789Sahrens free(allocp); 916*789Sahrens acl_free(aclp); 917*789Sahrens return (EACL_MEM_ERROR); 918*789Sahrens } 919*789Sahrens aclp->acl_aclp = tmpaclp; 920*789Sahrens tmpaclp = (ace_t *)aclp->acl_aclp + (aclp->acl_cnt - 1); 921*789Sahrens 922*789Sahrens /* look for entry type field */ 923*789Sahrens tp = strchr(aclimport, ':'); 924*789Sahrens if (tp == NULL) { 925*789Sahrens free(allocp); 926*789Sahrens acl_free(aclp); 927*789Sahrens return (EACL_ENTRY_ERROR); 928*789Sahrens } else 929*789Sahrens *tp = '\0'; 930*789Sahrens if (strcmp(aclimport, "owner@") == 0) { 931*789Sahrens entry_type = ACE_OWNER; 932*789Sahrens } else if (strcmp(aclimport, "group@") == 0) { 933*789Sahrens entry_type = ACE_GROUP | ACE_IDENTIFIER_GROUP; 934*789Sahrens } else if (strcmp(aclimport, "everyone@") == 0) { 935*789Sahrens entry_type = ACE_EVERYONE; 936*789Sahrens } else if (strcmp(aclimport, "group") == 0) { 937*789Sahrens entry_type = ACE_IDENTIFIER_GROUP; 938*789Sahrens } else if (strcmp(aclimport, "user") == 0) { 939*789Sahrens entry_type = 0; 940*789Sahrens } else { 941*789Sahrens free(allocp); 942*789Sahrens acl_free(aclp); 943*789Sahrens return (EACL_ENTRY_ERROR); 944*789Sahrens } 945*789Sahrens 946*789Sahrens /* 947*789Sahrens * If not an abstraction owner@, group@ or everyone@ 948*789Sahrens * then we must have a user/group name next 949*789Sahrens */ 950*789Sahrens 951*789Sahrens if (entry_type == 0 || entry_type == ACE_IDENTIFIER_GROUP) { 952*789Sahrens fieldp = tp + 1; 953*789Sahrens tp = strchr(fieldp, ':'); 954*789Sahrens if (tp == NULL) { 955*789Sahrens free(allocp); 956*789Sahrens acl_free(aclp); 957*789Sahrens return (EACL_INVALID_USER_GROUP); 958*789Sahrens } else 959*789Sahrens *tp = '\0'; 960*789Sahrens if (fieldp != tp) { 961*789Sahrens /* 962*789Sahrens * The second field could be empty. We only care 963*789Sahrens * when the field has user/group name. 964*789Sahrens */ 965*789Sahrens if (entry_type == 0) { 966*789Sahrens /* 967*789Sahrens * The reentrant interface getpwnam_r() 968*789Sahrens * is uncommitted and subject to 969*789Sahrens * change. Use the friendlier interface 970*789Sahrens * getpwnam(). 971*789Sahrens */ 972*789Sahrens error = 0; 973*789Sahrens passwdp = getpwnam(fieldp); 974*789Sahrens if (passwdp == NULL) { 975*789Sahrens error = acl_str_to_id( 976*789Sahrens fieldp, &id); 977*789Sahrens } else { 978*789Sahrens id = passwdp->pw_uid; 979*789Sahrens } 980*789Sahrens 981*789Sahrens if (error) { 982*789Sahrens free(allocp); 983*789Sahrens acl_free(aclp); 984*789Sahrens return (error); 985*789Sahrens } 986*789Sahrens } else { 987*789Sahrens error = 0; 988*789Sahrens if (entry_type == 989*789Sahrens ACE_IDENTIFIER_GROUP) { 990*789Sahrens groupp = getgrnam(fieldp); 991*789Sahrens if (groupp == NULL) { 992*789Sahrens /* no group? */ 993*789Sahrens error = acl_str_to_id( 994*789Sahrens fieldp, &id); 995*789Sahrens } else 996*789Sahrens id = groupp->gr_gid; 997*789Sahrens 998*789Sahrens } else if ((entry_type == ACE_OWNER) || 999*789Sahrens (entry_type == 1000*789Sahrens (ACE_IDENTIFIER_GROUP|ACE_GROUP)) || 1001*789Sahrens (entry_type != ACE_EVERYONE)) { 1002*789Sahrens error = EACL_FIELD_NOT_BLANK; 1003*789Sahrens } else { 1004*789Sahrens error = EACL_ENTRY_ERROR; 1005*789Sahrens } 1006*789Sahrens 1007*789Sahrens if (error) { 1008*789Sahrens free(allocp); 1009*789Sahrens acl_free(aclp); 1010*789Sahrens return (error); 1011*789Sahrens } 1012*789Sahrens } 1013*789Sahrens } 1014*789Sahrens } else { 1015*789Sahrens id = -1; 1016*789Sahrens } 1017*789Sahrens 1018*789Sahrens /* next field: permission */ 1019*789Sahrens fieldp = tp + 1; 1020*789Sahrens tp = strchr(fieldp, ':'); 1021*789Sahrens if (tp == NULL) { 1022*789Sahrens free(allocp); 1023*789Sahrens acl_free(aclp); 1024*789Sahrens return (EACL_PERM_MASK_ERROR); 1025*789Sahrens } else 1026*789Sahrens *tp = '\0'; 1027*789Sahrens 1028*789Sahrens perm = 0; 1029*789Sahrens 1030*789Sahrens perm_tok = strtok(fieldp, "/"); 1031*789Sahrens if (perm_tok == NULL) { 1032*789Sahrens perm = 0; 1033*789Sahrens } else { 1034*789Sahrens do { 1035*789Sahrens if (ace_permask(perm_tok, &perm) != 0) { 1036*789Sahrens free(allocp); 1037*789Sahrens acl_free(aclp); 1038*789Sahrens return (EACL_PERM_MASK_ERROR); 1039*789Sahrens } 1040*789Sahrens } while (perm_tok = strtok(NULL, "/")); 1041*789Sahrens } 1042*789Sahrens 1043*789Sahrens /* grab allow/deny */ 1044*789Sahrens fieldp = tp + 1; 1045*789Sahrens tp = strchr(fieldp, ':'); 1046*789Sahrens if (tp != NULL) 1047*789Sahrens *tp = '\0'; 1048*789Sahrens 1049*789Sahrens if (strcmp(fieldp, "allow") == 0) 1050*789Sahrens type = ACE_ACCESS_ALLOWED_ACE_TYPE; 1051*789Sahrens else if (strcmp(fieldp, "deny") == 0) 1052*789Sahrens type = ACE_ACCESS_DENIED_ACE_TYPE; 1053*789Sahrens else { 1054*789Sahrens free(allocp); 1055*789Sahrens acl_free(aclp); 1056*789Sahrens return (EACL_INVALID_ACCESS_TYPE); 1057*789Sahrens } 1058*789Sahrens 1059*789Sahrens /* grab option inherit flags */ 1060*789Sahrens 1061*789Sahrens iflags = 0; 1062*789Sahrens if (tp != NULL) { 1063*789Sahrens fieldp = tp + 1; 1064*789Sahrens if (fieldp != NULL) { 1065*789Sahrens *tp = '\0'; 1066*789Sahrens str = fieldp; 1067*789Sahrens if (build_iflags(str, &iflags) != 0) { 1068*789Sahrens free(allocp); 1069*789Sahrens acl_free(aclp); 1070*789Sahrens return (EACL_INHERIT_ERROR); 1071*789Sahrens } 1072*789Sahrens } else { 1073*789Sahrens free(allocp); 1074*789Sahrens acl_free(aclp); 1075*789Sahrens return (EACL_UNKNOWN_DATA); 1076*789Sahrens } 1077*789Sahrens } 1078*789Sahrens /* slap fields into ace_t structure */ 1079*789Sahrens 1080*789Sahrens tmpaclp->a_flags = entry_type; 1081*789Sahrens tmpaclp->a_flags |= iflags; 1082*789Sahrens tmpaclp->a_who = id; 1083*789Sahrens tmpaclp->a_access_mask = perm; 1084*789Sahrens tmpaclp->a_type = type; 1085*789Sahrens aclimport = nextp; 1086*789Sahrens } 1087*789Sahrens free(allocp); 1088*789Sahrens *ret_aclp = aclp; 1089*789Sahrens return (0); 1090*789Sahrens } 1091*789Sahrens 1092*789Sahrens char 1093*789Sahrens *acl_totext(acl_t *aclp) 1094*789Sahrens { 1095*789Sahrens if (aclp == NULL) 1096*789Sahrens return (NULL); 1097*789Sahrens 1098*789Sahrens switch (aclp->acl_type) { 1099*789Sahrens case ACE_T: 1100*789Sahrens return (ace_acltotext(aclp)); 1101*789Sahrens case ACLENT_T: 1102*789Sahrens return (acltotext(aclp->acl_aclp, aclp->acl_cnt)); 1103*789Sahrens } 1104*789Sahrens return (NULL); 1105*789Sahrens } 1106*789Sahrens 1107*789Sahrens int 1108*789Sahrens acl_fromtext(const char *acltextp, acl_t **ret_aclp) 1109*789Sahrens { 1110*789Sahrens acl_t *aclp; 1111*789Sahrens char *token; 1112*789Sahrens char *ptr; 1113*789Sahrens char *textp; 1114*789Sahrens enum acl_type flavor; 1115*789Sahrens int colon_cnt = 0; 1116*789Sahrens int error; 1117*789Sahrens 1118*789Sahrens /* 1119*789Sahrens * first try and detect what type of acl entries we have 1120*789Sahrens * 1121*789Sahrens * aclent_t can have 1, 2 or 3 colons 1122*789Sahrens * if 3 then must have word default: 1123*789Sahrens * 1124*789Sahrens * ace_t can have 2, 3 or 4 1125*789Sahrens * for 2 then must be owner@, group@ or everyone@ 1126*789Sahrens */ 1127*789Sahrens 1128*789Sahrens textp = strdup(acltextp); 1129*789Sahrens if (textp == NULL) 1130*789Sahrens return (-1); 1131*789Sahrens 1132*789Sahrens token = strtok(textp, ","); 1133*789Sahrens if (token == NULL) { 1134*789Sahrens free(textp); 1135*789Sahrens return (-1); 1136*789Sahrens } 1137*789Sahrens 1138*789Sahrens for (ptr = token; *ptr; ptr++) { 1139*789Sahrens if (*ptr == ':') 1140*789Sahrens colon_cnt++; 1141*789Sahrens } 1142*789Sahrens 1143*789Sahrens if (colon_cnt == 1 || colon_cnt == 2) { 1144*789Sahrens if ((strncmp(acltextp, "owner@", 6) == 0) || 1145*789Sahrens (strncmp(acltextp, "group@", 6) == 0) || 1146*789Sahrens (strncmp(acltextp, "everyone@", 9) == 0)) 1147*789Sahrens flavor = ACE_T; 1148*789Sahrens else 1149*789Sahrens flavor = ACLENT_T; 1150*789Sahrens } else if (colon_cnt == 3) { 1151*789Sahrens ptr = strtok(token, ":"); 1152*789Sahrens if (ptr == NULL) { 1153*789Sahrens free(textp); 1154*789Sahrens return (EACL_MISSING_FIELDS); 1155*789Sahrens } else if (strcmp(ptr, "default") == 0) { 1156*789Sahrens flavor = ACLENT_T; 1157*789Sahrens } else { 1158*789Sahrens flavor = ACE_T; 1159*789Sahrens } 1160*789Sahrens } else if (colon_cnt == 4) { 1161*789Sahrens flavor = ACE_T; 1162*789Sahrens } else { 1163*789Sahrens free(textp); 1164*789Sahrens return (EACL_MISSING_FIELDS); 1165*789Sahrens } 1166*789Sahrens 1167*789Sahrens 1168*789Sahrens free(textp); 1169*789Sahrens 1170*789Sahrens if (flavor == ACLENT_T) 1171*789Sahrens error = aclent_aclfromtext((char *)acltextp, &aclp); 1172*789Sahrens else 1173*789Sahrens error = ace_aclfromtext((char *)acltextp, &aclp); 1174*789Sahrens 1175*789Sahrens *ret_aclp = aclp; 1176*789Sahrens return (error); 1177*789Sahrens } 1178