1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1985-2011 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                 Eclipse Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *          http://www.eclipse.org/org/documents/epl-v10.html           *
11 *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
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 
42 int
strperm(const char * aexpr,char ** e,register int perm)43 strperm(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