1/***********************************************************************
2*                                                                      *
3*               This software is part of the ast package               *
4*          Copyright (c) 1985-2010 AT&T Intellectual Property          *
5*                      and is licensed under the                       *
6*                  Common Public License, Version 1.0                  *
7*                    by AT&T Intellectual Property                     *
8*                                                                      *
9*                A copy of the License is available at                 *
10*            http://www.opensource.org/licenses/cpl1.0.txt             *
11*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*                                                                      *
13*              Information and Software Systems Research               *
14*                            AT&T Research                             *
15*                           Florham Park NJ                            *
16*                                                                      *
17*                 Glenn Fowler <gsf@research.att.com>                  *
18*                  David Korn <dgk@research.att.com>                   *
19*                   Phong Vo <kpv@research.att.com>                    *
20*                                                                      *
21***********************************************************************/
22#pragma prototyped
23/*
24 * Glenn Fowler
25 * AT&T Research
26 *
27 * apply file permission expression expr to perm
28 *
29 * each expression term must match
30 *
31 *	[ugoa]*[-&+|^=]?[rwxst0-7]*
32 *
33 * terms may be combined using ,
34 *
35 * if non-null, e points to the first unrecognized char in expr
36 */
37
38#include <ast.h>
39#include <ls.h>
40#include <modex.h>
41
42int
43strperm(const char* aexpr, char** e, register int perm)
44{
45	register char*	expr = (char*)aexpr;
46	register int	c;
47	register int	typ;
48	register int	who;
49	int		num;
50	int		op;
51	int		mask;
52	int		masked;
53
54	if (perm == -1)
55	{
56		perm = 0;
57		masked = 1;
58		mask = ~0;
59	}
60	else
61		masked = 0;
62	for (;;)
63	{
64		op = num = who = typ = 0;
65		for (;;)
66		{
67			switch (c = *expr++)
68			{
69			case 'u':
70				who |= S_ISVTX|S_ISUID|S_IRWXU;
71				continue;
72			case 'g':
73				who |= S_ISVTX|S_ISGID|S_IRWXG;
74				continue;
75			case 'o':
76				who |= S_ISVTX|S_IRWXO;
77				continue;
78			case 'a':
79				who = S_ISVTX|S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
80				continue;
81			default:
82				if (c >= '0' && c <= '7')
83				{
84					if (!who)
85						who = S_ISVTX|S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
86					c = '=';
87				}
88				expr--;
89				/*FALLTHROUGH*/
90			case '=':
91				if (who)
92					perm &= ~who;
93				else
94					perm = 0;
95				/*FALLTHROUGH*/
96			case '+':
97			case '|':
98			case '-':
99			case '&':
100			case '^':
101				op = c;
102				for (;;)
103				{
104					switch (c = *expr++)
105					{
106					case 'r':
107						typ |= S_IRUSR|S_IRGRP|S_IROTH;
108						continue;
109					case 'w':
110						typ |= S_IWUSR|S_IWGRP|S_IWOTH;
111						continue;
112					case 'X':
113						if (!S_ISDIR(perm) && !(perm & (S_IXUSR|S_IXGRP|S_IXOTH)))
114							continue;
115						/*FALLTHROUGH*/
116					case 'x':
117						typ |= S_IXUSR|S_IXGRP|S_IXOTH;
118						continue;
119					case 's':
120						typ |= S_ISUID|S_ISGID;
121						continue;
122					case 't':
123						typ |= S_ISVTX;
124						continue;
125					case 'l':
126						if (perm & S_IXGRP)
127						{
128							if (e)
129								*e = expr - 1;
130							return perm & S_IPERM;
131						}
132						typ |= S_ISGID;
133						continue;
134					case '=':
135					case '+':
136					case '|':
137					case '-':
138					case '&':
139					case '^':
140					case ',':
141					case 0:
142						if (who)
143							typ &= who;
144						else
145							switch (op)
146							{
147							case '=':
148							case '+':
149							case '|':
150							case '-':
151							case '&':
152								if (!masked)
153								{
154									masked = 1;
155									umask(mask = umask(0));
156									mask = ~mask;
157								}
158								typ &= mask;
159								break;
160							}
161						switch (op)
162						{
163						default:
164							if (who)
165								perm &= ~who;
166							else
167								perm = 0;
168							/*FALLTHROUGH*/
169						case '+':
170						case '|':
171							perm |= typ;
172							typ = 0;
173							break;
174						case '-':
175							perm &= ~typ;
176							typ = 0;
177							break;
178						case '&':
179							perm &= typ;
180							typ = 0;
181							break;
182						case '^':
183							if (typ &= perm)
184							{
185								/*
186								 * propagate least restrictive to most restrictive
187								 */
188
189								if (typ & S_IXOTH)
190									perm |= who & (S_IXUSR|S_IXGRP);
191								if (typ & S_IWOTH)
192									perm |= who & (S_IWUSR|S_IWGRP);
193								if (typ & S_IROTH)
194									perm |= who & (S_IRUSR|S_IRGRP);
195								if (typ & S_IXGRP)
196									perm |= who & S_IXUSR;
197								if (typ & S_IWGRP)
198									perm |= who & S_IWUSR;
199								if (typ & S_IRGRP)
200									perm |= who & S_IRUSR;
201
202								/*
203								 * if any execute then read => execute
204								 */
205
206								if ((typ |= perm) & (S_IXUSR|S_IXGRP|S_IXOTH))
207								{
208									if (typ & S_IRUSR)
209										perm |= who & S_IXUSR;
210									if (typ & S_IRGRP)
211										perm |= who & S_IXGRP;
212									if (typ & S_IROTH)
213										perm |= who & S_IXOTH;
214								}
215								typ = 0;
216							}
217							break;
218						}
219						switch (c)
220						{
221						case '=':
222						case '+':
223						case '|':
224						case '-':
225						case '&':
226						case '^':
227							op = c;
228							typ = 0;
229							continue;
230						}
231						if (c)
232							break;
233						/*FALLTHROUGH*/
234					default:
235						if (c < '0' || c > '7')
236						{
237							if (e)
238								*e = expr - 1;
239							if (typ)
240							{
241								if (who)
242								{
243									typ &= who;
244									perm &= ~who;
245								}
246								perm |= typ;
247							}
248							return perm & S_IPERM;
249						}
250						num = (num << 3) | (c - '0');
251						if (!who && (op == '+' || op == '-'))
252							who = S_ISVTX|S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
253						if (*expr < '0' || *expr > '7')
254						{
255							typ |= modei(num);
256							num = 0;
257						}
258						continue;
259					}
260					break;
261				}
262				break;
263			}
264			break;
265		}
266	}
267}
268