335 lines
7.8 KiB
C
335 lines
7.8 KiB
C
|
/* @(#)getperm.c 1.5 12/04/15 Copyright 2004-2009 J. Schilling */
|
||
|
#include <schily/mconfig.h>
|
||
|
#ifndef lint
|
||
|
static UConst char sccsid[] =
|
||
|
"@(#)getperm.c 1.5 12/04/15 Copyright 2004-2009 J. Schilling";
|
||
|
#endif
|
||
|
/*
|
||
|
* Parser for chmod(1)/find(1)-perm, ....
|
||
|
*
|
||
|
* Copyright (c) 2004-2009 J. Schilling
|
||
|
*/
|
||
|
/*
|
||
|
* 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.
|
||
|
*
|
||
|
* See the file CDDL.Schily.txt in this distribution for details.
|
||
|
*
|
||
|
* When distributing Covered Code, include this CDDL HEADER in each
|
||
|
* file and include the License file CDDL.Schily.txt from this distribution.
|
||
|
*/
|
||
|
|
||
|
#include <schily/stdio.h>
|
||
|
#include <schily/stat.h>
|
||
|
#include <schily/utypes.h>
|
||
|
#include <schily/standard.h>
|
||
|
#include <schily/schily.h>
|
||
|
|
||
|
#include <schily/nlsdefs.h>
|
||
|
|
||
|
EXPORT int getperm __PR((FILE *f, char *perm, char *opname, mode_t *modep, int smode, int flag));
|
||
|
LOCAL char *getsperm __PR((FILE *f, char *p, mode_t *mp, int smode, int flag));
|
||
|
LOCAL mode_t iswho __PR((int c));
|
||
|
LOCAL int isop __PR((int c));
|
||
|
LOCAL mode_t isperm __PR((int c, int isX));
|
||
|
|
||
|
/*
|
||
|
* This is the mode bit translation code stolen from star...
|
||
|
*/
|
||
|
#define TSUID 04000 /* Set UID on execution */
|
||
|
#define TSGID 02000 /* Set GID on execution */
|
||
|
#define TSVTX 01000 /* On directories, restricted deletion flag */
|
||
|
#define TUREAD 00400 /* Read by owner */
|
||
|
#define TUWRITE 00200 /* Write by owner special */
|
||
|
#define TUEXEC 00100 /* Execute/search by owner */
|
||
|
#define TGREAD 00040 /* Read by group */
|
||
|
#define TGWRITE 00020 /* Write by group */
|
||
|
#define TGEXEC 00010 /* Execute/search by group */
|
||
|
#define TOREAD 00004 /* Read by other */
|
||
|
#define TOWRITE 00002 /* Write by other */
|
||
|
#define TOEXEC 00001 /* Execute/search by other */
|
||
|
|
||
|
#define TALLMODES 07777 /* The low 12 bits mentioned in the standard */
|
||
|
|
||
|
#define S_ALLPERM (S_IRWXU|S_IRWXG|S_IRWXO)
|
||
|
#define S_ALLFLAGS (S_ISUID|S_ISGID|S_ISVTX)
|
||
|
#define S_ALLMODES (S_ALLFLAGS | S_ALLPERM)
|
||
|
|
||
|
#if S_ISUID == TSUID && S_ISGID == TSGID && S_ISVTX == TSVTX && \
|
||
|
S_IRUSR == TUREAD && S_IWUSR == TUWRITE && S_IXUSR == TUEXEC && \
|
||
|
S_IRGRP == TGREAD && S_IWGRP == TGWRITE && S_IXGRP == TGEXEC && \
|
||
|
S_IROTH == TOREAD && S_IWOTH == TOWRITE && S_IXOTH == TOEXEC
|
||
|
|
||
|
#define HAVE_POSIX_MODE_BITS /* st_mode bits are equal to TAR mode bits */
|
||
|
#endif
|
||
|
|
||
|
#ifdef HAVE_POSIX_MODE_BITS /* st_mode bits are equal to TAR mode bits */
|
||
|
#define OSMODE(xmode) (xmode)
|
||
|
#else
|
||
|
#define OSMODE(xmode) ((xmode & TSUID ? S_ISUID : 0) \
|
||
|
| (xmode & TSGID ? S_ISGID : 0) \
|
||
|
| (xmode & TSVTX ? S_ISVTX : 0) \
|
||
|
| (xmode & TUREAD ? S_IRUSR : 0) \
|
||
|
| (xmode & TUWRITE ? S_IWUSR : 0) \
|
||
|
| (xmode & TUEXEC ? S_IXUSR : 0) \
|
||
|
| (xmode & TGREAD ? S_IRGRP : 0) \
|
||
|
| (xmode & TGWRITE ? S_IWGRP : 0) \
|
||
|
| (xmode & TGEXEC ? S_IXGRP : 0) \
|
||
|
| (xmode & TOREAD ? S_IROTH : 0) \
|
||
|
| (xmode & TOWRITE ? S_IWOTH : 0) \
|
||
|
| (xmode & TOEXEC ? S_IXOTH : 0))
|
||
|
#endif
|
||
|
|
||
|
EXPORT int
|
||
|
getperm(f, perm, opname, modep, smode, flag)
|
||
|
FILE *f; /* FILE * to print error messages to */
|
||
|
char *perm; /* Perm string to parse */
|
||
|
char *opname; /* find(1) operator name / NULL */
|
||
|
mode_t *modep; /* The mode result */
|
||
|
int smode; /* The start mode for the computation */
|
||
|
int flag; /* Flags, see getperm() flag defs */
|
||
|
{
|
||
|
char *p;
|
||
|
Llong ll;
|
||
|
mode_t mm;
|
||
|
|
||
|
p = perm;
|
||
|
if ((flag & GP_FPERM) && *p == '-')
|
||
|
p++;
|
||
|
|
||
|
if (*p >= '0' && *p <= '7') {
|
||
|
p = astollb(p, &ll, 8);
|
||
|
if (*p) {
|
||
|
if (f) {
|
||
|
if (opname) {
|
||
|
ferrmsgno(f, EX_BAD,
|
||
|
gettext("Non octal character '%c' in '-%s %s'.\n"),
|
||
|
*p, opname, perm);
|
||
|
} else {
|
||
|
ferrmsgno(f, EX_BAD,
|
||
|
gettext("Non octal character '%c' in '%s'.\n"),
|
||
|
*p, perm);
|
||
|
}
|
||
|
}
|
||
|
return (-1);
|
||
|
}
|
||
|
mm = ll & TALLMODES;
|
||
|
*modep = OSMODE(mm);
|
||
|
return (0);
|
||
|
}
|
||
|
p = getsperm(f, p, modep, smode, flag);
|
||
|
if (p && *p != '\0') {
|
||
|
if (f) {
|
||
|
if (opname) {
|
||
|
ferrmsgno(f, EX_BAD,
|
||
|
gettext("Bad perm character '%c' found in '-%s %s'.\n"),
|
||
|
*p, opname, perm);
|
||
|
} else {
|
||
|
ferrmsgno(f, EX_BAD,
|
||
|
gettext("Bad perm character '%c' found in '%s'.\n"),
|
||
|
*p, perm);
|
||
|
}
|
||
|
}
|
||
|
return (-1);
|
||
|
}
|
||
|
#ifdef PERM_DEBUG
|
||
|
error("GETPERM (%c) %4.4lo\n", perm, (long)*modep);
|
||
|
#endif
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
LOCAL char *
|
||
|
getsperm(f, p, mp, smode, flag)
|
||
|
FILE *f;
|
||
|
char *p; /* The perm input string */
|
||
|
mode_t *mp; /* To set the mode */
|
||
|
int smode; /* The start mode for the computation */
|
||
|
int flag; /* Flags, see getperm() flag defs */
|
||
|
{
|
||
|
#ifdef OLD
|
||
|
mode_t permval = 0; /* POSIX start value for "find" */
|
||
|
#else
|
||
|
mode_t permval = smode; /* POSIX start value for "find" */
|
||
|
#endif
|
||
|
mode_t who;
|
||
|
mode_t m;
|
||
|
int op;
|
||
|
mode_t perms;
|
||
|
mode_t pm;
|
||
|
|
||
|
nextclause:
|
||
|
#ifdef PERM_DEBUG
|
||
|
error("getsperm(%s)\n", p);
|
||
|
#endif
|
||
|
who = 0;
|
||
|
while ((m = iswho(*p)) != 0) {
|
||
|
p++;
|
||
|
who |= m;
|
||
|
}
|
||
|
if (who == 0) {
|
||
|
mode_t mask;
|
||
|
|
||
|
if (flag & GP_UMASK) {
|
||
|
who = (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
|
||
|
} else {
|
||
|
umask(mask = umask(0));
|
||
|
who = ~mask;
|
||
|
who &= (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
|
||
|
}
|
||
|
}
|
||
|
#ifdef PERM_DEBUG
|
||
|
error("WHO %4.4lo\n", (long)who);
|
||
|
error("getsperm(--->%s)\n", p);
|
||
|
#endif
|
||
|
|
||
|
nextop:
|
||
|
if ((op = isop(*p)) != '\0')
|
||
|
p++;
|
||
|
#ifdef PERM_DEBUG
|
||
|
error("op '%c'\n", op);
|
||
|
error("getsperm(--->%s)\n", p);
|
||
|
#endif
|
||
|
if (op == 0) {
|
||
|
if (f) {
|
||
|
ferrmsgno(f, EX_BAD, gettext("Missing -perm op.\n"));
|
||
|
}
|
||
|
return (p);
|
||
|
}
|
||
|
|
||
|
flag &= ~(GP_FPERM|GP_UMASK);
|
||
|
if (flag & GP_XERR)
|
||
|
flag = -1;
|
||
|
perms = 0;
|
||
|
while ((pm = isperm(*p, flag)) != (mode_t)-1) {
|
||
|
p++;
|
||
|
perms |= pm;
|
||
|
}
|
||
|
#ifdef PERM_DEBUG
|
||
|
error("PERM %4.4lo\n", (long)perms);
|
||
|
error("START PERMVAL %4.4lo\n", (long)permval);
|
||
|
#endif
|
||
|
if ((perms == 0) && (*p == 'u' || *p == 'g' || *p == 'o')) {
|
||
|
mode_t what = 0;
|
||
|
|
||
|
/*
|
||
|
* First select the bit triple we like to copy.
|
||
|
*/
|
||
|
switch (*p) {
|
||
|
|
||
|
case 'u':
|
||
|
what = permval & S_IRWXU;
|
||
|
break;
|
||
|
case 'g':
|
||
|
what = permval & S_IRWXG;
|
||
|
break;
|
||
|
case 'o':
|
||
|
what = permval & S_IRWXO;
|
||
|
break;
|
||
|
}
|
||
|
/*
|
||
|
* Now copy over bit by bit without relying on shifts
|
||
|
* that would make implicit assumptions on values.
|
||
|
*/
|
||
|
if (what & (S_IRUSR|S_IRGRP|S_IROTH))
|
||
|
perms |= (who & (S_IRUSR|S_IRGRP|S_IROTH));
|
||
|
if (what & (S_IWUSR|S_IWGRP|S_IWOTH))
|
||
|
perms |= (who & (S_IWUSR|S_IWGRP|S_IWOTH));
|
||
|
if (what & (S_IXUSR|S_IXGRP|S_IXOTH))
|
||
|
perms |= (who & (S_IXUSR|S_IXGRP|S_IXOTH));
|
||
|
p++;
|
||
|
}
|
||
|
#ifdef PERM_DEBUG
|
||
|
error("getsperm(--->%s)\n", p);
|
||
|
#endif
|
||
|
switch (op) {
|
||
|
|
||
|
case '=':
|
||
|
permval &= ~who;
|
||
|
/* FALLTHRU */
|
||
|
case '+':
|
||
|
permval |= (who & perms);
|
||
|
break;
|
||
|
|
||
|
case '-':
|
||
|
permval &= ~(who & perms);
|
||
|
break;
|
||
|
}
|
||
|
#ifdef PERM_DEBUG
|
||
|
error("END PERMVAL %4.4lo\n", (long)permval);
|
||
|
#endif
|
||
|
if (isop(*p))
|
||
|
goto nextop;
|
||
|
if (*p == ',') {
|
||
|
p++;
|
||
|
goto nextclause;
|
||
|
}
|
||
|
*mp = permval;
|
||
|
return (p);
|
||
|
}
|
||
|
|
||
|
LOCAL mode_t
|
||
|
iswho(c)
|
||
|
int c;
|
||
|
{
|
||
|
switch (c) {
|
||
|
|
||
|
case 'u': /* user */
|
||
|
return (S_ISUID|S_ISVTX|S_IRWXU);
|
||
|
case 'g': /* group */
|
||
|
return (S_ISGID|S_ISVTX|S_IRWXG);
|
||
|
case 'o': /* other */
|
||
|
return (S_ISVTX|S_IRWXO);
|
||
|
case 'a': /* all */
|
||
|
return (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
|
||
|
default:
|
||
|
return (0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LOCAL int
|
||
|
isop(c)
|
||
|
int c; /* The current perm character to parse */
|
||
|
{
|
||
|
switch (c) {
|
||
|
|
||
|
case '+':
|
||
|
case '-':
|
||
|
case '=':
|
||
|
return (c);
|
||
|
default:
|
||
|
return (0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LOCAL mode_t
|
||
|
isperm(c, isX)
|
||
|
int c; /* The current perm character to parse */
|
||
|
int isX; /* -1: Ignore X, 0: no dir/X 1: X OK */
|
||
|
{
|
||
|
switch (c) {
|
||
|
|
||
|
case 'r':
|
||
|
return (S_IRUSR|S_IRGRP|S_IROTH);
|
||
|
case 'w':
|
||
|
return (S_IWUSR|S_IWGRP|S_IWOTH);
|
||
|
case 'X':
|
||
|
if (isX < 0)
|
||
|
return ((mode_t)-1); /* Singnal parse error */
|
||
|
if (isX == 0)
|
||
|
return ((mode_t)0); /* No 'X' handling here */
|
||
|
/* FALLTHRU */
|
||
|
case 'x':
|
||
|
return (S_IXUSR|S_IXGRP|S_IXOTH);
|
||
|
case 's':
|
||
|
return (S_ISUID|S_ISGID);
|
||
|
case 'l':
|
||
|
return (S_ISGID);
|
||
|
case 't':
|
||
|
return (S_ISVTX);
|
||
|
default:
|
||
|
return ((mode_t)-1);
|
||
|
}
|
||
|
}
|