43fa6fe319
identifier namespace by renaming non standard functions and variables such that they have a leading underscore. The library will use those names internally. Weak aliases are used to provide the original names to the API. This is only the first part of this change. It is most of the functions which are implemented in C for all NetBSD ports. Subsequent changes are to add the same support to the remaining C files, to assembly files, and to the automagically generated assembly source used for system calls. When all of the above is done, ports with weak alias support should add a definition for __weak_alias to <sys/cdefs.h>.
474 lines
11 KiB
C
474 lines
11 KiB
C
/* $NetBSD: setmode.c,v 1.17 1997/07/21 14:07:31 jtc Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 1989, 1993, 1994
|
|
* The Regents of the University of California. All rights reserved.
|
|
*
|
|
* This code is derived from software contributed to Berkeley by
|
|
* Dave Borman at Cray Research, Inc.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by the University of
|
|
* California, Berkeley and its contributors.
|
|
* 4. Neither the name of the University nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
#if defined(LIBC_SCCS) && !defined(lint)
|
|
#if 0
|
|
static char sccsid[] = "@(#)setmode.c 8.2 (Berkeley) 3/25/94";
|
|
#else
|
|
__RCSID("$NetBSD: setmode.c,v 1.17 1997/07/21 14:07:31 jtc Exp $");
|
|
#endif
|
|
#endif /* LIBC_SCCS and not lint */
|
|
|
|
#include "namespace.h"
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <signal.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
|
|
#ifdef SETMODE_DEBUG
|
|
#include <stdio.h>
|
|
#endif
|
|
|
|
#ifdef __weak_alias
|
|
__weak_alias(getmode,_getmode);
|
|
__weak_alias(setmode,_setmode);
|
|
#endif
|
|
|
|
#define SET_LEN 6 /* initial # of bitcmd struct to malloc */
|
|
#define SET_LEN_INCR 4 /* # of bitcmd structs to add as needed */
|
|
|
|
typedef struct bitcmd {
|
|
char cmd;
|
|
char cmd2;
|
|
mode_t bits;
|
|
} BITCMD;
|
|
|
|
#define CMD2_CLR 0x01
|
|
#define CMD2_SET 0x02
|
|
#define CMD2_GBITS 0x04
|
|
#define CMD2_OBITS 0x08
|
|
#define CMD2_UBITS 0x10
|
|
|
|
static BITCMD *addcmd __P((BITCMD *, int, int, int, u_int));
|
|
static void compress_mode __P((BITCMD *));
|
|
#ifdef SETMODE_DEBUG
|
|
static void dumpmode __P((BITCMD *));
|
|
#endif
|
|
|
|
/*
|
|
* Given the old mode and an array of bitcmd structures, apply the operations
|
|
* described in the bitcmd structures to the old mode, and return the new mode.
|
|
* Note that there is no '=' command; a strict assignment is just a '-' (clear
|
|
* bits) followed by a '+' (set bits).
|
|
*/
|
|
mode_t
|
|
getmode(bbox, omode)
|
|
const void *bbox;
|
|
mode_t omode;
|
|
{
|
|
register const BITCMD *set;
|
|
register mode_t clrval, newmode, value;
|
|
|
|
set = (const BITCMD *)bbox;
|
|
newmode = omode;
|
|
for (value = 0;; set++)
|
|
switch(set->cmd) {
|
|
/*
|
|
* When copying the user, group or other bits around, we "know"
|
|
* where the bits are in the mode so that we can do shifts to
|
|
* copy them around. If we don't use shifts, it gets real
|
|
* grundgy with lots of single bit checks and bit sets.
|
|
*/
|
|
case 'u':
|
|
value = (newmode & S_IRWXU) >> 6;
|
|
goto common;
|
|
|
|
case 'g':
|
|
value = (newmode & S_IRWXG) >> 3;
|
|
goto common;
|
|
|
|
case 'o':
|
|
value = newmode & S_IRWXO;
|
|
common: if (set->cmd2 & CMD2_CLR) {
|
|
clrval =
|
|
(set->cmd2 & CMD2_SET) ? S_IRWXO : value;
|
|
if (set->cmd2 & CMD2_UBITS)
|
|
newmode &= ~((clrval<<6) & set->bits);
|
|
if (set->cmd2 & CMD2_GBITS)
|
|
newmode &= ~((clrval<<3) & set->bits);
|
|
if (set->cmd2 & CMD2_OBITS)
|
|
newmode &= ~(clrval & set->bits);
|
|
}
|
|
if (set->cmd2 & CMD2_SET) {
|
|
if (set->cmd2 & CMD2_UBITS)
|
|
newmode |= (value<<6) & set->bits;
|
|
if (set->cmd2 & CMD2_GBITS)
|
|
newmode |= (value<<3) & set->bits;
|
|
if (set->cmd2 & CMD2_OBITS)
|
|
newmode |= value & set->bits;
|
|
}
|
|
break;
|
|
|
|
case '+':
|
|
newmode |= set->bits;
|
|
break;
|
|
|
|
case '-':
|
|
newmode &= ~set->bits;
|
|
break;
|
|
|
|
case 'X':
|
|
if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
|
|
newmode |= set->bits;
|
|
break;
|
|
|
|
case '\0':
|
|
default:
|
|
#ifdef SETMODE_DEBUG
|
|
(void)printf("getmode:%04o -> %04o\n", omode, newmode);
|
|
#endif
|
|
return (newmode);
|
|
}
|
|
}
|
|
|
|
#define ADDCMD(a, b, c, d) \
|
|
if (set >= endset) { \
|
|
register BITCMD *newset; \
|
|
setlen += SET_LEN_INCR; \
|
|
newset = realloc(saveset, sizeof(BITCMD) * setlen); \
|
|
if (!saveset) \
|
|
return (NULL); \
|
|
set = newset + (set - saveset); \
|
|
saveset = newset; \
|
|
endset = newset + (setlen - 2); \
|
|
} \
|
|
set = addcmd(set, (a), (b), (c), (d))
|
|
|
|
#define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
|
|
|
|
void *
|
|
setmode(p)
|
|
register const char *p;
|
|
{
|
|
register int perm, who;
|
|
register char op;
|
|
BITCMD *set, *saveset, *endset;
|
|
sigset_t sigset, sigoset;
|
|
mode_t mask;
|
|
int equalopdone = 0; /* pacify gcc */
|
|
int permXbits, setlen;
|
|
|
|
if (!*p)
|
|
return (NULL);
|
|
|
|
/*
|
|
* Get a copy of the mask for the permissions that are mask relative.
|
|
* Flip the bits, we want what's not set. Since it's possible that
|
|
* the caller is opening files inside a signal handler, protect them
|
|
* as best we can.
|
|
*/
|
|
sigfillset(&sigset);
|
|
(void)sigprocmask(SIG_BLOCK, &sigset, &sigoset);
|
|
(void)umask(mask = umask(0));
|
|
mask = ~mask;
|
|
(void)sigprocmask(SIG_SETMASK, &sigoset, NULL);
|
|
|
|
setlen = SET_LEN + 2;
|
|
|
|
if ((set = malloc((u_int)(sizeof(BITCMD) * setlen))) == NULL)
|
|
return (NULL);
|
|
saveset = set;
|
|
endset = set + (setlen - 2);
|
|
|
|
/*
|
|
* If an absolute number, get it and return; disallow non-octal digits
|
|
* or illegal bits.
|
|
*/
|
|
if (isdigit(*p)) {
|
|
perm = (mode_t)strtol(p, NULL, 8);
|
|
if (perm & ~(STANDARD_BITS|S_ISTXT)) {
|
|
free(saveset);
|
|
return (NULL);
|
|
}
|
|
while (*++p)
|
|
if (*p < '0' || *p > '7') {
|
|
free(saveset);
|
|
return (NULL);
|
|
}
|
|
ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask);
|
|
return (saveset);
|
|
}
|
|
|
|
/*
|
|
* Build list of structures to set/clear/copy bits as described by
|
|
* each clause of the symbolic mode.
|
|
*/
|
|
for (;;) {
|
|
/* First, find out which bits might be modified. */
|
|
for (who = 0;; ++p) {
|
|
switch (*p) {
|
|
case 'a':
|
|
who |= STANDARD_BITS;
|
|
break;
|
|
case 'u':
|
|
who |= S_ISUID|S_IRWXU;
|
|
break;
|
|
case 'g':
|
|
who |= S_ISGID|S_IRWXG;
|
|
break;
|
|
case 'o':
|
|
who |= S_IRWXO;
|
|
break;
|
|
default:
|
|
goto getop;
|
|
}
|
|
}
|
|
|
|
getop: if ((op = *p++) != '+' && op != '-' && op != '=') {
|
|
free(saveset);
|
|
return (NULL);
|
|
}
|
|
if (op == '=')
|
|
equalopdone = 0;
|
|
|
|
who &= ~S_ISTXT;
|
|
for (perm = 0, permXbits = 0;; ++p) {
|
|
switch (*p) {
|
|
case 'r':
|
|
perm |= S_IRUSR|S_IRGRP|S_IROTH;
|
|
break;
|
|
case 's':
|
|
/*
|
|
* If specific bits where requested and
|
|
* only "other" bits ignore set-id.
|
|
*/
|
|
if (who == 0 || (who & ~S_IRWXO))
|
|
perm |= S_ISUID|S_ISGID;
|
|
break;
|
|
case 't':
|
|
/*
|
|
* If specific bits where requested and
|
|
* only "other" bits ignore set-id.
|
|
*/
|
|
if (who == 0 || (who & ~S_IRWXO)) {
|
|
who |= S_ISTXT;
|
|
perm |= S_ISTXT;
|
|
}
|
|
break;
|
|
case 'w':
|
|
perm |= S_IWUSR|S_IWGRP|S_IWOTH;
|
|
break;
|
|
case 'X':
|
|
permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
|
|
break;
|
|
case 'x':
|
|
perm |= S_IXUSR|S_IXGRP|S_IXOTH;
|
|
break;
|
|
case 'u':
|
|
case 'g':
|
|
case 'o':
|
|
/*
|
|
* When ever we hit 'u', 'g', or 'o', we have
|
|
* to flush out any partial mode that we have,
|
|
* and then do the copying of the mode bits.
|
|
*/
|
|
if (perm) {
|
|
ADDCMD(op, who, perm, mask);
|
|
perm = 0;
|
|
}
|
|
if (op == '=')
|
|
equalopdone = 1;
|
|
if (op == '+' && permXbits) {
|
|
ADDCMD('X', who, permXbits, mask);
|
|
permXbits = 0;
|
|
}
|
|
ADDCMD(*p, who, op, mask);
|
|
break;
|
|
|
|
default:
|
|
/*
|
|
* Add any permissions that we haven't already
|
|
* done.
|
|
*/
|
|
if (perm || (op == '=' && !equalopdone)) {
|
|
if (op == '=')
|
|
equalopdone = 1;
|
|
ADDCMD(op, who, perm, mask);
|
|
perm = 0;
|
|
}
|
|
if (permXbits) {
|
|
ADDCMD('X', who, permXbits, mask);
|
|
permXbits = 0;
|
|
}
|
|
goto apply;
|
|
}
|
|
}
|
|
|
|
apply: if (!*p)
|
|
break;
|
|
if (*p != ',')
|
|
goto getop;
|
|
++p;
|
|
}
|
|
set->cmd = 0;
|
|
#ifdef SETMODE_DEBUG
|
|
(void)printf("Before compress_mode()\n");
|
|
dumpmode(saveset);
|
|
#endif
|
|
compress_mode(saveset);
|
|
#ifdef SETMODE_DEBUG
|
|
(void)printf("After compress_mode()\n");
|
|
dumpmode(saveset);
|
|
#endif
|
|
return (saveset);
|
|
}
|
|
|
|
static BITCMD *
|
|
addcmd(set, op, who, oparg, mask)
|
|
BITCMD *set;
|
|
register int oparg, who;
|
|
register int op;
|
|
u_int mask;
|
|
{
|
|
switch (op) {
|
|
case '=':
|
|
set->cmd = '-';
|
|
set->bits = who ? who : STANDARD_BITS;
|
|
set++;
|
|
|
|
op = '+';
|
|
/* FALLTHROUGH */
|
|
case '+':
|
|
case '-':
|
|
case 'X':
|
|
set->cmd = op;
|
|
set->bits = (who ? who : mask) & oparg;
|
|
break;
|
|
|
|
case 'u':
|
|
case 'g':
|
|
case 'o':
|
|
set->cmd = op;
|
|
if (who) {
|
|
set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) |
|
|
((who & S_IRGRP) ? CMD2_GBITS : 0) |
|
|
((who & S_IROTH) ? CMD2_OBITS : 0);
|
|
set->bits = ~0;
|
|
} else {
|
|
set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
|
|
set->bits = mask;
|
|
}
|
|
|
|
if (oparg == '+')
|
|
set->cmd2 |= CMD2_SET;
|
|
else if (oparg == '-')
|
|
set->cmd2 |= CMD2_CLR;
|
|
else if (oparg == '=')
|
|
set->cmd2 |= CMD2_SET|CMD2_CLR;
|
|
break;
|
|
}
|
|
return (set + 1);
|
|
}
|
|
|
|
#ifdef SETMODE_DEBUG
|
|
static void
|
|
dumpmode(set)
|
|
register BITCMD *set;
|
|
{
|
|
for (; set->cmd; ++set)
|
|
(void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n",
|
|
set->cmd, set->bits, set->cmd2 ? " cmd2:" : "",
|
|
set->cmd2 & CMD2_CLR ? " CLR" : "",
|
|
set->cmd2 & CMD2_SET ? " SET" : "",
|
|
set->cmd2 & CMD2_UBITS ? " UBITS" : "",
|
|
set->cmd2 & CMD2_GBITS ? " GBITS" : "",
|
|
set->cmd2 & CMD2_OBITS ? " OBITS" : "");
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Given an array of bitcmd structures, compress by compacting consecutive
|
|
* '+', '-' and 'X' commands into at most 3 commands, one of each. The 'u',
|
|
* 'g' and 'o' commands continue to be separate. They could probably be
|
|
* compacted, but it's not worth the effort.
|
|
*/
|
|
static void
|
|
compress_mode(set)
|
|
register BITCMD *set;
|
|
{
|
|
register BITCMD *nset;
|
|
register int setbits, clrbits, Xbits, op;
|
|
|
|
for (nset = set;;) {
|
|
/* Copy over any 'u', 'g' and 'o' commands. */
|
|
while ((op = nset->cmd) != '+' && op != '-' && op != 'X') {
|
|
*set++ = *nset++;
|
|
if (!op)
|
|
return;
|
|
}
|
|
|
|
for (setbits = clrbits = Xbits = 0;; nset++) {
|
|
if ((op = nset->cmd) == '-') {
|
|
clrbits |= nset->bits;
|
|
setbits &= ~nset->bits;
|
|
Xbits &= ~nset->bits;
|
|
} else if (op == '+') {
|
|
setbits |= nset->bits;
|
|
clrbits &= ~nset->bits;
|
|
Xbits &= ~nset->bits;
|
|
} else if (op == 'X')
|
|
Xbits |= nset->bits & ~setbits;
|
|
else
|
|
break;
|
|
}
|
|
if (clrbits) {
|
|
set->cmd = '-';
|
|
set->cmd2 = 0;
|
|
set->bits = clrbits;
|
|
set++;
|
|
}
|
|
if (setbits) {
|
|
set->cmd = '+';
|
|
set->cmd2 = 0;
|
|
set->bits = setbits;
|
|
set++;
|
|
}
|
|
if (Xbits) {
|
|
set->cmd = 'X';
|
|
set->cmd2 = 0;
|
|
set->bits = Xbits;
|
|
set++;
|
|
}
|
|
}
|
|
}
|