/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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
*/
/*
*/
/*
* setfacl [-r] -f aclfile file ...
* setfacl [-r] -d acl_entries file ...
* setfacl [-r] -m acl_entries file ...
* setfacl [-r] -s acl_entries file ...
* or files.
*/
#include <stdlib.h>
#include <stdio.h>
#include <pwd.h>
#include <grp.h>
#include <string.h>
#include <locale.h>
#include <unistd.h>
#include <errno.h>
static int mod_entries(aclent_t *, int, char *, char *, char *, int);
static int set_file_entries(char *, char *, int);
static int set_online_entries(char *, char *, int);
static void usage();
static int parse_entry_list(aclent_t **, int *, char *, int);
static int convert_to_aclent_t(char *, int *, aclent_t **, int);
static int parse_entry(char *, aclent_t *, int);
static void err_handle(int, aclent_t *);
static int conv_id(char *);
int
{
int c;
int dflag = 0;
int mflag = 0;
int rflag = 0;
int sflag = 0;
int fflag = 0;
int errflag = 0;
(void) textdomain(TEXT_DOMAIN);
if (argc < 3)
usage();
switch (c) {
case 'r':
rflag++;
break;
case 'd':
usage();
dflag++;
break;
case 'm':
usage();
mflag++;
break;
case 's':
usage();
sflag++;
break;
case 'f':
usage();
fflag++;
break;
case '?':
errflag++;
break;
}
}
if (errflag)
usage();
/* one of these flags should be set */
usage();
/* no file arguments */
usage();
register char *filep;
/* modify and delete: we need to get the ACL first */
gettext("out of memory %s\n"),
m_entryp);
exit(1);
}
}
gettext("out of memory %s\n"),
d_entryp);
exit(1);
}
}
if (aclcnt == -1)
exit(2);
exit(2);
} else if (fflag) {
exit(2);
} else if (sflag) {
gettext("out of memory %s\n"),
s_entryp);
exit(1);
}
}
exit(2);
}
}
return (0);
}
/*
* For add, modify, and delete, we need to get the ACL of the file first.
*/
static int
{
int aclcnt;
gettext("File system doesn't support aclent_t "
"style ACL's.\n"
"See acl(5) for more information on"
" ACL styles support by Solaris.\n"));
return (-1);
}
perror("get acl count error");
return (-1);
}
if (aclcnt < MIN_ACL_ENTRIES) {
gettext("%d: acl count is too small from %s\n"),
return (-1);
}
return (-1);
}
perror("getacl error");
return (-1);
}
return (aclcnt);
}
/*
* mod_entries() handles add, delete, and modify ACL entries of a file.
* The real action is in convert_to_aclent_t() called by parse_entry_list().
* aclp: points ACL of a file and may be changed by lower level routine.
* modp: modify entry list in ascii format
* delp: delete entry list in ascii format
* fnamep: file of interest
*/
static int
{
/* modify and add: from -m option */
return (-1);
/* deletion: from -d option */
return (-1);
return (-1);
}
perror("setacl error");
return (-1);
}
return (0);
}
/*
* set_file_entries() creates ACL entries from ACL file (acl_fnamep).
* It opens the file and converts every line (one line per acl entry)
* into aclent_t format. It then recalculates the mask according to rflag.
* Finally it sets ACL to the file (fnamep).
*/
static int
{
int aclcnt = 0;
char *tp;
else {
return (-1);
}
}
continue;
/* check effective permission: add a null after real perm */
tp--;
tp--;
else {
gettext("entry format error %s\n"),
buf);
exit(1);
}
}
}
/* remove <nl> at the end if there is one */
*tp = '\0';
aclcnt++;
return (-1);
}
aclcnt, acl_fnamep);
return (-1);
}
perror("setacl error");
return (-1);
}
return (0);
}
/*
* set_online_entries() parses the acl entries from command line (setp).
* It converts the comma separated acl entries into aclent_t format.
* It then recalculates the mask according to rflag.
* Finally it sets ACL to the file (fnamep).
*/
static int
{
char *commap;
int aclcnt = 0;
return (-1);
return (-1);
}
perror("setacl error");
return (-1);
}
return (0);
}
/*
* parse_entry_list() parses entry list (listp) separated by commas.
* Once it gets an ACL entry, it calls convert_to_aclent_t() to convert
* to internal format.
*/
static int
{
char *commap;
return (0);
*commap = '\0';
*aclcntp += 1;
/* aclcnt may be updated after the call: add or modify */
return (-1);
}
/* this is for only one entry or last entry */
if (*listp != '\0') {
*aclcntp += 1;
return (-1);
}
return (0);
}
/*
* convert_to_aclent_t() converts an acl entry in ascii format (fields separated
* by colon) into aclent_t and appends it to the current ACL. It also handles
* memory allocation/deallocation for acl entries in aclent_t format.
* aclpp that contains acl entries in acl format will be returned.
* We don't check duplicates.
*/
static int
{
int cur_cnt;
int found = 0;
int is_obj;
return (0);
if (*cntp > 1)
else
return (-1);
}
if (entryp[0] == 'u')
if (entryp[0] == 'g')
return (-1);
switch (mode) {
case MODIFY: /* and add */
found++;
/* cnt is added before it's called */
*cntp -= 1;
break;
}
}
if (!found) /* Add it to the end: no need to change cntp */
break;
case DELETE:
found++;
/* move up the rest */
while (cur_cnt-- > 0) {
sizeof (aclent_t));
taclp++;
}
break;
}
}
if (!found)
*cntp -= 1;
break;
case SET:
/* we may check duplicate before copying over?? */
break;
default:
gettext("Unrecognized mode: internal error\n"));
break;
}
/*
* If converting from non-trivial acl entry to trivial one,
* reset CLASS_OBJ's permission with that of GROUP_OBJ.
*/
case USER_OBJ:
case OTHER_OBJ:
break;
case CLASS_OBJ:
break;
case GROUP_OBJ:
break;
default:
/*
* Confirmed that the new acl set is
* still a non-trivial acl.
* Skip reset.
*/
}
}
}
return (0);
}
static void
usage()
{
gettext("\tsetfacl [-r] -f aclfile file ...\n"));
gettext("\tsetfacl [-r] -d acl_entries file ...\n"));
gettext("\tsetfacl [-r] -m acl_entries file ...\n"));
gettext("\tsetfacl [-r] -s acl_entries file ...\n"));
exit(1);
}
static void
{
int rc;
int which;
switch (rc) {
case USER_ERROR:
gettext("There is more than one user owner entry"));
break;
case GRP_ERROR:
gettext("There is more than one group owner entry"));
break;
case CLASS_ERROR:
gettext("There is more than one mask entry"));
break;
case OTHER_ERROR:
gettext("There is more than one other entry"));
break;
case DUPLICATE_ERROR:
gettext("Duplicate user or group entries"));
break;
case MISS_ERROR:
break;
case MEM_ERROR:
gettext("Insufficient memory\n"));
break;
case ENTRY_ERROR:
gettext("Unrecognized entry type"));
break;
default:
/* error is not from aclcheck */
gettext("aclsort error\n"));
break;
}
}
static int
{
char *colonp;
int id;
return (-1);
}
*colonp = '\0';
def_flag++;
return (-1);
}
*colonp = '\0';
}
/* process entry type */
if (def_flag)
else
}
if (def_flag)
else
}
if (def_flag)
else
}
if (def_flag)
else
}
/* still can't determine entry type */
return (-1);
}
/* mask and other entries dont have id field */
/* process id: */
gettext("Can't find colon delimiter %s\n"),
fieldp);
return (-1);
}
} else
*colonp = '\0';
if (*fieldp == '\0') {
/* empty uid */
} else {
else {
/* treat it as numeric id */
if (id == -1)
return (-1);
}
} else {
/* group name */
else {
if (id == -1)
return (-1);
}
}
}
} else {
mo_flag = 1;
}
/* process permission: rwx and [0]n format */
/* delete format: no permission field */
return (0);
if (mo_flag == 1) {
"mask and other entries.\n"));
return (-1);
} else {
/* it's ok to have extra colon */
*colonp = '\0';
}
}
gettext("only rwx or [0]n format is allowed\n"));
return (-1);
}
/* treat it as rwx */
if (*fieldp == 'r')
else
if (*fieldp != '-') {
gettext("Unrecognized character "));
gettext("found in mode field\n"));
return (-1);
}
fieldp++;
if (*fieldp == 'w')
else
if (*fieldp != '-') {
gettext("Unrecognized character "));
gettext("found in mode field\n"));
return (-1);
}
fieldp++;
if (*fieldp == 'x')
else
if (*fieldp != '-') {
gettext("Unrecognized character "));
gettext("found in mode field\n"));
return (-1);
}
return (0);
}
if (*fieldp == '\0')
return (0);
else {
return (-1);
}
/* look at next char */
else {
gettext("Check also the number of fields "));
gettext("(default) mask and other entries\n"));
return (-1);
}
}
/* check for junk at the end ??? */
return (0);
}
/*
* This function is different from atoi() in that it checks for
* valid digit in the id field whereas atoi() won't report any
* error.
*/
static int
{
int a_id = 0;
return (-1);
}
}
return (a_id);
}