1 /* @(#)getperm.c 1.7 18/08/30 Copyright 2004-2018 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)getperm.c 1.7 18/08/30 Copyright 2004-2018 J. Schilling";
6 #endif
7 /*
8 * Parser for chmod(1)/find(1)/umask(1)-perm, ....
9 *
10 * Copyright (c) 2004-2018 J. Schilling
11 */
12 /*
13 * The contents of this file are subject to the terms of the
14 * Common Development and Distribution License, Version 1.0 only
15 * (the "License"). You may not use this file except in compliance
16 * with the License.
17 *
18 * See the file CDDL.Schily.txt in this distribution for details.
19 * A copy of the CDDL is also available via the Internet at
20 * http://www.opensource.org/licenses/cddl1.txt
21 *
22 * When distributing Covered Code, include this CDDL HEADER in each
23 * file and include the License file CDDL.Schily.txt from this distribution.
24 */
25
26 #include <schily/stdio.h>
27 #include <schily/stat.h>
28 #include <schily/utypes.h>
29 #include <schily/standard.h>
30 #include <schily/schily.h>
31
32 #include <schily/nlsdefs.h>
33
34 EXPORT int getperm __PR((FILE *f, char *perm, char *opname,
35 mode_t *modep, int smode, int flag));
36 LOCAL char *getsperm __PR((FILE *f, char *p, char *opname,
37 mode_t *mp, int smode, int flag));
38 LOCAL mode_t iswho __PR((int c));
39 LOCAL int isop __PR((int c));
40 LOCAL mode_t isperm __PR((int c, int isX));
41
42 /*
43 * This is the mode bit translation code stolen from star...
44 */
45 #define TSUID 04000 /* Set UID on execution */
46 #define TSGID 02000 /* Set GID on execution */
47 #define TSVTX 01000 /* On directories, restricted deletion flag */
48 #define TUREAD 00400 /* Read by owner */
49 #define TUWRITE 00200 /* Write by owner special */
50 #define TUEXEC 00100 /* Execute/search by owner */
51 #define TGREAD 00040 /* Read by group */
52 #define TGWRITE 00020 /* Write by group */
53 #define TGEXEC 00010 /* Execute/search by group */
54 #define TOREAD 00004 /* Read by other */
55 #define TOWRITE 00002 /* Write by other */
56 #define TOEXEC 00001 /* Execute/search by other */
57
58 #define TALLMODES 07777 /* The low 12 bits mentioned in the standard */
59
60 #define S_ALLPERM (S_IRWXU|S_IRWXG|S_IRWXO)
61 #define S_ALLFLAGS (S_ISUID|S_ISGID|S_ISVTX)
62 #define S_ALLMODES (S_ALLFLAGS | S_ALLPERM)
63
64 #if S_ISUID == TSUID && S_ISGID == TSGID && S_ISVTX == TSVTX && \
65 S_IRUSR == TUREAD && S_IWUSR == TUWRITE && S_IXUSR == TUEXEC && \
66 S_IRGRP == TGREAD && S_IWGRP == TGWRITE && S_IXGRP == TGEXEC && \
67 S_IROTH == TOREAD && S_IWOTH == TOWRITE && S_IXOTH == TOEXEC
68
69 #define HAVE_POSIX_MODE_BITS /* st_mode bits are equal to TAR mode bits */
70 #endif
71
72 #ifdef HAVE_POSIX_MODE_BITS /* st_mode bits are equal to TAR mode bits */
73 #define OSMODE(xmode) (xmode)
74 #else
75 #define OSMODE(xmode) ((xmode & TSUID ? S_ISUID : 0) \
76 | (xmode & TSGID ? S_ISGID : 0) \
77 | (xmode & TSVTX ? S_ISVTX : 0) \
78 | (xmode & TUREAD ? S_IRUSR : 0) \
79 | (xmode & TUWRITE ? S_IWUSR : 0) \
80 | (xmode & TUEXEC ? S_IXUSR : 0) \
81 | (xmode & TGREAD ? S_IRGRP : 0) \
82 | (xmode & TGWRITE ? S_IWGRP : 0) \
83 | (xmode & TGEXEC ? S_IXGRP : 0) \
84 | (xmode & TOREAD ? S_IROTH : 0) \
85 | (xmode & TOWRITE ? S_IWOTH : 0) \
86 | (xmode & TOEXEC ? S_IXOTH : 0))
87 #endif
88
89 EXPORT int
getperm(f,perm,opname,modep,smode,flag)90 getperm(f, perm, opname, modep, smode, flag)
91 FILE *f; /* FILE * to print error messages to */
92 char *perm; /* Perm string to parse */
93 char *opname; /* find(1) operator name / NULL */
94 mode_t *modep; /* The mode result */
95 int smode; /* The start mode for the computation */
96 int flag; /* Flags, see getperm() flag defs */
97 {
98 char *p;
99 Llong ll;
100 mode_t mm;
101
102 p = perm;
103 if (p == NULL)
104 return (-1);
105
106 if ((flag & GP_FPERM) && *p == '-')
107 p++;
108
109 if (*p >= '0' && *p <= '7') {
110 p = astollb(p, &ll, 8);
111 if (*p) {
112 if (f) {
113 if (opname) {
114 ferrmsgno(f, EX_BAD,
115 gettext("Non octal character '%c' in '-%s %s'.\n"),
116 *p, opname, perm);
117 } else {
118 ferrmsgno(f, EX_BAD,
119 gettext("Non octal character '%c' in '%s'.\n"),
120 *p, perm);
121 }
122 }
123 return (-1);
124 }
125 mm = ll & TALLMODES;
126 *modep = OSMODE(mm);
127 return (0);
128 }
129 p = getsperm(f, p, opname, modep, smode, flag);
130 if (p == NULL) {
131 return (-1);
132 } else if (*p != '\0') {
133 if (f) {
134 if (opname) {
135 ferrmsgno(f, EX_BAD,
136 gettext("Bad perm character '%c' found in '-%s %s'.\n"),
137 *p, opname, perm);
138 } else {
139 ferrmsgno(f, EX_BAD,
140 gettext("Bad perm character '%c' found in '%s'.\n"),
141 *p, perm);
142 }
143 }
144 return (-1);
145 }
146 #ifdef PERM_DEBUG
147 error("GETPERM (%s) %4.4lo\n", perm, (long)*modep);
148 #endif
149 return (0);
150 }
151
152 LOCAL char *
getsperm(f,p,opname,mp,smode,flag)153 getsperm(f, p, opname, mp, smode, flag)
154 FILE *f;
155 char *p; /* The perm input string */
156 char *opname; /* find(1) operator name / NULL */
157 mode_t *mp; /* To set the mode */
158 int smode; /* The start mode for the computation */
159 int flag; /* Flags, see getperm() flag defs */
160 {
161 #ifdef OLD
162 mode_t permval = 0; /* POSIX start value for "find" */
163 #else
164 mode_t permval = smode; /* POSIX start value for "find" */
165 #endif
166 mode_t who;
167 mode_t who_mask = 0; /* Useless init to calm down silly GCC */
168 mode_t m;
169 int op;
170 mode_t perms;
171 mode_t pm;
172
173 nextclause:
174 #ifdef PERM_DEBUG
175 error("getsperm(%s, %o)\n", p, smode);
176 #endif
177 who = 0;
178 while ((m = iswho(*p)) != 0) {
179 p++;
180 who_mask = who |= m;
181 }
182 if (who == 0) {
183 mode_t mask;
184
185 /*
186 * If "who" has not been specified, select all bits for umask(1)
187 * or all reduced by umask(2) in the general case.
188 */
189 if (flag & GP_UMASK) {
190 who_mask =
191 who = (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
192 } else {
193 umask(mask = umask(0));
194 who = ~mask;
195 who &=
196 (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
197 who_mask =
198 (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
199 }
200 }
201 #ifdef PERM_DEBUG
202 error("WHO %4.4lo\n", (long)who);
203 error("getsperm(--->%s)\n", p);
204 #endif
205
206 nextop:
207 if ((op = isop(*p)) != '\0')
208 p++;
209 #ifdef PERM_DEBUG
210 error("OP '%c'\n", op);
211 error("getsperm(--->%s)\n", p);
212 #endif
213 if (op == 0) {
214 if (f) {
215 if (opname) {
216 ferrmsgno(f, EX_BAD,
217 gettext("Missing -%s op.\n"), opname);
218 } else {
219 ferrmsgno(f, EX_BAD,
220 gettext("Missing op in perm string.\n"));
221 }
222 }
223 if (*p == '\0')
224 return (NULL);
225 return (p);
226 }
227
228 flag &= ~(GP_FPERM|GP_UMASK);
229 if (flag & GP_XERR)
230 flag = -1;
231 perms = 0;
232 while ((pm = isperm(*p, flag)) != (mode_t)-1) {
233 p++;
234 perms |= pm;
235 }
236 #ifdef PERM_DEBUG
237 error("PERM %4.4lo\n", (long)perms);
238 error("START PERMVAL %4.4lo\n", (long)permval);
239 #endif
240 if ((perms == 0) && (*p == 'u' || *p == 'g' || *p == 'o')) {
241 mode_t what = 0;
242
243 /*
244 * First select the bit triple we like to copy.
245 */
246 switch (*p) {
247
248 case 'u':
249 what = permval & S_IRWXU;
250 break;
251 case 'g':
252 what = permval & S_IRWXG;
253 break;
254 case 'o':
255 what = permval & S_IRWXO;
256 break;
257 }
258 /*
259 * Now copy over bit by bit without relying on shifts
260 * that would make implicit assumptions on values.
261 */
262 if (what & (S_IRUSR|S_IRGRP|S_IROTH))
263 perms |= (who & (S_IRUSR|S_IRGRP|S_IROTH));
264 if (what & (S_IWUSR|S_IWGRP|S_IWOTH))
265 perms |= (who & (S_IWUSR|S_IWGRP|S_IWOTH));
266 if (what & (S_IXUSR|S_IXGRP|S_IXOTH))
267 perms |= (who & (S_IXUSR|S_IXGRP|S_IXOTH));
268 p++;
269 #ifdef PERM_DEBUG
270 error("PERM %4.4lo (copy) WHAT %lo WHO %lo\n",
271 (long)perms, (long)what, (long)who);
272 #endif
273 }
274 #ifdef PERM_DEBUG
275 error("getsperm(--->%s)\n", p);
276 error("PERMVAL %lo WHO %lo WHO_MASK %lo PERM %lo OP '%c'\n",
277 (long)permval, (long)who, (long)who_mask, (long)perms, op);
278 #endif
279 switch (op) {
280
281 case '=':
282 permval &= ~who_mask;
283 /* FALLTHRU */
284 case '+':
285 permval |= (who & perms);
286 break;
287
288 case '-':
289 permval &= ~(who & perms);
290 break;
291 }
292 #ifdef PERM_DEBUG
293 error("END PERMVAL %4.4lo\n", (long)permval);
294 #endif
295 if (isop(*p))
296 goto nextop;
297 if (*p == ',') {
298 p++;
299 goto nextclause;
300 }
301 *mp = permval;
302 return (p);
303 }
304
305 LOCAL mode_t
iswho(c)306 iswho(c)
307 int c;
308 {
309 switch (c) {
310
311 case 'u': /* user */
312 return (S_ISUID|S_ISVTX|S_IRWXU);
313 case 'g': /* group */
314 return (S_ISGID|S_ISVTX|S_IRWXG);
315 case 'o': /* other */
316 return (S_ISVTX|S_IRWXO);
317 case 'a': /* all */
318 return (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
319 default:
320 return (0);
321 }
322 }
323
324 LOCAL int
isop(c)325 isop(c)
326 int c; /* The current perm character to parse */
327 {
328 switch (c) {
329
330 case '+':
331 case '-':
332 case '=':
333 return (c);
334 default:
335 return (0);
336 }
337 }
338
339 LOCAL mode_t
isperm(c,isX)340 isperm(c, isX)
341 int c; /* The current perm character to parse */
342 int isX; /* -1: Ignore X, 0: no dir/X 1: X OK */
343 {
344 switch (c) {
345
346 case 'r':
347 return (S_IRUSR|S_IRGRP|S_IROTH);
348 case 'w':
349 return (S_IWUSR|S_IWGRP|S_IWOTH);
350 case 'X':
351 if (isX < 0)
352 return ((mode_t)-1); /* Singnal parse error */
353 if (isX == 0)
354 return ((mode_t)0); /* No 'X' handling here */
355 /* FALLTHRU */
356 case 'x':
357 return (S_IXUSR|S_IXGRP|S_IXOTH);
358 case 's':
359 return (S_ISUID|S_ISGID);
360 case 'l':
361 return (S_ISGID);
362 case 't':
363 return (S_ISVTX);
364 default:
365 return ((mode_t)-1);
366 }
367 }
368