1585 lines
39 KiB
C
1585 lines
39 KiB
C
/**************************************************************************
|
||
* *
|
||
* Copyright (C) 1993, Silicon Graphics, Inc. *
|
||
* *
|
||
* These coded instructions, statements, and computer programs contain *
|
||
* unpublished proprietary information of Silicon Graphics, Inc., and *
|
||
* are protected by Federal copyright law. They may not be disclosed *
|
||
* to third parties or copied or duplicated in any form, in whole or *
|
||
* in part, without the prior written consent of Silicon Graphics, Inc. *
|
||
* *
|
||
**************************************************************************/
|
||
|
||
/***************************************************************************
|
||
* Command: setacl
|
||
*
|
||
***************************************************************************/
|
||
|
||
#include <stdio.h>
|
||
#include <errno.h>
|
||
#include <pwd.h>
|
||
#include <grp.h>
|
||
#include <sys/acl.h>
|
||
#include <sys/types.h>
|
||
#include <sys/param.h>
|
||
#include <locale.h>
|
||
#include <pfmt.h>
|
||
|
||
#define AREAD 0x4 /* read permission */
|
||
#define AWRITE 0x2 /* write permission */
|
||
#define AEXEC 0x1 /* execute permission */
|
||
|
||
#define NOMATCH 0 /* no entry match found in ACL */
|
||
#define MRECLEN 256 /* maximum record length for "-f" option file */
|
||
|
||
#define NENTRIES 128 /* initial size of ACL buffer */
|
||
|
||
#define BADMALLOC ":66:malloc failed\n"
|
||
#define NOPERM ":63:permission denied for \"%s\"\n"
|
||
#define NOINSTALL ":57:system service not installed\n"
|
||
#define ACLFAIL ":80:acl failed for \"%s\", %s\n"
|
||
#define INCOMPTBLOPT ":81:incompatible options specified\n"
|
||
#define BADUSAGE ":48:incorrect usage\n"
|
||
#define DUPENTRY ":82:duplicate entries: \"%s\"\n"
|
||
#define ILLEGALOPT ":84:illegal entry specification, \"%s\"\n"
|
||
#define ILLEGALOPT2 ":50:program error\n"
|
||
#define NOENTRY ":85:required entry for file owner, file group, \"class\", or \"other\" not specified\n"
|
||
#define ACLSORTFAIL ":86:aclsort call failed\n"
|
||
#define ACLSORTFAIL1 ":87:aclsort call failed for \"%s\"\n"
|
||
#define NOFILEFOUND ":64:file \"%s\" not found\n"
|
||
#define OPENFAIL ":88:can't open file \"%s\", %s\n"
|
||
#define BADACLENTRY ":89:\"%s\", line %d; invalid ACL entry\n"
|
||
#define DONOTDELETE ":90:file owner, file group, \"class\", and \"other\" entries may not be deleted\n"
|
||
#define UNKTYPE ":91:unknown type \"%s\"\n"
|
||
#define UNKUSER ":92:unknown user-id \"%s\"\n"
|
||
#define UNKGROUP ":93:unknown group-id \"%s\"\n"
|
||
#define UNKPERM ":94:unknown permission \"%s\"\n"
|
||
#define NOMATCHFOUND ":95:matching entry not found in ACL for \"%s\": \"%s\"\n"
|
||
#define BADENTRYTYPE ":96:only file owner, file group, \"class\", or \"other\" may be specified for \"%s\"\n"
|
||
#define NODEFAULT ":97:default ACL entries may only be set on directories, not on \"%s\"\n"
|
||
|
||
int lno; /* aid in printing the file and line number */
|
||
char *curfile; /* when the -f option is specified */
|
||
int fflag = 0;
|
||
|
||
#define FILE_PRINT() { \
|
||
if (fflag) \
|
||
pfmt(stderr, MM_ERROR, BADACLENTRY, curfile, lno); \
|
||
}
|
||
|
||
struct acl_entry aclbuf[NENTRIES]; /* initial ACL buffer */
|
||
|
||
/*
|
||
*
|
||
* The ACL operations buffer will be filled up with ACL entries specified
|
||
* as option arguments to the "-d" and "-m" options. If the same ACL
|
||
* entry is specified in multiple option argument lists, only the last
|
||
* one specified will take affect. In order to accomplish this, as each
|
||
* "-m" or "-d" option argument list is processed, all previously specified
|
||
* entries, contained in the operations buffer, will be scanned for duplicates.
|
||
* If a duplicate entry is found, the most recent one will replace
|
||
* the previous one in the ACL operations buffer.
|
||
* This work is done by routine dmtoacl(). Once all option arguments are
|
||
* processed, the ACL from the current file is obtained via routine getacl(),
|
||
* and routines modacl() and delacl() are called to modify entries and delete
|
||
* entries from the ACL, based on the entries in the ACL operations buffer.
|
||
*
|
||
*/
|
||
struct aclops { /* buffer of ACL operations for "-d" & "-m" */
|
||
int a_op; /* operation to perform */
|
||
struct acl_entry a_acl; /* entry to perform it on */
|
||
} aclopbuf[NENTRIES]; /* initial ACL operations buffer */
|
||
|
||
/* flags for aclops.a_op */
|
||
#define ACL_MOD 0x1 /* modify this entry */
|
||
#define ACL_DEL 0x2 /* delete this entry */
|
||
#define ACL_ADD 0x4 /* add this entry */
|
||
|
||
|
||
/*
|
||
* Macro GROWACLBUF is used to make the ACL buffer larger
|
||
* when necessary.
|
||
*
|
||
* NEWENTRIES is the number of entries the new buffer must hold.
|
||
* BUFENTRIES is the number of entries the current buffer holds.
|
||
* NBUFP is a pointer for the new ACL buffer.
|
||
* OBUFP is a pointer to the old ACL buffer.
|
||
* OLDENTRIES is the number of actual entries in the old buffer
|
||
* (it may not be full).
|
||
*
|
||
* If OLDENTRIES is not zero, the actual entries in the old buffer
|
||
* are copied into the new buffer.
|
||
* The old buffer OBUFP is free()'ed if it was obtained via malloc().
|
||
*
|
||
*/
|
||
#define GROWACLBUF(NEWENTRIES, BUFENTRIES, NBUFP, OBUFP, OLDENTRIES) \
|
||
{ \
|
||
int buflen; \
|
||
int i; \
|
||
struct acl_entry *SRCACLP; \
|
||
struct acl_entry *TGTACLP; \
|
||
while (NEWENTRIES > BUFENTRIES) \
|
||
BUFENTRIES *= 2; \
|
||
buflen = BUFENTRIES * sizeof(struct acl_entry); \
|
||
if ((NBUFP = (struct acl_entry *)malloc(buflen)) == NULL) { \
|
||
pfmt(stderr, MM_ERROR, BADMALLOC); \
|
||
exit(32); \
|
||
} \
|
||
if (OLDENTRIES) { \
|
||
SRCACLP = OBUFP; \
|
||
TGTACLP = NBUFP; \
|
||
for (i = 0; i < OLDENTRIES; i++) \
|
||
*TGTACLP++ = *SRCACLP++; \
|
||
} \
|
||
if (OBUFP != aclbuf) \
|
||
free(OBUFP); \
|
||
OBUFP = NBUFP; \
|
||
}
|
||
|
||
|
||
void usage(); /* print "usage: " message */
|
||
|
||
extern int optind; /* for getopt */
|
||
extern char *optarg; /* for getopt */
|
||
extern int errno;
|
||
extern char *sys_errlist[];
|
||
extern int sys_nerr;
|
||
|
||
/*
|
||
* Procedure: main
|
||
*
|
||
* Restrictions:
|
||
getopt: none
|
||
pfmt: none
|
||
*/
|
||
main(argc,argv)
|
||
char *argv[];
|
||
{
|
||
struct aclops *aclopbp = aclopbuf; /* ACL operations buffer */
|
||
struct acl_entry *aclbp = aclbuf;/* pointer to ACL buffer */
|
||
void ftoacl(); /* processes -f option args */
|
||
void acltochar(); /* converts acl to printable format */
|
||
int opbuf_entries = NENTRIES;/* ACL operations buf size */
|
||
int buf_entries = NENTRIES; /* ACL buffer size */
|
||
int mflag = 0; /* option flags */
|
||
int dflag = 0;
|
||
int sflag = 0;
|
||
int rflag = 0;
|
||
int dmentries = 0; /* args of "-d" & "-m" */
|
||
int nentries = 0; /* entries to set */
|
||
int i,j,k,c;
|
||
int ret; /* return value from aclsort */
|
||
int error = 0; /* final return code to user */
|
||
char *ffile; /* file for "-f" option */
|
||
char *argp;
|
||
char aclentry[MRECLEN];
|
||
|
||
|
||
(void)setlocale(LC_ALL,"");
|
||
(void)setcat("uxes");
|
||
(void)setlabel("UX:setacl");
|
||
|
||
while ((c=getopt(argc,argv,"rm:d:s:f:"))!=EOF) {
|
||
argp = optarg;
|
||
switch(c) {
|
||
case 'm':
|
||
if (fflag || sflag) {
|
||
pfmt(stderr, MM_ERROR, INCOMPTBLOPT);
|
||
usage();
|
||
exit(1);
|
||
}
|
||
if ((ret = dmtoacl(argp, &aclopbp, &opbuf_entries,
|
||
&dmentries, ACL_MOD)) == -1) {
|
||
pfmt(stderr, MM_ERROR, BADUSAGE);
|
||
usage();
|
||
exit(1);
|
||
}
|
||
mflag++;
|
||
break;
|
||
case 'd':
|
||
if (fflag || sflag) {
|
||
pfmt(stderr, MM_ERROR, INCOMPTBLOPT);
|
||
usage();
|
||
exit(1);
|
||
}
|
||
if ((ret = dmtoacl(argp, &aclopbp, &opbuf_entries,
|
||
&dmentries, ACL_DEL)) == -1) {
|
||
pfmt(stderr, MM_ERROR, BADUSAGE);
|
||
usage();
|
||
exit(1);
|
||
}
|
||
dflag++;
|
||
break;
|
||
case 's':
|
||
if (mflag || dflag || fflag) {
|
||
pfmt(stderr, MM_ERROR, INCOMPTBLOPT);
|
||
usage();
|
||
exit(1);
|
||
}
|
||
if ((ret = stoacl(argp, &aclbp, &buf_entries,
|
||
&nentries)) == -1) {
|
||
pfmt(stderr, MM_ERROR, BADUSAGE);
|
||
usage();
|
||
exit(1);
|
||
}
|
||
sflag++;
|
||
break;
|
||
case 'f':
|
||
if (sflag || mflag || dflag) {
|
||
pfmt(stderr, MM_ERROR, INCOMPTBLOPT );
|
||
usage();
|
||
exit(1);
|
||
}
|
||
ffile = optarg;
|
||
fflag++;
|
||
ftoacl(ffile, &aclbp, &buf_entries, &nentries);
|
||
break;
|
||
case 'r':
|
||
rflag++;
|
||
break;
|
||
case '?':
|
||
usage();
|
||
exit(1);
|
||
break;
|
||
} /* end switch */
|
||
} /* end while getopt */
|
||
|
||
if (optind == argc) { /* no file name given */
|
||
pfmt(stderr, MM_ERROR, BADUSAGE);
|
||
usage();
|
||
exit(1);
|
||
}
|
||
if (!dflag && !mflag && !sflag && !fflag) {
|
||
pfmt(stderr, MM_ERROR, BADUSAGE);
|
||
usage();
|
||
exit(1);
|
||
}
|
||
/*
|
||
* Fixed ACL for -s and -f options; sort once only.
|
||
*/
|
||
if (sflag || fflag) {
|
||
/* sort the entries and update the ACL */
|
||
if ((ret = aclsort(nentries, rflag, aclbp)) != 0) {
|
||
if (ret > 0) {
|
||
acltochar(aclbp + ret, aclentry);
|
||
pfmt(stderr, MM_ERROR, DUPENTRY, aclentry);
|
||
exit(32);
|
||
}
|
||
if ((ret == -1) && (ckmandacls(nentries, aclbp) != 0)) {
|
||
/* check that all base entries exist */
|
||
pfmt(stderr, MM_ERROR, NOENTRY);
|
||
usage();
|
||
exit(1);
|
||
}
|
||
pfmt(stderr, MM_ERROR, ACLSORTFAIL);
|
||
exit(32);
|
||
} /* end "if ((ret = aclsort( ..." */
|
||
}
|
||
for (i = optind; i < argc; i++) {
|
||
/* loop for each file specified */
|
||
if (dflag || mflag) {
|
||
/*
|
||
* get all existing ACL entries for the file
|
||
*/
|
||
if (getacl(argv[i], &aclbp, &buf_entries,
|
||
&nentries) < 0) {
|
||
error = 2;
|
||
continue;
|
||
}
|
||
|
||
if (dflag) {
|
||
/*
|
||
* 1st delete all entries marked for deletion
|
||
* in the operations buffer from the file's
|
||
* ACL buffer.
|
||
*/
|
||
if (delacl(aclopbp, dmentries, aclbp, &nentries, argv[i]) < 0){
|
||
error = 2;
|
||
continue;
|
||
}
|
||
}
|
||
if (mflag) {
|
||
/*
|
||
* then add or modify all entries marked
|
||
* for modification in the operations buffer
|
||
*/
|
||
if (modacl(aclopbp, dmentries, &aclbp,
|
||
&buf_entries, &nentries, argv[i]) < 0) {
|
||
error = 2;
|
||
continue;
|
||
}
|
||
}
|
||
/*
|
||
* if we deleted entries, and now only have four base
|
||
* entries, make sure the CLASS_OBJ & GROUP_OBJ
|
||
* permissions match now.
|
||
*/
|
||
if (dflag && (nentries == NACLBASE))
|
||
rflag++;
|
||
|
||
/* sort the entries and update the ACL */
|
||
if ((ret = aclsort(nentries, rflag, aclbp)) != 0) {
|
||
pfmt(stderr, MM_ERROR, ACLSORTFAIL1, argv[i]);
|
||
error = 2;
|
||
continue;
|
||
} /* end "if ((ret = aclsort( ..." */
|
||
}
|
||
if (putacls(argv[i], aclbp, nentries, (dflag || mflag)) != 0)
|
||
error = 2;
|
||
} /* end for */
|
||
|
||
/*
|
||
* if we had to allocate a new operations buffer
|
||
* or ACL buffer, make sure to free them now
|
||
*/
|
||
if (aclbp != aclbuf)
|
||
free(aclbp);
|
||
if (aclopbp != aclopbuf)
|
||
free(aclopbp);
|
||
exit(error);
|
||
|
||
}
|
||
|
||
/*
|
||
* Procedure: stoacl
|
||
*
|
||
* Restrictions:
|
||
*/
|
||
/*
|
||
*
|
||
* stoacl - converts operands of the "-s" option
|
||
* which are expressions of the form
|
||
*
|
||
* [d[efault]:]u[ser]:[uid]:operm | perm
|
||
* or
|
||
* [d[efault]:]g[roup]:[gid]:operm | perm
|
||
* or
|
||
* [d[efault]:]c[lass]:operm | perm
|
||
* or
|
||
* [d[efault]:]o[ther]:operm | perm
|
||
*
|
||
* to a buffer containing an ACL
|
||
*
|
||
* input - 1. Pointer to the argument expression
|
||
* 2. Pointer to the buffer to store the ACL in
|
||
* 3. Pointer to number of entries which will
|
||
* fit in the buffer.
|
||
* 4. Pointer to the number of entries actually
|
||
* stored in the buffer.
|
||
*
|
||
* output - 0 on success, -1 on failure
|
||
*
|
||
*/
|
||
|
||
int
|
||
stoacl(argp, aclpp, bufentriesp, sentriesp)
|
||
char *argp;
|
||
struct acl_entry **aclpp;
|
||
int *bufentriesp;
|
||
int *sentriesp;
|
||
{
|
||
register int commas, i, buflen;
|
||
struct acl_entry *aclp = *aclpp;
|
||
struct acl_entry *tgtaclp = aclp;
|
||
char *malloc(), *scanugo();
|
||
char *argstart;
|
||
long bentries = *bufentriesp;
|
||
|
||
if (argp == NULL || *argp=='\0')
|
||
return(-1);
|
||
argstart = argp;
|
||
|
||
/* count number of acl entries to modify */
|
||
|
||
commas = 1;
|
||
while (*argp && *argp != '\n') {
|
||
if (*argp == ',')
|
||
commas++;
|
||
++argp;
|
||
}
|
||
|
||
if (commas > bentries)
|
||
GROWACLBUF(commas, bentries, tgtaclp, aclp, 0);
|
||
argp = argstart;
|
||
for (i = 0; i < commas; i++, tgtaclp++) {
|
||
|
||
/* validate ae_type, ae_id portion of ACL entry */
|
||
argp = scanugo(argp, &tgtaclp->ae_type, &tgtaclp->ae_id, ':');
|
||
|
||
/* validate ae_perm portion of ACL entry */
|
||
(void)scanperms(&argp, &tgtaclp->ae_perm, ',');
|
||
|
||
} /* end for */
|
||
*sentriesp = commas;
|
||
*bufentriesp = bentries;
|
||
*aclpp = aclp;
|
||
return(0);
|
||
}
|
||
|
||
/*
|
||
* Procedure: ftoacl
|
||
*
|
||
* Restrictions:
|
||
fopen: none
|
||
fgets: none
|
||
rewind: none
|
||
pfmt: none
|
||
*/
|
||
/*
|
||
*
|
||
* ftoacl - reads file argument of "-f" option
|
||
* which contains expressions of the form
|
||
*
|
||
* [d[efault]:]u[ser]:[uid]:operm | perm
|
||
* or
|
||
* [d[efault]:]g[roup]:[gid]:operm | perm
|
||
* or
|
||
* [d[efault]:]c[lass]:operm | perm
|
||
* or
|
||
* [d[efault]:]o[ther]:operm | perm
|
||
* or
|
||
* comments starting with "#"
|
||
* and converts them to ACL entries.
|
||
*
|
||
* input - 1. Pointer to the file name
|
||
* 2. Pointer to the ACL buffer.
|
||
* 3. Pointer to the number of entries which
|
||
* will fit in the ACL buffer.
|
||
* 4. Pointer to the number of ACL entries
|
||
* stored in the ACL buffer.
|
||
*
|
||
* output - none
|
||
*
|
||
*/
|
||
|
||
void
|
||
ftoacl(filep, aclpp, bufentriesp, nentriesp)
|
||
register char *filep;
|
||
struct acl_entry **aclpp;
|
||
int *bufentriesp;
|
||
int *nentriesp;
|
||
{
|
||
struct acl_entry *aclp = *aclpp;
|
||
struct acl_entry *tgtaclp = aclp;
|
||
FILE *fd, *fopen();
|
||
char *malloc(), *fgets(), *scanugo();
|
||
char *argp, rec[MRECLEN];
|
||
int c, entries, buflen;
|
||
int ret;
|
||
int bentries = *bufentriesp;
|
||
int oentries;
|
||
void rewind();
|
||
|
||
if ((fd = fopen(filep, "r")) == NULL) {
|
||
if (errno == EACCES)
|
||
pfmt(stderr, MM_ERROR, NOPERM, filep);
|
||
else if (errno == ENOENT)
|
||
pfmt(stderr, MM_ERROR, NOFILEFOUND, filep);
|
||
else
|
||
pfmt(stderr, MM_ERROR, OPENFAIL, filep, strerror(errno));
|
||
exit(32);
|
||
}
|
||
entries = 0;
|
||
lno = 0;
|
||
curfile = filep;
|
||
while (fgets(rec, MRECLEN, fd) != NULL) {
|
||
lno++;
|
||
argp = rec;
|
||
while (*argp == ' ')
|
||
argp++;
|
||
if (!*argp)
|
||
continue; /* if blank or null line, skip it */
|
||
if (*argp == '#') /* if line start w/ comment, skip it */
|
||
continue;
|
||
entries++;
|
||
if (entries > bentries) {
|
||
oentries = entries - 1;
|
||
GROWACLBUF(entries, bentries, tgtaclp, aclp, oentries);
|
||
tgtaclp += oentries;
|
||
}
|
||
|
||
/* validate type and id in entry */
|
||
argp = scanugo(argp, &tgtaclp->ae_type, &tgtaclp->ae_id, ':');
|
||
|
||
/* validate permissions in entry */
|
||
if ((ret = scanperms(&argp, &tgtaclp->ae_perm, ' ')) != -1) {
|
||
/* make sure only white space or comments follow */
|
||
argp++;
|
||
while ((*argp == ' ') || (*argp == '\t'))
|
||
argp++;
|
||
if ((*argp != '#') && (*argp != '\n')) {
|
||
pfmt(stderr, MM_ERROR, BADACLENTRY, filep, lno);
|
||
exit(32);
|
||
}
|
||
}
|
||
tgtaclp++;
|
||
} /* end while "fscanf" */
|
||
*nentriesp = entries;
|
||
*bufentriesp = bentries;
|
||
*aclpp = aclp;
|
||
return;
|
||
}
|
||
|
||
/*
|
||
* Procedure: dmtoacl
|
||
*
|
||
* Restrictions:
|
||
pfmt: none
|
||
*/
|
||
/*
|
||
*
|
||
* dmtoacl - converts operands of the "-d" & "-m" options
|
||
* which are expressions of the form
|
||
*
|
||
* [d[efault]:]u[ser]:[uid][:operm | perm]
|
||
* or
|
||
* [d[efault]:]g[roup]:[gid][:operm | perm]
|
||
* or
|
||
* [d[efault]:]c[lass]:operm | perm
|
||
* or
|
||
* [d[efault]:]o[ther]:operm | perm
|
||
*
|
||
* to a buffer containing an ACL
|
||
*
|
||
* input - 1. Pointer to the argument expression
|
||
* 2. current buffer containing entries to be
|
||
* modified or deleted.
|
||
* 3. Pointer to number of entries which will
|
||
* fit in current buffer.
|
||
* 4. Pointer to number of entries to be
|
||
* modified or deleted.
|
||
* 5. Flag indicating whether processing "-d" or "-m"
|
||
*
|
||
* output - 0 on success, -1 on failure
|
||
*
|
||
*/
|
||
|
||
int
|
||
dmtoacl(argp, dmaclopbpp, bufentriesp, nentriesp, dmflag)
|
||
char *argp; /* argument string */
|
||
struct aclops **dmaclopbpp; /* ptr to buffer of -d & -m entries */
|
||
int *bufentriesp; /* max number of entries in buffer */
|
||
int *nentriesp; /* current num. of entries in buffer */
|
||
int dmflag; /* ACL_DEL for "-d", ACL_MOD for "-m" */
|
||
{
|
||
char *argstart, *malloc(), *scanugo();
|
||
struct aclops *newaclopbp;
|
||
struct aclops *srcaclopbp;
|
||
struct aclops *tgtaclopbp;
|
||
struct aclops *dmaclopbp = *dmaclopbpp;
|
||
struct acl_entry dmacl;
|
||
register int commas, i, j, buflen;
|
||
int entries = *nentriesp;
|
||
int bentries = *bufentriesp;
|
||
char delim;
|
||
|
||
if ((argp == NULL) || (*argp == '\0'))
|
||
return (-1);
|
||
argstart = argp;
|
||
|
||
/* count number of acl entries to modify */
|
||
|
||
commas = 1;
|
||
while (*argp && *argp != '\n') {
|
||
if (*argp == ',')
|
||
commas++;
|
||
++argp;
|
||
}
|
||
/*
|
||
* if the new argument entries, added to the entries currently
|
||
* in the operations buffer, will exceed the buffer size,
|
||
* we've got to allocate a new operations buffer
|
||
*/
|
||
if ((entries + commas) > bentries) {
|
||
|
||
/* existing operations buffer not big enough */
|
||
while ((entries + commas) > bentries)
|
||
bentries *= 2;
|
||
|
||
/* get storage space for acl entries to modify */
|
||
buflen = bentries * sizeof(struct aclops);
|
||
if ((newaclopbp = (struct aclops *)malloc(buflen)) == NULL) {
|
||
pfmt(stderr, MM_ERROR, BADMALLOC);
|
||
exit(32);
|
||
}
|
||
/* now copy existing operations buffer to new buffer */
|
||
srcaclopbp = dmaclopbp;
|
||
tgtaclopbp = newaclopbp;
|
||
for (i = 0; i < entries; i++)
|
||
*tgtaclopbp++ = *srcaclopbp++;
|
||
|
||
/* if the previous buffer was malloc'ed, free it */
|
||
if (dmaclopbp != aclopbuf)
|
||
free(dmaclopbp);
|
||
dmaclopbp = newaclopbp;
|
||
} /* end if */
|
||
|
||
/*
|
||
* now scan each argument entry, and for each, try to find it in
|
||
* the existing operations buffer of entries.
|
||
*/
|
||
tgtaclopbp = dmaclopbp;
|
||
argp = argstart;
|
||
for (i = 0; i < commas; i++) {
|
||
|
||
/* validate ae_type, ae_id portion of ACL entry */
|
||
if (dmflag & ACL_DEL)
|
||
delim = ',';
|
||
else
|
||
delim = ':';
|
||
argp = scanugo(argp, &dmacl.ae_type, &dmacl.ae_id, delim);
|
||
|
||
if (dmflag & ACL_DEL) {
|
||
/* can't delete these types */
|
||
if ((dmacl.ae_type == USER_OBJ) ||
|
||
(dmacl.ae_type == GROUP_OBJ) ||
|
||
(dmacl.ae_type == CLASS_OBJ) ||
|
||
(dmacl.ae_type == OTHER_OBJ)) {
|
||
pfmt(stderr, MM_ERROR, DONOTDELETE);
|
||
exit (32);
|
||
}
|
||
} else {
|
||
/* get permissions to modify */
|
||
(void)scanperms(&argp, &dmacl.ae_perm, ',');
|
||
}
|
||
|
||
for (j = 0; j < entries; j++, tgtaclopbp++) {
|
||
if ((tgtaclopbp->a_acl.ae_type == dmacl.ae_type) &&
|
||
(tgtaclopbp->a_acl.ae_id == dmacl.ae_id)) {
|
||
/*
|
||
* the entry has been previously specified
|
||
* as an arg to -d or -m.
|
||
* mark entry for modification or deletion
|
||
*/
|
||
if (dmflag & ACL_MOD)
|
||
/* if "-m", set new permissions */
|
||
tgtaclopbp->a_acl.ae_perm = dmacl.ae_perm;
|
||
tgtaclopbp->a_op = dmflag;
|
||
break;
|
||
}
|
||
} /* end for j */
|
||
if (j == entries) {
|
||
/*
|
||
* no match - this is the first time this entry
|
||
* has been specified. add it to the buffer for
|
||
* modification or deletion
|
||
*/
|
||
tgtaclopbp->a_acl.ae_type = dmacl.ae_type;
|
||
tgtaclopbp->a_acl.ae_id = dmacl.ae_id;
|
||
if (dmflag & ACL_MOD)
|
||
/* if "-m", set new permissions */
|
||
tgtaclopbp->a_acl.ae_perm = dmacl.ae_perm;
|
||
tgtaclopbp->a_op = dmflag;
|
||
entries++;
|
||
}
|
||
tgtaclopbp = dmaclopbp;
|
||
} /* end for i */
|
||
*nentriesp = entries;
|
||
*bufentriesp = bentries;
|
||
*dmaclopbpp = dmaclopbp;
|
||
return(0);
|
||
}
|
||
|
||
/*
|
||
* Procedure: scanugo
|
||
*
|
||
* Restrictions:
|
||
getpwnam: P_MACREAD
|
||
getgrnam: P_MACREAD
|
||
pfmt: none
|
||
sscanf: none
|
||
*/
|
||
/*
|
||
*
|
||
* scanugo - scans for an expression of the form
|
||
* "user::", "user:uid:", "group::",
|
||
* "group:gid:", "class:", or "other:"
|
||
* Each of the expressions may optionally be preceded
|
||
* by the default specifier "default:" or "d:"
|
||
*
|
||
* input - argp : a pointer to the argument string
|
||
* type : pointer to a variable to store the entry type in
|
||
* id : pointer to a variable to store the id in
|
||
* delim: the character ending the "type:id" expression -
|
||
* currently either ':' for arguments of the
|
||
* -f, -m, and -s option, or ',' for arguments
|
||
* of the -d option.
|
||
*
|
||
* output - the updated pointer to the arg string
|
||
*
|
||
*/
|
||
char *
|
||
scanugo(argp, type, id, delim)
|
||
char *argp;
|
||
int *type;
|
||
uid_t *id;
|
||
char delim;
|
||
{
|
||
char *p, *unamep, *gnamep;
|
||
struct passwd *getpwnam(),*pwd_p;
|
||
struct group *getgrnam(),*grp_p;
|
||
uid_t uid, gid;
|
||
int ret;
|
||
char name[50]; /* for sscanf call; error if filled */
|
||
char *tnamep;
|
||
|
||
tnamep = unamep = argp;
|
||
ret = skipc(&argp, ':');
|
||
|
||
/*
|
||
* check if this is a default entry
|
||
* scan for "default" or "d"
|
||
*/
|
||
|
||
if ((strcmp(unamep, "default") == 0) || (strcmp(unamep, "d") == 0)) {
|
||
*type = ACL_DEFAULT;
|
||
unamep = argp;
|
||
*(unamep-1) = ':'; /* for tnamep */
|
||
ret = skipc(&argp, ':');
|
||
} else
|
||
*type = 0;
|
||
|
||
/*
|
||
* scan for "user", "u", "group", "g", "class", "c", "other", or "o"
|
||
*/
|
||
|
||
if ((strcmp(unamep, "user") == 0) || (strcmp(unamep, "u") == 0)) {
|
||
/*
|
||
* ae_type is USER_OBJ or USER
|
||
*/
|
||
if (ret == 0)
|
||
*(argp-1) = ':'; /* for tnamep */
|
||
if (*argp == '\0') {
|
||
FILE_PRINT();
|
||
pfmt(stderr, MM_ERROR, ILLEGALOPT, tnamep);
|
||
usage();
|
||
exit(1);
|
||
}
|
||
unamep = argp;
|
||
if (*unamep == ':') {
|
||
if (delim == ',') { /* -d option */
|
||
unamep++;
|
||
if (*unamep && *unamep != ',') {
|
||
FILE_PRINT();
|
||
pfmt(stderr, MM_ERROR, ILLEGALOPT,
|
||
tnamep);
|
||
usage();
|
||
exit(1);
|
||
}
|
||
|
||
}
|
||
*type |= USER_OBJ;
|
||
return ++unamep;
|
||
}
|
||
ret = skipc(&argp, delim);
|
||
pwd_p=getpwnam(unamep);
|
||
if (pwd_p == NULL) {
|
||
/*
|
||
* uname not in passwd file. if valid numeric
|
||
* uid, ok. Otherwise, error
|
||
*/
|
||
p = unamep;
|
||
if ((sscanf(unamep, "%d%s", &uid, name) == 1) &&
|
||
(uid < MAXUID) && (uid >= 0)) {
|
||
*id = (ushort)uid;
|
||
*type |= USER;
|
||
return argp;
|
||
} else {
|
||
FILE_PRINT();
|
||
pfmt(stderr, MM_ERROR, UNKUSER, unamep);
|
||
exit(32);
|
||
}
|
||
} else {
|
||
*id = (ushort) pwd_p->pw_uid;
|
||
*type |= USER;
|
||
return argp;
|
||
}
|
||
} else if ((strcmp(unamep,"group") == 0) || (strcmp(unamep,"g") == 0)) {
|
||
/*
|
||
* ae_type is GROUP_OBJ or GROUP
|
||
*/
|
||
if (ret == 0)
|
||
*(argp-1) = ':'; /* for tnamep */
|
||
if (*argp == '\0') {
|
||
FILE_PRINT();
|
||
pfmt(stderr, MM_ERROR, ILLEGALOPT, tnamep);
|
||
usage();
|
||
exit(1);
|
||
}
|
||
gnamep = argp;
|
||
if (*gnamep == ':') {
|
||
if (delim == ',') { /* -d option */
|
||
gnamep++;
|
||
if (*gnamep && *gnamep != ',') {
|
||
FILE_PRINT();
|
||
pfmt(stderr, MM_ERROR, ILLEGALOPT,
|
||
tnamep);
|
||
usage();
|
||
exit(1);
|
||
}
|
||
|
||
}
|
||
*type |= GROUP_OBJ;
|
||
return ++gnamep;
|
||
}
|
||
ret = skipc(&argp, delim);
|
||
grp_p=getgrnam(gnamep);
|
||
if (grp_p == NULL) {
|
||
/*
|
||
* gname not in group file. if valid numeric
|
||
* gid, ok. Otherwise, error
|
||
*/
|
||
if ((sscanf(gnamep, "%d%s", &gid, name) == 1) &&
|
||
(gid < MAXUID) && (gid >= 0)) {
|
||
*id = (ushort)gid;
|
||
*type |= GROUP;
|
||
return argp;
|
||
} else {
|
||
FILE_PRINT();
|
||
pfmt(stderr, MM_ERROR, UNKGROUP, gnamep);
|
||
exit(32);
|
||
}
|
||
} else {
|
||
*id = (ushort)grp_p->gr_gid;
|
||
*type |= GROUP;
|
||
return argp;
|
||
}
|
||
} else if ((strcmp(unamep,"class") == 0) || (strcmp(unamep,"c") == 0)) { /*
|
||
* ae_type is CLASS_OBJ
|
||
*/
|
||
if (ret == 0)
|
||
*(argp-1) = ':'; /* for tnamep */
|
||
if (ret || (delim == ',' && *argp && *argp != ',')) {
|
||
FILE_PRINT();
|
||
pfmt(stderr, MM_ERROR, ILLEGALOPT, tnamep);
|
||
usage();
|
||
exit(1);
|
||
}
|
||
if (delim == ',')
|
||
argp++;
|
||
*type |= CLASS_OBJ;
|
||
return argp;
|
||
} else if ((strcmp(unamep,"other") == 0) || (strcmp(unamep,"o") == 0)) {
|
||
/*
|
||
* ae_type is OTHER_OBJ
|
||
*/
|
||
if (ret == 0)
|
||
*(argp-1) = ':'; /* for tnamep */
|
||
if (ret || (delim == ',' && *argp && *argp != ',')) {
|
||
FILE_PRINT();
|
||
pfmt(stderr, MM_ERROR, ILLEGALOPT, tnamep);
|
||
usage();
|
||
exit(1);
|
||
}
|
||
if (delim == ',')
|
||
argp++;
|
||
*type |= OTHER_OBJ;
|
||
return argp;
|
||
}
|
||
|
||
/*
|
||
* If we get this far, illegal option
|
||
*/
|
||
|
||
if (*argp == '\0') {
|
||
FILE_PRINT();
|
||
pfmt(stderr, MM_ERROR, ILLEGALOPT, tnamep);
|
||
usage();
|
||
exit(1);
|
||
}
|
||
FILE_PRINT();
|
||
pfmt(stderr, MM_ERROR, UNKTYPE, tnamep);
|
||
exit(32);
|
||
}
|
||
|
||
/*
|
||
* Procedure: scanperms
|
||
*
|
||
* Restrictions:
|
||
pfmt: none
|
||
*/
|
||
/*
|
||
*
|
||
* scanperms - scan the argument string
|
||
* for an expression specifying
|
||
* permissions for the file or
|
||
* the ACL entry.
|
||
*
|
||
* input - a ptr to a ptr to the argument string,
|
||
* a ptr to the variable which
|
||
* will receive the permissions.
|
||
* the trailing delimiter of the permissions:
|
||
* currently either a comma or a blank
|
||
*
|
||
* output - return code from skipc() routine:
|
||
* 0 if trailing delimiter found,
|
||
* 1 if space or tab found,
|
||
* 2 if null found,
|
||
* -1 if newline found
|
||
*
|
||
*/
|
||
int
|
||
scanperms(argpp, permp, delim)
|
||
char **argpp;
|
||
ushort *permp;
|
||
char delim;
|
||
{
|
||
char *argp = *argpp;
|
||
char *p; /* for scanning characters */
|
||
char *cmodep; /* ptr to start of perm characters */
|
||
int permchars = 0; /* # of perm characters so far */
|
||
int rchar = 0; /* non-zero if "r" specified */
|
||
int wchar = 0; /* non-zero if "w" specified */
|
||
int xchar = 0; /* non-zero if "x" specified */
|
||
int ret;
|
||
ushort perms = 0;
|
||
|
||
if (argp && *argp) {
|
||
if ((*argp >= '0') && (*argp <= '7')) {
|
||
ret = omode(&argp, permp, delim);
|
||
*argpp = argp;
|
||
return (ret);
|
||
}
|
||
p = cmodep = argp;
|
||
ret = skipc(&argp, delim);
|
||
while (*p) {
|
||
switch (*p++) { /* scan for "perm" */
|
||
case 'r':
|
||
if (rchar) {
|
||
FILE_PRINT();
|
||
pfmt(stderr, MM_ERROR, UNKPERM, cmodep);
|
||
exit(32);
|
||
}
|
||
perms |= AREAD;
|
||
rchar++;
|
||
break;
|
||
case 'w':
|
||
if (wchar) {
|
||
FILE_PRINT();
|
||
pfmt(stderr, MM_ERROR, UNKPERM, cmodep);
|
||
exit(32);
|
||
}
|
||
wchar++;
|
||
perms |= AWRITE;
|
||
break;
|
||
case 'x':
|
||
if (xchar) {
|
||
FILE_PRINT();
|
||
pfmt(stderr, MM_ERROR, UNKPERM, cmodep);
|
||
exit(32);
|
||
}
|
||
xchar++;
|
||
perms |= AEXEC;
|
||
break;
|
||
case '-':
|
||
break;
|
||
default:
|
||
FILE_PRINT();
|
||
pfmt(stderr, MM_ERROR, UNKPERM, cmodep);
|
||
exit(32);
|
||
break;
|
||
} /* end switch to scan for "perm" */
|
||
permchars++;
|
||
} /* end while */
|
||
if (permchars < 1 || permchars > 3) {
|
||
FILE_PRINT();
|
||
pfmt(stderr, MM_ERROR, UNKPERM, cmodep);
|
||
exit(32);
|
||
}
|
||
*permp = perms;
|
||
*argpp = argp;
|
||
return (ret);
|
||
} /* end if argp */
|
||
else {
|
||
FILE_PRINT();
|
||
pfmt(stderr, MM_ERROR, UNKPERM, argp);
|
||
exit(32);
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Procedure: omode
|
||
*
|
||
* Restrictions:
|
||
pfmt: none
|
||
*/
|
||
/*
|
||
*
|
||
* omode - scan the argument string for an
|
||
* octal permissions expresssion
|
||
*
|
||
* input - a ptr to a ptr to the argument string
|
||
* a ptr to the variable which
|
||
* will receive the permissions
|
||
* the trailing delimiter of permissions:
|
||
* currently either a comma or a blank
|
||
*
|
||
* output - return value from skipc:
|
||
* 0 if character found,
|
||
* 1 if blank or tab found,
|
||
* 2 if null found,
|
||
* -1 if newline found
|
||
*
|
||
*/
|
||
int
|
||
omode(argpp, permp, delim)
|
||
char **argpp;
|
||
ushort *permp;
|
||
char delim;
|
||
{
|
||
register int c;
|
||
char *argp = *argpp;
|
||
char *p;
|
||
int ret;
|
||
p = argp; /* save pointer to octal mode */
|
||
ret = skipc(&argp, delim);
|
||
if (((c = *p) < '0') || (c > '7') || *(p+1)) {
|
||
FILE_PRINT();
|
||
pfmt(stderr, MM_ERROR, UNKPERM, p);
|
||
exit(32);
|
||
}
|
||
*permp = (ushort)(c - '0');
|
||
*argpp = argp;
|
||
return(ret);
|
||
}
|
||
|
||
|
||
/*
|
||
* Procedure: skipc
|
||
*
|
||
* Restrictions:
|
||
*/
|
||
/*
|
||
* skipc - skip characters in string pointed to by p
|
||
* until the char in c or '\n' or '\0'
|
||
* when the char in c or '\n' is found,
|
||
* replace it with a '\0'
|
||
*
|
||
* input - pointer to pointer to the argument string
|
||
* the character to search for
|
||
*
|
||
* output - zero if character found,
|
||
* 1 if space or tab found,
|
||
* 2 if null found,
|
||
* -1 if newline found
|
||
*/
|
||
int
|
||
skipc(pp, c)
|
||
register char **pp;
|
||
char c;
|
||
{
|
||
register char *p = *pp;
|
||
int ret;
|
||
|
||
while (*p && *p != c && *p != '\n' && *p != '\t' && *p != ' ')
|
||
++p;
|
||
if (*p == '\n') {
|
||
*p = '\0';
|
||
ret = -1;
|
||
} else if (*p == ' ' || *p == '\t') {
|
||
*p = '\0';
|
||
ret = 1;
|
||
} else if (*p) {
|
||
*p++ = '\0';
|
||
ret = 0;
|
||
} else
|
||
ret = 2;
|
||
*pp = p;
|
||
return(ret);
|
||
}
|
||
|
||
|
||
/*
|
||
* Procedure: delacl
|
||
*
|
||
* Restrictions:
|
||
pfmt: none
|
||
*/
|
||
/*
|
||
* delacl - deletes the acl entries in the first list
|
||
* marked for deletion from the second list
|
||
*
|
||
* input - 1. ACL operations buffer with entries
|
||
* to be deleted or modified
|
||
* 2. count of entries to be deleted or modified
|
||
* 3. ACL buffer with entries from file
|
||
* 4. pointer to count of file's entries
|
||
* 5. file name
|
||
*
|
||
* output - zero on success, -1 on failure
|
||
*
|
||
*/
|
||
|
||
int
|
||
delacl(daclopbp, dentries, aclp, nentriesp, fname)
|
||
struct aclops *daclopbp;
|
||
int dentries;
|
||
struct acl_entry *aclp;
|
||
int *nentriesp;
|
||
char *fname;
|
||
{
|
||
struct aclops *aclopsp = daclopbp;
|
||
struct acl_entry *tgtaclp, *srcaclp;
|
||
void acltochar();
|
||
int i, j, k, match;
|
||
int entries = *nentriesp;
|
||
char aclentry[MRECLEN];
|
||
|
||
tgtaclp = aclp;
|
||
for (i = 0; i < dentries; i++, aclopsp++) {
|
||
if (aclopsp->a_op != ACL_DEL)
|
||
continue;
|
||
match = NOMATCH;
|
||
for (j = 0; j < entries; j++, tgtaclp++) {
|
||
if (aclopsp->a_acl.ae_type == tgtaclp->ae_type) {
|
||
switch(aclopsp->a_acl.ae_type) {
|
||
case USER_OBJ:
|
||
case GROUP_OBJ:
|
||
case CLASS_OBJ:
|
||
case OTHER_OBJ:
|
||
case DEF_USER_OBJ:
|
||
case DEF_GROUP_OBJ:
|
||
case DEF_CLASS_OBJ:
|
||
case DEF_OTHER_OBJ:
|
||
match++;
|
||
break;
|
||
case USER:
|
||
case GROUP:
|
||
case DEF_USER:
|
||
case DEF_GROUP:
|
||
if (aclopsp->a_acl.ae_id ==
|
||
tgtaclp->ae_id)
|
||
match++;
|
||
break;
|
||
default:
|
||
/* This can't really happen */
|
||
pfmt(stderr, MM_ERROR, ILLEGALOPT2);
|
||
exit(32);
|
||
} /* end switch */
|
||
if (match) {
|
||
/* found a match !! remove acl entry */
|
||
/* and compress buffer */
|
||
srcaclp = tgtaclp + 1;
|
||
for (k = j + 1; k < entries; k++)
|
||
*tgtaclp++ = *srcaclp++;
|
||
entries--;
|
||
break; /* out of j-loop */
|
||
}
|
||
} /* end if type equal */
|
||
} /* end for "j" */
|
||
if (!match) {
|
||
/* did not find a match ! */
|
||
acltochar(&aclopsp->a_acl, aclentry);
|
||
pfmt(stderr, MM_ERROR, NOMATCHFOUND, fname, aclentry);
|
||
return (-1);
|
||
}
|
||
tgtaclp = aclp;
|
||
} /* end for "i" */
|
||
*nentriesp = entries;
|
||
return (0);
|
||
}
|
||
|
||
|
||
/*
|
||
* Procedure: modacl
|
||
*
|
||
* Restrictions:
|
||
pfmt: none
|
||
*/
|
||
/*
|
||
* modacl - All ACL entries in the first buffer which are marked
|
||
* for modification are modified in second buffer or added
|
||
* to the buffer.
|
||
*
|
||
* input - 1. ACL operations buffer with entries
|
||
* to be deleted or modified
|
||
* 2. count of entries to be deleted or modified
|
||
* 3. Ptr to ptr to ACL buffer with entries from file
|
||
* 4. Pointer to number of entries which will fit in ACL buffer.
|
||
* 5. pointer to count of file's entries
|
||
*
|
||
* output - zero on success, -1 on failure
|
||
*
|
||
*/
|
||
int
|
||
modacl(maclopbp, mentries, aclpp, bufentriesp, nentriesp)
|
||
struct aclops *maclopbp; /* buffer of entries to modify */
|
||
int mentries; /* number of entries to modify */
|
||
struct acl_entry **aclpp;/* buffer of current ACL entries on file */
|
||
int *bufentriesp; /* max no. entries in current ACL buffer */
|
||
int *nentriesp; /* current no. entries in ACL buffer */
|
||
{
|
||
struct aclops *aclopsp = maclopbp; /* start of acls to modify */
|
||
struct acl_entry *aclp = *aclpp;
|
||
struct acl_entry *srcaclp;
|
||
struct acl_entry *tgtaclp = aclp;
|
||
struct acl_entry *newaclp; /* new acl buffer with mods */
|
||
char *malloc();
|
||
int i, j;
|
||
int add_entries = 0; /* ACL entries to add to file */
|
||
int entries = *nentriesp;
|
||
int bentries = *bufentriesp;
|
||
int newentries;
|
||
int buflen;
|
||
int match; /* entry found in file's ACL */
|
||
|
||
for (i = 0; i < mentries; i++, aclopsp++) {
|
||
if (aclopsp->a_op != ACL_MOD)
|
||
/* this entry is marked for deletion. skip it. */
|
||
continue;
|
||
match = NOMATCH;
|
||
for (j = 0; j < entries; j++, tgtaclp++) {
|
||
if (aclopsp->a_acl.ae_type == tgtaclp->ae_type) {
|
||
switch(aclopsp->a_acl.ae_type) {
|
||
case USER_OBJ:
|
||
case GROUP_OBJ:
|
||
case CLASS_OBJ:
|
||
case OTHER_OBJ:
|
||
case DEF_USER_OBJ:
|
||
case DEF_GROUP_OBJ:
|
||
case DEF_CLASS_OBJ:
|
||
case DEF_OTHER_OBJ:
|
||
tgtaclp->ae_perm = aclopsp->a_acl.ae_perm;
|
||
match++;
|
||
break;
|
||
case USER:
|
||
case GROUP:
|
||
case DEF_USER:
|
||
case DEF_GROUP:
|
||
if (aclopsp->a_acl.ae_id ==
|
||
tgtaclp->ae_id){
|
||
tgtaclp->ae_perm =
|
||
aclopsp->a_acl.ae_perm;
|
||
match++;
|
||
}
|
||
break;
|
||
default:
|
||
/* This can't really happen */
|
||
pfmt(stderr, MM_ERROR, ILLEGALOPT2);
|
||
exit(32);
|
||
} /* end switch */
|
||
} else
|
||
continue;
|
||
|
||
/* if match found, end search of file's ACL */
|
||
if (match)
|
||
break;
|
||
|
||
} /* end for "j" */
|
||
|
||
/* if no match, this entry will be added as is to file */
|
||
if (!match) {
|
||
aclopsp->a_op |= ACL_ADD;
|
||
add_entries++;
|
||
}
|
||
tgtaclp = aclp;
|
||
} /* end for "i" */
|
||
|
||
/* now check if any acl entries should be added to acl buffer */
|
||
if (add_entries) {
|
||
/*
|
||
* if the number of entries to be added will exceed
|
||
* the maximum number of entries that will fit in the
|
||
* buffer, allocate a new buffer
|
||
*/
|
||
if ((add_entries + entries) > bentries) {
|
||
newentries = add_entries + entries;
|
||
GROWACLBUF(newentries, bentries, newaclp, aclp,entries);
|
||
}
|
||
tgtaclp = aclp + entries;
|
||
entries += add_entries;
|
||
aclopsp = maclopbp;
|
||
for (i = 0; i < mentries; i++, aclopsp++)
|
||
/*
|
||
* search all -m entries, looking for those
|
||
* to be added to ACL. Add them to the buffer
|
||
* when they are found.
|
||
* Be sure to turn off "add" flag for next file.
|
||
*/
|
||
if ((aclopsp->a_op & ACL_ADD) != 0) {
|
||
*tgtaclp++ = aclopsp->a_acl;
|
||
aclopsp->a_op &= ~ACL_ADD;
|
||
}
|
||
} /* end if (mentries) */
|
||
*nentriesp = entries;
|
||
*bufentriesp = bentries;
|
||
*aclpp = aclp;
|
||
return (0);
|
||
}
|
||
|
||
/*
|
||
* Procedure: ckmandacls
|
||
*
|
||
* Restrictions:
|
||
*/
|
||
/*
|
||
*
|
||
* ckmandacls - validate that all required entries are in ACL buffer
|
||
*
|
||
* input - 1. number of entries in ACL buffer
|
||
* 2. pointer to ACL buffer
|
||
*
|
||
* output - 0 on success, -1 on failure
|
||
*/
|
||
int
|
||
ckmandacls(nentries, aclp)
|
||
int nentries;
|
||
struct acl_entry *aclp;
|
||
{
|
||
struct acl_entry *p;
|
||
int i;
|
||
int u_obj = 0;
|
||
int g_obj = 0;
|
||
int c_obj = 0;
|
||
int o_obj = 0;
|
||
|
||
for (i = 0, p = aclp; i < nentries; i++, p++) {
|
||
switch (p->ae_type) {
|
||
case USER_OBJ:
|
||
u_obj++;
|
||
break;
|
||
case GROUP_OBJ:
|
||
g_obj++;
|
||
break;
|
||
case CLASS_OBJ:
|
||
c_obj++;
|
||
break;
|
||
case OTHER_OBJ:
|
||
o_obj++;
|
||
break;
|
||
default:
|
||
break;
|
||
} /* end switch */
|
||
} /* end for */
|
||
if (!u_obj || !g_obj || !c_obj || !o_obj)
|
||
return -1;
|
||
else
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* Procedure: getacl
|
||
*
|
||
* Restrictions:
|
||
acl(2): none
|
||
pfmt: none
|
||
*/
|
||
/*
|
||
*
|
||
* getacl - get ACL entries from file
|
||
*
|
||
* input - 1. pointer to file name
|
||
* 2. pointer to pointer to ACL buffer
|
||
* 3. pointer to max number of entries ACL buffer will hold
|
||
* 4. pointer to number of entries in buffer
|
||
*
|
||
* output - zero on success, -1 on failure
|
||
*
|
||
*/
|
||
int
|
||
getacl(filep, aclpp, bufentriesp, nentriesp)
|
||
char *filep;
|
||
struct acl_entry **aclpp;
|
||
int *bufentriesp;
|
||
int *nentriesp;
|
||
{
|
||
struct acl_entry *aclp = *aclpp;
|
||
struct acl_entry *newaclp;
|
||
char *malloc();
|
||
int entries;
|
||
int bentries = *bufentriesp;
|
||
int newentries;
|
||
ushort bsize;
|
||
|
||
while ((*nentriesp = acl(filep, ACL_GET, bentries, aclp)) == -1) {
|
||
switch (errno) {
|
||
case ENOSPC:
|
||
newentries = bentries + 1;
|
||
GROWACLBUF(newentries, bentries, newaclp, aclp, 0);
|
||
break;
|
||
case EACCES:
|
||
pfmt(stderr, MM_ERROR, NOPERM, filep);
|
||
return (-1);
|
||
case ENOENT:
|
||
pfmt(stderr, MM_ERROR, NOFILEFOUND, filep);
|
||
return (-1);
|
||
case ENOPKG:
|
||
pfmt(stderr, MM_ERROR, NOINSTALL);
|
||
exit(3);
|
||
default:
|
||
pfmt(stderr, MM_ERROR, ACLFAIL, strerror(errno));
|
||
return (-1);
|
||
}
|
||
} /* end while */
|
||
*bufentriesp = bentries;
|
||
*aclpp = aclp;
|
||
return (0);
|
||
}
|
||
|
||
/*
|
||
* Procedure: putacls
|
||
*
|
||
* Restrictions:
|
||
acl(2): none
|
||
pfmt: none
|
||
*/
|
||
/*
|
||
*
|
||
* putacls - store ACLs on file
|
||
*
|
||
* input - 1. pointer to file name
|
||
* 2. pointer to ACL buffer
|
||
* 3. number of entries to store
|
||
* 4. continue flag on EINVAL from acl()
|
||
*
|
||
* output - zero on success, -1 on failure
|
||
*
|
||
*/
|
||
int
|
||
putacls(filep, aclp, nentries, cont)
|
||
char *filep;
|
||
struct acl *aclp;
|
||
int nentries;
|
||
int cont;
|
||
{
|
||
if (acl(filep, ACL_SET, nentries, aclp) == -1) {
|
||
switch(errno) {
|
||
case EPERM:
|
||
case EACCES:
|
||
pfmt(stderr, MM_ERROR, NOPERM, filep);
|
||
break;
|
||
case ENOSYS:
|
||
pfmt(stderr, MM_ERROR, BADENTRYTYPE, filep);
|
||
break;
|
||
case ENOENT:
|
||
pfmt(stderr, MM_ERROR, NOFILEFOUND, filep);
|
||
break;
|
||
case ENOTDIR:
|
||
pfmt(stderr, MM_ERROR, NODEFAULT, filep);
|
||
break;
|
||
case ENOPKG:
|
||
pfmt(stderr, MM_ERROR, NOINSTALL);
|
||
exit(3);
|
||
/* NOTREACHED */
|
||
break;
|
||
case EINVAL:
|
||
pfmt(stderr, MM_ERROR, ACLFAIL, filep, strerror(errno));
|
||
if (!cont)
|
||
exit(32);
|
||
break;
|
||
default:
|
||
pfmt(stderr, MM_ERROR, ACLFAIL, filep, strerror(errno));
|
||
break;
|
||
} /* end switch */
|
||
return (-1);
|
||
}
|
||
return (0);
|
||
}
|
||
|
||
/*
|
||
* Procedure: usage
|
||
*
|
||
* Restrictions:
|
||
pfmt: none
|
||
fprintf: none
|
||
*/
|
||
/* print Usage message */
|
||
void
|
||
usage ()
|
||
{
|
||
pfmt(stderr, MM_ACTION, ":98:\nusage: setacl [-r]\n");
|
||
pfmt(stderr, MM_NOSTD, ":99: [-m [[d[efault]:]u[ser]::operm | perm[,]]\n");
|
||
pfmt(stderr, MM_NOSTD, ":100: [[d[efault]:]u[ser]:uid:operm | perm[,...]]\n");
|
||
pfmt(stderr, MM_NOSTD, ":101: [[d[efault]:]g[roup]::operm | perm[,]]\n");
|
||
pfmt(stderr, MM_NOSTD, ":102: [[d[efault]:]g[roup]:gid:operm | perm[,...]]\n");
|
||
pfmt(stderr, MM_NOSTD, ":103: [[d[efault]:]c[lass]:operm | perm[,]]\n");
|
||
pfmt(stderr, MM_NOSTD, ":104: [[d[efault]:]o[ther]:operm | perm]]\n");
|
||
pfmt(stderr, MM_NOSTD, ":105: [-d [[d[efault]:]u[ser]:uid[,...]]\n");
|
||
pfmt(stderr, MM_NOSTD, ":106: [[d[efault]:]g[roup]:gid[,...]]\n");
|
||
pfmt(stderr, MM_NOSTD, ":107: [[d[efault]:]u[ser]::[,]]\n");
|
||
pfmt(stderr, MM_NOSTD, ":108: [[d[efault]:]g[roup]::[,]]\n");
|
||
pfmt(stderr, MM_NOSTD, ":109: [[d[efault]:]c[lass]:[,]]\n");
|
||
pfmt(stderr, MM_NOSTD, ":110: [[d[efault]:]o[ther]:[,]]]\n");
|
||
pfmt(stderr, MM_NOSTD, ":111: object(s)\n");
|
||
fprintf(stderr,"\n");
|
||
pfmt(stderr, MM_NOSTD, ":112: or\n");
|
||
fprintf(stderr,"\n");
|
||
pfmt(stderr, MM_NOSTD, ":113: setacl [-r]\n");
|
||
pfmt(stderr, MM_NOSTD, ":114: -s u[ser]::operm | perm[,]\n");
|
||
pfmt(stderr, MM_NOSTD, ":115: [d[efault]:u[ser]::operm | perm[,]]\n");
|
||
pfmt(stderr, MM_NOSTD, ":116: g[roup]::operm | perm[,]\n");
|
||
pfmt(stderr, MM_NOSTD, ":117: [d[efault]:g[roup]::operm | perm[,]]\n");
|
||
pfmt(stderr, MM_NOSTD, ":118: c[lass]:operm | perm[,]\n");
|
||
pfmt(stderr, MM_NOSTD, ":119: [d[efault]:c[lass]:operm | perm[,]]\n");
|
||
pfmt(stderr, MM_NOSTD, ":120: o[ther]:operm | perm[,]\n");
|
||
pfmt(stderr, MM_NOSTD, ":121: [d[efault]:o[ther]:operm | perm[,]]\n");
|
||
pfmt(stderr, MM_NOSTD, ":122: [[d[efault]:]u[ser]:uid:operm | perm[,...]]\n");
|
||
pfmt(stderr, MM_NOSTD, ":123: [[d[efault]:]g[roup]:gid:operm | perm[,...]]\n");
|
||
pfmt(stderr, MM_NOSTD, ":111: object(s)\n");
|
||
fprintf(stderr,"\n");
|
||
pfmt(stderr, MM_NOSTD, ":112: or\n");
|
||
fprintf(stderr,"\n");
|
||
pfmt(stderr, MM_NOSTD, ":124: setacl [-r] -f file_name object(s)\n");
|
||
}
|
||
|
||
/*
|
||
* Procedure: acltochar
|
||
*
|
||
* Restrictions:
|
||
getpwuid: None
|
||
getgrgid: None
|
||
*/
|
||
/*
|
||
*
|
||
*
|
||
* input - 1. pointer to ACL entry
|
||
* 2. pointer to character string
|
||
*
|
||
* output - none
|
||
*
|
||
*/
|
||
void
|
||
acltochar(aclp, entry)
|
||
struct acl_entry *aclp;
|
||
char *entry;
|
||
{
|
||
struct passwd *getpwuid(),*pwd_p;
|
||
struct group *getgrgid(),*grp_p;
|
||
int entry_type = aclp->ae_type;
|
||
|
||
if (entry_type & ACL_DEFAULT) {
|
||
entry += sprintf(entry, "default:");
|
||
entry_type &= ~ACL_DEFAULT;
|
||
}
|
||
switch (entry_type) {
|
||
case USER_OBJ:
|
||
sprintf(entry, "user::");
|
||
break;
|
||
case USER:
|
||
entry += sprintf(entry, "user:");
|
||
if ((pwd_p = getpwuid(aclp->ae_id)) != NULL)
|
||
sprintf(entry, "%s", pwd_p->pw_name);
|
||
else
|
||
sprintf(entry, "%d",aclp->ae_id);
|
||
break;
|
||
case GROUP_OBJ:
|
||
sprintf(entry, "group::");
|
||
break;
|
||
case GROUP:
|
||
entry += sprintf(entry, "group:");
|
||
if ((grp_p = getgrgid(aclp->ae_id)) != NULL)
|
||
sprintf(entry, "%s", grp_p->gr_name);
|
||
else
|
||
sprintf(entry, "%d", aclp->ae_id);
|
||
break;
|
||
case CLASS_OBJ:
|
||
sprintf(entry, "class:");
|
||
break;
|
||
case OTHER_OBJ:
|
||
sprintf(entry, "other:");
|
||
break;
|
||
default:
|
||
break;
|
||
} /* end switch */
|
||
}
|