1 /* @(#)umask.c	1.7 16/01/04 Copyright 2004-2016 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef RES
4 static	UConst char sccsid[] =
5 	"@(#)umask.c	1.7 16/01/04 Copyright 2004-2016 J. Schilling";
6 /*
7  *	Parser for chmod(1)/find(1)-perm, ....
8  *	The code has been taken from libschily/getperm.c and adopted to
9  *	avoid stdio for the Bourne Shell.
10  *
11  *	Copyright (c) 2004-2016 J. Schilling
12  */
13 /*
14  * The contents of this file are subject to the terms of the
15  * Common Development and Distribution License, Version 1.0 only
16  * (the "License").  You may not use this file except in compliance
17  * with the License.
18  *
19  * See the file CDDL.Schily.txt in this distribution for details.
20  * A copy of the CDDL is also available via the Internet at
21  * http://www.opensource.org/licenses/cddl1.txt
22  *
23  * When distributing Covered Code, include this CDDL HEADER in each
24  * file and include the License file CDDL.Schily.txt from this distribution.
25  */
26 
27 #include "defs.h"
28 
29 #define	LOCAL	static
30 
31 /*
32  * getperm() flags:
33  */
34 #define	GP_NOX		0	/* This is not a dir and 'X' is not valid */
35 #define	GP_DOX		1	/* 'X' perm character is valid		  */
36 #define	GP_XERR		2	/* 'X' perm characters are invalid	  */
37 #define	GP_FPERM	4	/* TRUE if we implement find -perm	  */
38 
39 #ifdef	DO_UMASK_S
40 LOCAL	int	getperm		__PR((char *perm, mode_t *modep,
41 							int smode, int flag));
42 LOCAL	char	*getsperm	__PR((char *p, mode_t *mp, int smode, int isX));
43 LOCAL	mode_t	iswho		__PR((int c));
44 LOCAL	int	isop		__PR((int c));
45 LOCAL	mode_t	isperm		__PR((int c, int isX));
46 LOCAL	int	mval		__PR((mode_t m));
47 #endif
48 LOCAL	void	promask		__PR((void));
49 	void	sysumask	__PR((int argc, char **argv));
50 
51 /*
52  * This is the mode bit translation code stolen from star...
53  */
54 #define	TSUID		04000	/* Set UID on execution */
55 #define	TSGID		02000	/* Set GID on execution */
56 #define	TSVTX		01000	/* On directories, restricted deletion flag */
57 #define	TUREAD		00400	/* Read by owner */
58 #define	TUWRITE		00200	/* Write by owner special */
59 #define	TUEXEC		00100	/* Execute/search by owner */
60 #define	TGREAD		00040	/* Read by group */
61 #define	TGWRITE		00020	/* Write by group */
62 #define	TGEXEC		00010	/* Execute/search by group */
63 #define	TOREAD		00004	/* Read by other */
64 #define	TOWRITE		00002	/* Write by other */
65 #define	TOEXEC		00001	/* Execute/search by other */
66 
67 #define	TALLMODES	07777	/* The low 12 bits mentioned in the standard */
68 
69 #define	S_ALLPERM	(S_IRWXU|S_IRWXG|S_IRWXO)
70 #define	S_ALLFLAGS	(S_ISUID|S_ISGID|S_ISVTX)
71 #define	S_ALLMODES	(S_ALLFLAGS | S_ALLPERM)
72 
73 #if	S_ISUID == TSUID && S_ISGID == TSGID && S_ISVTX == TSVTX && \
74 	S_IRUSR == TUREAD && S_IWUSR == TUWRITE && S_IXUSR == TUEXEC && \
75 	S_IRGRP == TGREAD && S_IWGRP == TGWRITE && S_IXGRP == TGEXEC && \
76 	S_IROTH == TOREAD && S_IWOTH == TOWRITE && S_IXOTH == TOEXEC
77 
78 #define	HAVE_POSIX_MODE_BITS	/* st_mode bits are equal to TAR mode bits */
79 #endif
80 
81 #ifdef	HAVE_POSIX_MODE_BITS	/* st_mode bits are equal to TAR mode bits */
82 #define	OSMODE(xmode)	    (xmode)
83 #define	TARMODE(xmode)	    (xmode)
84 #else
85 #define	OSMODE(xmode)	    ((xmode  & TSUID   ? S_ISUID : 0) \
86 			    | (xmode & TSGID   ? S_ISGID : 0) \
87 			    | (xmode & TSVTX   ? S_ISVTX : 0) \
88 			    | (xmode & TUREAD  ? S_IRUSR : 0) \
89 			    | (xmode & TUWRITE ? S_IWUSR : 0) \
90 			    | (xmode & TUEXEC  ? S_IXUSR : 0) \
91 			    | (xmode & TGREAD  ? S_IRGRP : 0) \
92 			    | (xmode & TGWRITE ? S_IWGRP : 0) \
93 			    | (xmode & TGEXEC  ? S_IXGRP : 0) \
94 			    | (xmode & TOREAD  ? S_IROTH : 0) \
95 			    | (xmode & TOWRITE ? S_IWOTH : 0) \
96 			    | (xmode & TOEXEC  ? S_IXOTH : 0))
97 
98 #define	TARMODE(xmode)	    ((xmode  & S_ISUID ? TSUID   : 0) \
99 			    | (xmode & S_ISGID ? TSGID   : 0) \
100 			    | (xmode & S_ISVTX ? TSVTX   : 0) \
101 			    | (xmode & S_IRUSR ? TUREAD  : 0) \
102 			    | (xmode & S_IWUSR ? TUWRITE : 0) \
103 			    | (xmode & S_IXUSR ? TUEXEC  : 0) \
104 			    | (xmode & S_IRGRP ? TGREAD  : 0) \
105 			    | (xmode & S_IWGRP ? TGWRITE : 0) \
106 			    | (xmode & S_IXGRP ? TGEXEC  : 0) \
107 			    | (xmode & S_IROTH ? TOREAD  : 0) \
108 			    | (xmode & S_IWOTH ? TOWRITE : 0) \
109 			    | (xmode & S_IXOTH ? TOEXEC  : 0))
110 #endif
111 
112 #ifdef	DO_UMASK_S
113 LOCAL int
getperm(perm,modep,smode,flag)114 getperm(perm, modep, smode, flag)
115 	char	*perm;			/* Perm string to parse		    */
116 	mode_t	*modep;			/* The mode result		    */
117 	int	smode;			/* The start mode for the computation */
118 	int	flag;			/* Flags, see getperm() flag defs */
119 {
120 	char	*p;
121 #ifdef	DO_OCTAL
122 	Llong	ll;
123 	mode_t	mm;
124 #endif
125 
126 	p = perm;
127 	if ((flag & GP_FPERM) && *p == '-')
128 		p++;
129 
130 #ifdef	DO_OCTAL
131 	if (*p >= '0' && *p <= '7') {
132 		p = astollb(p, &ll, 8);
133 		if (*p) {
134 			return (-1);
135 		}
136 		mm = ll & TALLMODES;
137 		*modep = OSMODE(mm);
138 		return (0);
139 	}
140 #endif
141 	flag &= ~GP_FPERM;
142 	if (flag & GP_XERR)
143 		flag = -1;
144 	p = getsperm(p, modep, smode, flag);
145 	if (p && *p != '\0') {
146 		return (-1);
147 	}
148 	return (0);
149 }
150 
151 LOCAL char *
getsperm(p,mp,smode,isX)152 getsperm(p, mp, smode, isX)
153 	char	*p;		/* The perm input string		*/
154 	mode_t	*mp;		/* To set the mode			*/
155 	int	smode;		/* The start mode for the computation	*/
156 	int	isX;		/* -1: Ignore X, 0: no dir/X 1: X OK	*/
157 {
158 	mode_t	permval = smode;	/* POSIX start value for "find" */
159 	mode_t	who;
160 	mode_t	m;
161 	int	op;
162 	mode_t	perms;
163 	mode_t	pm;
164 
165 nextclause:
166 	who = 0;
167 	while ((m = iswho(*p)) != 0) {
168 		p++;
169 		who |= m;
170 	}
171 	if (who == 0) {
172 #ifndef	BOURNE_SHELL
173 		mode_t	mask = umask(0);
174 
175 		umask(mask);
176 		who = ~mask;
177 		who &= (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
178 #else
179 		who = (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
180 #endif
181 	}
182 
183 nextop:
184 	if ((op = isop(*p)) != '\0')
185 		p++;
186 	if (op == 0) {
187 		return (p);
188 	}
189 
190 	perms = 0;
191 	while ((pm = isperm(*p, isX)) != (mode_t)-1) {
192 		p++;
193 		perms |= pm;
194 	}
195 	if ((perms == 0) && (*p == 'u' || *p == 'g' || *p == 'o')) {
196 		mode_t	what = 0;
197 
198 		/*
199 		 * First select the bit triple we like to copy.
200 		 */
201 		switch (*p) {
202 
203 		case 'u':
204 			what = permval & S_IRWXU;
205 			break;
206 		case 'g':
207 			what = permval & S_IRWXG;
208 			break;
209 		case 'o':
210 			what = permval & S_IRWXO;
211 			break;
212 		}
213 		/*
214 		 * Now copy over bit by bit without relying on shifts
215 		 * that would make implicit assumptions on values.
216 		 */
217 		if (what & (S_IRUSR|S_IRGRP|S_IROTH))
218 			perms |= (who & (S_IRUSR|S_IRGRP|S_IROTH));
219 		if (what & (S_IWUSR|S_IWGRP|S_IWOTH))
220 			perms |= (who & (S_IWUSR|S_IWGRP|S_IWOTH));
221 		if (what & (S_IXUSR|S_IXGRP|S_IXOTH))
222 			perms |= (who & (S_IXUSR|S_IXGRP|S_IXOTH));
223 		p++;
224 	}
225 	switch (op) {
226 
227 	case '=':
228 		permval &= ~who;
229 		/* FALLTHRU */
230 	case '+':
231 		permval |= (who & perms);
232 		break;
233 
234 	case '-':
235 		permval &= ~(who & perms);
236 		break;
237 	}
238 	if (isop(*p))
239 		goto nextop;
240 	if (*p == ',') {
241 		p++;
242 		goto nextclause;
243 	}
244 	*mp = permval;
245 	return (p);
246 }
247 
248 LOCAL mode_t
iswho(c)249 iswho(c)
250 	int	c;
251 {
252 	switch (c) {
253 
254 	case 'u':					/* user */
255 		return (S_ISUID|S_ISVTX|S_IRWXU);
256 	case 'g':					/* group */
257 		return (S_ISGID|S_ISVTX|S_IRWXG);
258 	case 'o':					/* other */
259 		return (S_ISVTX|S_IRWXO);
260 	case 'a':					/* all */
261 		return (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
262 	default:
263 		return (0);
264 	}
265 }
266 
267 LOCAL int
isop(c)268 isop(c)
269 	int	c;		/* The current perm character to parse	*/
270 {
271 	switch (c) {
272 
273 	case '+':
274 	case '-':
275 	case '=':
276 		return (c);
277 	default:
278 		return (0);
279 	}
280 }
281 
282 LOCAL mode_t
isperm(c,isX)283 isperm(c, isX)
284 	int	c;		/* The current perm character to parse	*/
285 	int	isX;		/* -1: Ignore X, 0: no dir/X 1: X OK	*/
286 {
287 	switch (c) {
288 
289 	case 'r':
290 		return (S_IRUSR|S_IRGRP|S_IROTH);
291 	case 'w':
292 		return (S_IWUSR|S_IWGRP|S_IWOTH);
293 	case 'X':
294 		if (isX < 0)
295 			return ((mode_t)-1);	/* Singnal parse error	*/
296 		if (isX == 0)
297 			return ((mode_t)0);	/* No 'X' handling here	*/
298 		/* FALLTHRU */
299 	case 'x':
300 		return (S_IXUSR|S_IXGRP|S_IXOTH);
301 	case 's':
302 		return (S_ISUID|S_ISGID);
303 	case 'l':
304 		return (S_ISGID);
305 	case 't':
306 		return (S_ISVTX);
307 	default:
308 		return ((mode_t)-1);
309 	}
310 }
311 
312 static char *umodtab[] =
313 {"", "x", "w", "wx", "r", "rx", "rw", "rwx"};
314 
315 #ifdef	PROTOTYPES
316 LOCAL int
mval(mode_t m)317 mval(mode_t m)
318 #else
319 LOCAL int
320 mval(m)
321 	mode_t	m;
322 #endif
323 {
324 	int	ret = 0;
325 
326 	if (m & (S_IRUSR|S_IRGRP|S_IROTH))
327 		ret |= 4;
328 	if (m & (S_IWUSR|S_IWGRP|S_IWOTH))
329 		ret |= 2;
330 	if (m & (S_IXUSR|S_IXGRP|S_IXOTH))
331 		ret |= 1;
332 
333 	return (ret);
334 }
335 #endif	/* DO_UMASK_S */
336 
337 LOCAL void
promask()338 promask()
339 {
340 	mode_t	i;
341 	int	j;
342 
343 	umask(i = umask(0));
344 	i = TARMODE(i);
345 	prc_buff('0');
346 	for (j = 6; j >= 0; j -= 3)
347 		prc_buff(((i >> j) & 07) +'0');
348 	prc_buff(NL);
349 }
350 
351 void
sysumask(argc,argv)352 sysumask(argc, argv)
353 	int	argc;
354 	char	**argv;
355 {
356 	char	*a1 = argv[1];
357 
358 #ifdef	DO_UMASK_S
359 	if (argc == 2 && eq(a1, "-S")) {
360 		mode_t	m;
361 
362 		umask(m = umask(0));
363 		m = ~m;
364 
365 		prs_buff((unsigned char *)"u=");
366 		prs_buff((unsigned char *)umodtab[mval(m & S_IRWXU)]);
367 		prs_buff((unsigned char *)",g=");
368 		prs_buff((unsigned char *)umodtab[mval(m & S_IRWXG)]);
369 		prs_buff((unsigned char *)",o=");
370 		prs_buff((unsigned char *)umodtab[mval(m & S_IRWXO)]);
371 		prc_buff(NL);
372 	} else if (a1) {
373 		int	c;
374 		mode_t	i;
375 
376 		/*
377 		 * POSIX requires "umask -r" to fail.
378 		 * Must use "umask -- -r" to set this mode.
379 		 */
380 		if (a1[0] == '-') {
381 			if (a1[1] == '-' && a1[2] == '\0') {	/* found -- */
382 				if (argc <= 2) {		/* umask -- */
383 					promask();
384 					return;
385 				}
386 				argv++;
387 				a1 = argv[1];
388 			} else {
389 				/*
390 				 * This is a "bad option".
391 				 */
392 				failure((unsigned char *)&badumask[4],
393 								badumask);
394 			}
395 		}
396 		i = 0;
397 		while ((c = *a1++) >= '0' && c <= '7')
398 			i = (i << 3) + c - '0';
399 
400 		if (c == '\0') {	/* Fully octal arg */
401 			umask(OSMODE(i));
402 			return;
403 		}
404 
405 		umask(i = umask(0));
406 		i = ~i;
407 		if (getperm(argv[1], &i, i, GP_NOX)) {
408 			failure((unsigned char *)&badumask[4], badumask);
409 		}
410 		umask(~i);
411 	} else {
412 		promask();
413 	}
414 #else
415 	if (a1) {
416 		int	c;
417 		mode_t	i;
418 
419 		i = 0;
420 		while ((c = *a1++) >= '0' && c <= '7')
421 			i = (i << 3) + c - '0';
422 
423 		umask(OSMODE(i));
424 	} else {
425 		promask();
426 	}
427 #endif
428 }
429 
430 #endif /* RES */
431