Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/wapython
Path: blob/main/core/posix-wasm/src/lib/bsd/setmode.c
1067 views
1
/* $OpenBSD: setmode.c,v 1.22 2014/10/11 04:14:35 deraadt Exp $ */
2
/* $NetBSD: setmode.c,v 1.15 1997/02/07 22:21:06 christos Exp $ */
3
4
/*
5
* Copyright (c) 1989, 1993, 1994
6
* The Regents of the University of California. All rights reserved.
7
*
8
* This code is derived from software contributed to Berkeley by
9
* Dave Borman at Cray Research, Inc.
10
*
11
* Redistribution and use in source and binary forms, with or without
12
* modification, are permitted provided that the following conditions
13
* are met:
14
* 1. Redistributions of source code must retain the above copyright
15
* notice, this list of conditions and the following disclaimer.
16
* 2. Redistributions in binary form must reproduce the above copyright
17
* notice, this list of conditions and the following disclaimer in the
18
* documentation and/or other materials provided with the distribution.
19
* 3. Neither the name of the University nor the names of its contributors
20
* may be used to endorse or promote products derived from this software
21
* without specific prior written permission.
22
*
23
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33
* SUCH DAMAGE.
34
*/
35
36
#include "posix-wasm.h"
37
#include <sys/types.h>
38
#include <sys/stat.h>
39
40
#include <ctype.h>
41
#include <errno.h>
42
#include <signal.h>
43
#include <stdlib.h>
44
#include <unistd.h>
45
46
#ifdef SETMODE_DEBUG
47
#include <stdio.h>
48
#endif
49
50
#define SET_LEN 6 /* initial # of bitcmd struct to malloc */
51
#define SET_LEN_INCR 4 /* # of bitcmd structs to add as needed */
52
53
typedef struct bitcmd {
54
char cmd;
55
char cmd2;
56
mode_t bits;
57
} BITCMD;
58
59
#define CMD2_CLR 0x01
60
#define CMD2_SET 0x02
61
#define CMD2_GBITS 0x04
62
#define CMD2_OBITS 0x08
63
#define CMD2_UBITS 0x10
64
65
static BITCMD *addcmd(BITCMD *, int, int, int, u_int);
66
static void compress_mode(BITCMD *);
67
#ifdef SETMODE_DEBUG
68
static void dumpmode(BITCMD *);
69
#endif
70
71
/*
72
* Given the old mode and an array of bitcmd structures, apply the operations
73
* described in the bitcmd structures to the old mode, and return the new mode.
74
* Note that there is no '=' command; a strict assignment is just a '-' (clear
75
* bits) followed by a '+' (set bits).
76
*/
77
mode_t
78
getmode(const void *bbox, mode_t omode)
79
{
80
const BITCMD *set;
81
mode_t clrval, newmode, value;
82
83
set = (const BITCMD *)bbox;
84
newmode = omode;
85
for (value = 0;; set++)
86
switch(set->cmd) {
87
/*
88
* When copying the user, group or other bits around, we "know"
89
* where the bits are in the mode so that we can do shifts to
90
* copy them around. If we don't use shifts, it gets real
91
* grundgy with lots of single bit checks and bit sets.
92
*/
93
case 'u':
94
value = (newmode & S_IRWXU) >> 6;
95
goto common;
96
97
case 'g':
98
value = (newmode & S_IRWXG) >> 3;
99
goto common;
100
101
case 'o':
102
value = newmode & S_IRWXO;
103
common: if (set->cmd2 & CMD2_CLR) {
104
clrval =
105
(set->cmd2 & CMD2_SET) ? S_IRWXO : value;
106
if (set->cmd2 & CMD2_UBITS)
107
newmode &= ~((clrval<<6) & set->bits);
108
if (set->cmd2 & CMD2_GBITS)
109
newmode &= ~((clrval<<3) & set->bits);
110
if (set->cmd2 & CMD2_OBITS)
111
newmode &= ~(clrval & set->bits);
112
}
113
if (set->cmd2 & CMD2_SET) {
114
if (set->cmd2 & CMD2_UBITS)
115
newmode |= (value<<6) & set->bits;
116
if (set->cmd2 & CMD2_GBITS)
117
newmode |= (value<<3) & set->bits;
118
if (set->cmd2 & CMD2_OBITS)
119
newmode |= value & set->bits;
120
}
121
break;
122
123
case '+':
124
newmode |= set->bits;
125
break;
126
127
case '-':
128
newmode &= ~set->bits;
129
break;
130
131
case 'X':
132
if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
133
newmode |= set->bits;
134
break;
135
136
case '\0':
137
default:
138
#ifdef SETMODE_DEBUG
139
(void)printf("getmode:%04o -> %04o\n", omode, newmode);
140
#endif
141
return (newmode);
142
}
143
}
144
145
#define ADDCMD(a, b, c, d) \
146
if (set >= endset) { \
147
BITCMD *newset; \
148
setlen += SET_LEN_INCR; \
149
newset = reallocarray(saveset, setlen, sizeof(BITCMD)); \
150
if (newset == NULL) { \
151
free(saveset); \
152
return (NULL); \
153
} \
154
set = newset + (set - saveset); \
155
saveset = newset; \
156
endset = newset + (setlen - 2); \
157
} \
158
set = addcmd(set, (a), (b), (c), (d))
159
160
#define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
161
162
void *
163
setmode(const char *p)
164
{
165
char op, *ep;
166
BITCMD *set, *saveset, *endset;
167
sigset_t sigset, sigoset;
168
mode_t mask, perm, permXbits, who;
169
int equalopdone, setlen;
170
u_long perml;
171
172
if (!*p) {
173
errno = EINVAL;
174
return (NULL);
175
}
176
177
/*
178
* Get a copy of the mask for the permissions that are mask relative.
179
* Flip the bits, we want what's not set. Since it's possible that
180
* the caller is opening files inside a signal handler, protect them
181
* as best we can.
182
*/
183
sigfillset(&sigset);
184
(void)sigprocmask(SIG_BLOCK, &sigset, &sigoset);
185
(void)umask(mask = umask(0));
186
mask = ~mask;
187
(void)sigprocmask(SIG_SETMASK, &sigoset, NULL);
188
189
setlen = SET_LEN + 2;
190
191
if ((set = calloc((u_int)sizeof(BITCMD), setlen)) == NULL)
192
return (NULL);
193
saveset = set;
194
endset = set + (setlen - 2);
195
196
/*
197
* If an absolute number, get it and return; disallow non-octal digits
198
* or illegal bits.
199
*/
200
if (isdigit((unsigned char)*p)) {
201
perml = strtoul(p, &ep, 8);
202
/* The test on perml will also catch overflow. */
203
if (*ep != '\0' || (perml & ~(STANDARD_BITS|S_ISTXT))) {
204
free(saveset);
205
errno = ERANGE;
206
return (NULL);
207
}
208
perm = (mode_t)perml;
209
ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask);
210
set->cmd = 0;
211
return (saveset);
212
}
213
214
/*
215
* Build list of structures to set/clear/copy bits as described by
216
* each clause of the symbolic mode.
217
*/
218
for (;;) {
219
/* First, find out which bits might be modified. */
220
for (who = 0;; ++p) {
221
switch (*p) {
222
case 'a':
223
who |= STANDARD_BITS;
224
break;
225
case 'u':
226
who |= S_ISUID|S_IRWXU;
227
break;
228
case 'g':
229
who |= S_ISGID|S_IRWXG;
230
break;
231
case 'o':
232
who |= S_IRWXO;
233
break;
234
default:
235
goto getop;
236
}
237
}
238
239
getop: if ((op = *p++) != '+' && op != '-' && op != '=') {
240
free(saveset);
241
errno = EINVAL;
242
return (NULL);
243
}
244
if (op == '=')
245
equalopdone = 0;
246
247
who &= ~S_ISTXT;
248
for (perm = 0, permXbits = 0;; ++p) {
249
switch (*p) {
250
case 'r':
251
perm |= S_IRUSR|S_IRGRP|S_IROTH;
252
break;
253
case 's':
254
/*
255
* If specific bits where requested and
256
* only "other" bits ignore set-id.
257
*/
258
if (who == 0 || (who & ~S_IRWXO))
259
perm |= S_ISUID|S_ISGID;
260
break;
261
case 't':
262
/*
263
* If specific bits where requested and
264
* only "other" bits ignore sticky.
265
*/
266
if (who == 0 || (who & ~S_IRWXO)) {
267
who |= S_ISTXT;
268
perm |= S_ISTXT;
269
}
270
break;
271
case 'w':
272
perm |= S_IWUSR|S_IWGRP|S_IWOTH;
273
break;
274
case 'X':
275
permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
276
break;
277
case 'x':
278
perm |= S_IXUSR|S_IXGRP|S_IXOTH;
279
break;
280
case 'u':
281
case 'g':
282
case 'o':
283
/*
284
* When ever we hit 'u', 'g', or 'o', we have
285
* to flush out any partial mode that we have,
286
* and then do the copying of the mode bits.
287
*/
288
if (perm) {
289
ADDCMD(op, who, perm, mask);
290
perm = 0;
291
}
292
if (op == '=')
293
equalopdone = 1;
294
if (op == '+' && permXbits) {
295
ADDCMD('X', who, permXbits, mask);
296
permXbits = 0;
297
}
298
ADDCMD(*p, who, op, mask);
299
break;
300
301
default:
302
/*
303
* Add any permissions that we haven't already
304
* done.
305
*/
306
if (perm || (op == '=' && !equalopdone)) {
307
if (op == '=')
308
equalopdone = 1;
309
ADDCMD(op, who, perm, mask);
310
perm = 0;
311
}
312
if (permXbits) {
313
ADDCMD('X', who, permXbits, mask);
314
permXbits = 0;
315
}
316
goto apply;
317
}
318
}
319
320
apply: if (!*p)
321
break;
322
if (*p != ',')
323
goto getop;
324
++p;
325
}
326
set->cmd = 0;
327
#ifdef SETMODE_DEBUG
328
(void)printf("Before compress_mode()\n");
329
dumpmode(saveset);
330
#endif
331
compress_mode(saveset);
332
#ifdef SETMODE_DEBUG
333
(void)printf("After compress_mode()\n");
334
dumpmode(saveset);
335
#endif
336
return (saveset);
337
}
338
339
static BITCMD *
340
addcmd(BITCMD *set, int op, int who, int oparg, u_int mask)
341
{
342
switch (op) {
343
case '=':
344
set->cmd = '-';
345
set->bits = who ? who : STANDARD_BITS;
346
set++;
347
348
op = '+';
349
/* FALLTHROUGH */
350
case '+':
351
case '-':
352
case 'X':
353
set->cmd = op;
354
set->bits = (who ? who : mask) & oparg;
355
break;
356
357
case 'u':
358
case 'g':
359
case 'o':
360
set->cmd = op;
361
if (who) {
362
set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) |
363
((who & S_IRGRP) ? CMD2_GBITS : 0) |
364
((who & S_IROTH) ? CMD2_OBITS : 0);
365
set->bits = (mode_t)~0;
366
} else {
367
set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
368
set->bits = mask;
369
}
370
371
if (oparg == '+')
372
set->cmd2 |= CMD2_SET;
373
else if (oparg == '-')
374
set->cmd2 |= CMD2_CLR;
375
else if (oparg == '=')
376
set->cmd2 |= CMD2_SET|CMD2_CLR;
377
break;
378
}
379
return (set + 1);
380
}
381
382
#ifdef SETMODE_DEBUG
383
static void
384
dumpmode(BITCMD *set)
385
{
386
for (; set->cmd; ++set)
387
(void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n",
388
set->cmd, set->bits, set->cmd2 ? " cmd2:" : "",
389
set->cmd2 & CMD2_CLR ? " CLR" : "",
390
set->cmd2 & CMD2_SET ? " SET" : "",
391
set->cmd2 & CMD2_UBITS ? " UBITS" : "",
392
set->cmd2 & CMD2_GBITS ? " GBITS" : "",
393
set->cmd2 & CMD2_OBITS ? " OBITS" : "");
394
}
395
#endif
396
397
/*
398
* Given an array of bitcmd structures, compress by compacting consecutive
399
* '+', '-' and 'X' commands into at most 3 commands, one of each. The 'u',
400
* 'g' and 'o' commands continue to be separate. They could probably be
401
* compacted, but it's not worth the effort.
402
*/
403
static void
404
compress_mode(BITCMD *set)
405
{
406
BITCMD *nset;
407
int setbits, clrbits, Xbits, op;
408
409
for (nset = set;;) {
410
/* Copy over any 'u', 'g' and 'o' commands. */
411
while ((op = nset->cmd) != '+' && op != '-' && op != 'X') {
412
*set++ = *nset++;
413
if (!op)
414
return;
415
}
416
417
for (setbits = clrbits = Xbits = 0;; nset++) {
418
if ((op = nset->cmd) == '-') {
419
clrbits |= nset->bits;
420
setbits &= ~nset->bits;
421
Xbits &= ~nset->bits;
422
} else if (op == '+') {
423
setbits |= nset->bits;
424
clrbits &= ~nset->bits;
425
Xbits &= ~nset->bits;
426
} else if (op == 'X')
427
Xbits |= nset->bits & ~setbits;
428
else
429
break;
430
}
431
if (clrbits) {
432
set->cmd = '-';
433
set->cmd2 = 0;
434
set->bits = clrbits;
435
set++;
436
}
437
if (setbits) {
438
set->cmd = '+';
439
set->cmd2 = 0;
440
set->bits = setbits;
441
set++;
442
}
443
if (Xbits) {
444
set->cmd = 'X';
445
set->cmd2 = 0;
446
set->bits = Xbits;
447
set++;
448
}
449
}
450
}
451
452