acltext.c revision 11e3217022ca85e61c9af16135a16592fe10dc6b
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*LINTLIBRARY*/
#include <grp.h>
#include <pwd.h>
#include <string.h>
#include <limits.h>
#include <stdlib.h>
#include <errno.h>
#include <aclutils.h>
#include <libintl.h>
/*
* acltotext() converts each ACL entry to look like this:
*
* entry_type:uid^gid^name:perms
*
* The maximum length of entry_type is 14 ("defaultgroup::" and
* "defaultother::") hence ENTRYTYPELEN is set to 14.
*
* The max length of a uid^gid^name entry (in theory) is 8, hence we use
* LOGNAME_MAX.
*
* The length of a perms entry is 4 to allow for the comma appended to each
* to each acl entry. Hence PERMS is set to 4.
*/
#define ENTRYTYPELEN 14
#define PERMS 4
struct dynaclstr {
char *aclexport;
};
static char *strappend(char *, char *);
static char *convert_perm(char *, o_mode_t);
static int
{
char *end;
return (EACL_INVALID_USER_GROUP);
return (0);
}
/*
* Convert internal acl representation to external representation.
*
* The length of a non-owning user name or non-owning group name ie entries
* of type DEF_USER, USER, DEF_GROUP or GROUP, can exceed LOGNAME_MAX. We
* thus check the length of these entries, and if greater than LOGNAME_MAX,
* we realloc() via increase_length().
*
* The LOGNAME_MAX, ENTRYTYPELEN and PERMS limits are otherwise always
* adhered to.
*/
char *
{
char *aclexport;
char *where;
int i, rtn;
return (NULL);
return (NULL);
return (NULL);
}
case DEF_USER_OBJ:
case USER_OBJ:
else
break;
case DEF_USER:
case USER:
else
/* put in uid instead */
} else {
if (excess > 0) {
if (rtn == 1) {
} else {
return (NULL);
}
}
}
break;
case DEF_GROUP_OBJ:
case GROUP_OBJ:
else
break;
case DEF_GROUP:
case GROUP:
else
/* put in gid instead */
} else {
if (excess > 0) {
if (rtn == 1) {
} else {
return (NULL);
}
}
}
break;
case DEF_CLASS_OBJ:
case CLASS_OBJ:
else
break;
case DEF_OTHER_OBJ:
case OTHER_OBJ:
else
break;
default:
return (NULL);
}
if (i < aclcnt - 1)
}
return (aclexport);
}
/*
* Convert external acl representation to internal representation.
* The accepted syntax is: <acl_entry>[,<acl_entry>]*[,]
* The comma at the end is not prescribed by the man pages.
* But it is needed not to break the old programs.
*/
static int
{
char *fieldp;
char *tp;
char *nextp;
char *allocp;
char *aclimport;
int entry_type;
int id;
int len;
int error;
if (! aclstr)
return (NULL);
return (EACL_MEM_ERROR);
}
return (EACL_MEM_ERROR);
}
for (; aclimport; ) {
/* look for an ACL entry */
} else {
*tp = '\0';
}
/*
* get additional memory:
* can be more efficient by allocating a bigger block
* each time.
*/
else
return (EACL_MEM_ERROR);
}
/* look for entry type field */
if (aclp)
return (EACL_ENTRY_ERROR);
} else
*tp = '\0';
else
entry_type = USER;
else
entry_type = GROUP;
else
else
else {
return (EACL_ENTRY_ERROR);
}
entry_type != DEF_CLASS_OBJ &&
entry_type != DEF_OTHER_OBJ) {
return (EACL_INVALID_USER_GROUP);
} else
*tp = '\0';
/*
* The second field could be empty. We only care
*/
if (entry_type == USER ||
entry_type == DEF_USER) {
/*
* The reentrant interface getpwnam_r()
* is uncommitted and subject to
* change. Use the friendlier interface
* getpwnam().
*/
error = 0;
&id);
} else {
}
if (error) {
return (error);
}
} else {
error = 0;
if (entry_type == GROUP ||
entry_type == DEF_GROUP) {
}
if (error == 0)
}
if (error) {
return (error);
}
}
} else {
/*
* The second field is empty.
* Treat it as undefined (-1)
*/
id = -1;
}
} else {
/*
* Let's not break the old applications
* that use mask::rwx, other::rwx format,
* though they violate the man pages.
*/
*++tp = 0;
}
/* next field: permission */
/* not "rwx" format */
return (EACL_PERM_MASK_ERROR);
} else {
char s[] = "rwx";
int mask = 0x04;
int i;
perm = 0;
if (fieldp[i] == s[i])
else if (fieldp[i] != '-') {
return (EACL_PERM_MASK_ERROR);
}
}
}
}
return (0);
}
aclent_t *
{
int error;
if (error)
return (NULL);
return (aclentp);
}
static char *
{
}
static char *
{
if (perm & 04)
else
if (perm & 02)
else
if (perm & 01)
else
/* perm is the last field */
return (where);
}
static char *
{
/*
* The following mneumonics all have the
* same value. The only difference is the
* first value is for files and second for directories
*/
/*
* If ACE is a directory, but inheritance indicates its
* for a file then print permissions for file rather than
* dir.
*/
if (isdir) {
if (perm & ACE_LIST_DIRECTORY) {
if (iflags == ACE_FILE_INHERIT_ACE)
else
"list_directory/read_data/");
}
if (perm & ACE_ADD_FILE) {
if (iflags == ACE_FILE_INHERIT_ACE)
else
"add_file/write_data/");
}
if (perm & ACE_ADD_SUBDIRECTORY) {
if (iflags == ACE_FILE_INHERIT_ACE)
else
}
} else {
if (perm & ACE_READ_DATA)
if (perm & ACE_WRITE_DATA)
if (perm & ACE_APPEND_DATA)
}
if (perm & ACE_READ_NAMED_ATTRS)
if (perm & ACE_WRITE_NAMED_ATTRS)
if (perm & ACE_EXECUTE)
if (perm & ACE_DELETE_CHILD)
if (perm & ACE_READ_ATTRIBUTES)
if (perm & ACE_WRITE_ATTRIBUTES)
if (perm & ACE_DELETE)
if (perm & ACE_READ_ACL)
if (perm & ACE_WRITE_ACL)
if (perm & ACE_WRITE_OWNER)
if (perm & ACE_SYNCHRONIZE)
}
return (where);
}
int
{
*perm |= ACE_READ_DATA;
*perm |= ACE_LIST_DIRECTORY;
*perm |= ACE_WRITE_DATA;
*perm |= ACE_ADD_FILE;
*perm |= ACE_APPEND_DATA;
*perm |= ACE_ADD_SUBDIRECTORY;
*perm |= ACE_READ_NAMED_ATTRS;
*perm |= ACE_EXECUTE;
*perm |= ACE_DELETE_CHILD;
*perm |= ACE_READ_ATTRIBUTES;
*perm |= ACE_WRITE_ATTRIBUTES;
*perm |= ACE_DELETE;
*perm |= ACE_READ_ACL;
*perm |= ACE_WRITE_ACL;
*perm |= ACE_WRITE_OWNER;
*perm |= ACE_SYNCHRONIZE;
else {
return (1);
}
return (0);
}
/*
* Callers should check the return code as this routine may change the string
* pointer in dynaclstr.
*/
static int
{
char *tptr;
return (1);
} else
return (0);
}
/*
* ace_acltotext() conver each ace formatted acl to look like this:
*
* entry_type:uid^gid^name:perms:allow^deny[:flags][,]
*
* The maximum length of entry_type is 5 ("group")
*
* The max length of a uid^gid^name entry (in theory) is 8, hence we use
* LOGNAME_MAX.
*
* The length of a perms entry is 144 i.e read_data/write_data...
* to each acl entry.
*
* iflags: file_inherit/dir_inherit/inherit_only/no_propagate
*
*/
#define ACE_ENTRYTYPLEN 6
#define IFLAGS_SIZE 51
#define ACCESS_TYPE_SIZE 5
#define COLON_CNT 3
#define PERMS_LEN 216
static char *
{
char *aclexport;
char *where;
char *start;
int i, rtn;
return (NULL);
return (NULL);
return (NULL);
case ACE_OWNER:
case 0:
else
/* put in uid instead */
} else {
if (excess > 0) {
excess);
if (rtn == 1)
/* reset where */
where =
else
return (NULL);
}
}
} else {
}
break;
case ACE_IDENTIFIER_GROUP:
else
/* put in gid instead */
} else {
if (excess > 0) {
excess);
if (rtn == 1)
/* reset where */
where =
else
return (NULL);
}
}
} else {
}
break;
case ACE_EVERYONE:
break;
default:
return (NULL);
}
":allow" : ":deny");
/*
* slap on inheritance flags if we have any
*/
/*
* chop off trailing slash, if present
*/
}
}
if (i < aclcnt - 1)
}
return (aclexport);
}
static int
{
char *tok;
*iflags = 0;
return (1);
do {
else
return (1);
return (0);
}
/*
* Convert external acl representation to internal representation.
* The accepted syntax is: <acl_entry>[,<acl_entry>]*[,]
* The comma at the end is not prescribed by the man pages.
* But it is needed not to break the old programs.
*/
int
{
char *fieldp;
char *tp;
char *nextp;
char *allocp;
char *aclimport;
char *str;
char *perm_tok;
int entry_type;
int id;
int type;
int iflags;
int len;
int error;
if (! aclstr)
return (EACL_INVALID_STR);
return (EACL_MEM_ERROR);
}
return (EACL_MEM_ERROR);
}
for (; aclimport; ) {
/* look for an ACL entry */
} else {
*tp = '\0';
}
/*
* get additional memory:
* can be more efficient by allocating a bigger block
* each time.
*/
else
return (EACL_MEM_ERROR);
}
/* look for entry type field */
return (EACL_ENTRY_ERROR);
} else
*tp = '\0';
entry_type = 0;
} else {
return (EACL_ENTRY_ERROR);
}
/*
* If not an abstraction owner@, group@ or everyone@
*/
return (EACL_INVALID_USER_GROUP);
} else
*tp = '\0';
/*
* The second field could be empty. We only care
*/
if (entry_type == 0) {
/*
* The reentrant interface getpwnam_r()
* is uncommitted and subject to
* change. Use the friendlier interface
* getpwnam().
*/
error = 0;
} else {
}
if (error) {
return (error);
}
} else {
error = 0;
if (entry_type ==
/* no group? */
} else
} else if ((entry_type == ACE_OWNER) ||
(entry_type ==
(entry_type != ACE_EVERYONE)) {
} else {
}
if (error) {
return (error);
}
}
}
} else {
id = -1;
}
/* next field: permission */
return (EACL_PERM_MASK_ERROR);
} else
*tp = '\0';
perm = 0;
perm = 0;
} else {
do {
return (EACL_PERM_MASK_ERROR);
}
}
*tp = '\0';
else {
return (EACL_INVALID_ACCESS_TYPE);
}
/* grab option inherit flags */
iflags = 0;
*tp = '\0';
return (EACL_INHERIT_ERROR);
}
} else {
return (EACL_UNKNOWN_DATA);
}
}
/* slap fields into ace_t structure */
}
return (0);
}
char
{
return (NULL);
case ACE_T:
return (ace_acltotext(aclp));
case ACLENT_T:
}
return (NULL);
}
int
{
char *token;
char *ptr;
char *textp;
int colon_cnt = 0;
int error;
/*
* first try and detect what type of acl entries we have
*
* aclent_t can have 1, 2 or 3 colons
* if 3 then must have word default:
*
* ace_t can have 2, 3 or 4
* for 2 then must be owner@, group@ or everyone@
*/
return (-1);
return (-1);
}
if (*ptr == ':')
colon_cnt++;
}
else
} else if (colon_cnt == 3) {
return (EACL_MISSING_FIELDS);
} else {
}
} else if (colon_cnt == 4) {
} else {
return (EACL_MISSING_FIELDS);
}
else
return (error);
}