1.2.7
by Bdale Garbee
Import upstream version 1.7.0 |
1 |
%{
|
2 |
/*
|
|
3 |
* Copyright (c) 1996, 1998-2005, 2007-2008
|
|
4 |
* Todd C. Miller <Todd.Miller@courtesan.com>
|
|
5 |
*
|
|
6 |
* Permission to use, copy, modify, and distribute this software for any
|
|
7 |
* purpose with or without fee is hereby granted, provided that the above
|
|
8 |
* copyright notice and this permission notice appear in all copies.
|
|
9 |
*
|
|
10 |
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
11 |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
12 |
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
13 |
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
14 |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
15 |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
16 |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
17 |
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
18 |
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
19 |
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
20 |
*
|
|
21 |
* Sponsored in part by the Defense Advanced Research Projects
|
|
22 |
* Agency (DARPA) and Air Force Research Laboratory, Air Force
|
|
23 |
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
|
|
24 |
*/
|
|
25 |
||
26 |
#include <config.h>
|
|
27 |
||
28 |
#include <sys/types.h>
|
|
29 |
#include <sys/param.h>
|
|
30 |
#include <stdio.h>
|
|
31 |
#ifdef STDC_HEADERS
|
|
32 |
# include <stdlib.h>
|
|
33 |
# include <stddef.h>
|
|
34 |
#else
|
|
35 |
# ifdef HAVE_STDLIB_H
|
|
36 |
# include <stdlib.h>
|
|
37 |
# endif
|
|
38 |
#endif /* STDC_HEADERS */
|
|
39 |
#ifdef HAVE_STRING_H
|
|
40 |
# include <string.h>
|
|
41 |
#else
|
|
42 |
# ifdef HAVE_STRINGS_H
|
|
43 |
# include <strings.h>
|
|
44 |
# endif
|
|
45 |
#endif /* HAVE_STRING_H */
|
|
46 |
#ifdef HAVE_UNISTD_H
|
|
47 |
# include <unistd.h>
|
|
48 |
#endif /* HAVE_UNISTD_H */
|
|
49 |
#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
|
|
50 |
# include <malloc.h>
|
|
51 |
#endif /* HAVE_MALLOC_H && !STDC_HEADERS */
|
|
52 |
#include <ctype.h>
|
|
53 |
#include "sudo.h"
|
|
54 |
#include "parse.h"
|
|
55 |
#include <gram.h>
|
|
56 |
||
57 |
#ifndef lint
|
|
58 |
__unused static const char rcsid[] = "$Sudo: toke.l,v 1.27 2008/11/24 00:41:36 millert Exp $";
|
|
59 |
#endif /* lint */
|
|
60 |
||
61 |
extern YYSTYPE yylval;
|
|
62 |
int sudolineno = 1;
|
|
63 |
char *sudoers;
|
|
64 |
static int sawspace = 0;
|
|
65 |
static int arg_len = 0;
|
|
66 |
static int arg_size = 0;
|
|
67 |
||
68 |
static int append __P((char *, int));
|
|
69 |
static int _fill __P((char *, int, int));
|
|
70 |
static int fill_cmnd __P((char *, int));
|
|
71 |
static int fill_args __P((char *, int, int));
|
|
72 |
static int switch_buffer __P((char *));
|
|
73 |
static int ipv6_valid __P((const char *s));
|
|
74 |
static char *parse_include __P((char *));
|
|
75 |
extern void yyerror __P((const char *));
|
|
76 |
||
77 |
#define fill(a, b) _fill(a, b, 0)
|
|
78 |
||
79 |
#define push_include(_p) (switch_buffer((_p)))
|
|
80 |
#define pop_include() (switch_buffer(NULL))
|
|
81 |
||
82 |
/* realloc() to size + COMMANDARGINC to make room for command args */
|
|
83 |
#define COMMANDARGINC 64
|
|
84 |
||
85 |
#ifdef TRACELEXER
|
|
86 |
#define LEXTRACE(msg) fputs(msg, stderr)
|
|
87 |
#else
|
|
88 |
#define LEXTRACE(msg)
|
|
89 |
#endif
|
|
90 |
%}
|
|
91 |
||
92 |
HEX16 [0-9A-Fa-f]{1,4} |
|
93 |
OCTET (1?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5]) |
|
94 |
IPV4ADDR {OCTET}(\.{OCTET}){3} |
|
95 |
IPV6ADDR ({HEX16}?:){2,7}{HEX16}?|({HEX16}?:){2,6}:{IPV4ADDR} |
|
96 |
||
97 |
HOSTNAME [[:alnum:]_-]+ |
|
98 |
WORD ([^#>!=:,\(\) \t\n\\]|\\[^\n])+ |
|
99 |
ID #-?[0-9]+ |
|
100 |
PATH \/(\\[\,:= \t#]|[^\,:=\\ \t\n#])+ |
|
101 |
ENVAR ([^#!=, \t\n\\\"]|\\[^\n])([^#=, \t\n\\\"]|\\[^\n])* |
|
102 |
DEFVAR [a-z_]+ |
|
103 |
||
104 |
%option nounput
|
|
105 |
%option noyywrap
|
|
106 |
||
107 |
%s GOTDEFS
|
|
108 |
%x GOTCMND
|
|
109 |
%x STARTDEFS
|
|
110 |
%x INDEFS
|
|
111 |
%x INSTR
|
|
112 |
||
113 |
%%
|
|
114 |
<GOTDEFS>[[:blank:]]+ BEGIN STARTDEFS; |
|
115 |
||
116 |
<STARTDEFS>{DEFVAR} { |
|
117 |
BEGIN INDEFS; |
|
118 |
LEXTRACE("DEFVAR "); |
|
119 |
if (!fill(yytext, yyleng)) |
|
120 |
yyterminate(); |
|
121 |
return(DEFVAR); |
|
122 |
}
|
|
123 |
||
124 |
<INDEFS>{ |
|
125 |
, { |
|
126 |
BEGIN STARTDEFS; |
|
127 |
LEXTRACE(", "); |
|
128 |
return(','); |
|
129 |
} /* return ',' */ |
|
130 |
||
131 |
= { |
|
132 |
LEXTRACE("= "); |
|
133 |
return('='); |
|
134 |
} /* return '=' */ |
|
135 |
||
136 |
\+= { |
|
137 |
LEXTRACE("+= "); |
|
138 |
return('+'); |
|
139 |
} /* return '+' */ |
|
140 |
||
141 |
-= { |
|
142 |
LEXTRACE("-= "); |
|
143 |
return('-'); |
|
144 |
} /* return '-' */ |
|
145 |
||
146 |
\" { |
|
147 |
LEXTRACE("BEGINSTR "); |
|
148 |
yylval.string = NULL;
|
|
149 |
BEGIN INSTR;
|
|
150 |
}
|
|
151 |
||
152 |
{ENVAR} {
|
|
153 |
LEXTRACE("WORD(2) "); |
|
154 |
if (!fill(yytext, yyleng))
|
|
155 |
yyterminate();
|
|
156 |
return(WORD);
|
|
157 |
}
|
|
158 |
}
|
|
159 |
||
160 |
<INSTR>{
|
|
161 |
\\[[:blank:]]*\n[[:blank:]]* {
|
|
162 |
/* Line continuation char followed by newline. */
|
|
163 |
++sudolineno;
|
|
164 |
LEXTRACE("\n"); |
|
165 |
}
|
|
166 |
||
167 |
\" { |
|
168 |
LEXTRACE("ENDSTR "); |
|
169 |
BEGIN INDEFS; |
|
170 |
return(WORD); |
|
171 |
}
|
|
172 |
||
173 |
\\ { |
|
174 |
LEXTRACE("BACKSLASH "); |
|
175 |
if (!append(yytext, yyleng)) |
|
176 |
yyterminate(); |
|
177 |
}
|
|
178 |
||
179 |
([^\"\n\\]|\\\")+ { |
|
180 |
LEXTRACE("STRBODY "); |
|
181 |
if (!append(yytext, yyleng)) |
|
182 |
yyterminate(); |
|
183 |
}
|
|
184 |
}
|
|
185 |
||
186 |
<GOTCMND>{ |
|
187 |
\\[\*\?\[\]\!] { |
|
188 |
/* quoted fnmatch glob char, pass verbatim */ |
|
189 |
LEXTRACE("QUOTEDCHAR "); |
|
190 |
if (!fill_args(yytext, 2, sawspace)) |
|
191 |
yyterminate(); |
|
192 |
sawspace = FALSE; |
|
193 |
}
|
|
194 |
||
195 |
\\[:\\,= \t#] { |
|
196 |
/* quoted sudoers special char, strip backslash */ |
|
197 |
LEXTRACE("QUOTEDCHAR "); |
|
198 |
if (!fill_args(yytext + 1, 1, sawspace)) |
|
199 |
yyterminate(); |
|
200 |
sawspace = FALSE; |
|
201 |
}
|
|
202 |
||
203 |
[#:\,=\n] { |
|
204 |
BEGIN INITIAL; |
|
205 |
yyless(0); |
|
206 |
return(COMMAND); |
|
207 |
} /* end of command line args */ |
|
208 |
||
209 |
[^\\:, \t\n]+ { |
|
210 |
LEXTRACE("ARG "); |
|
211 |
if (!fill_args(yytext, yyleng, sawspace)) |
|
212 |
yyterminate(); |
|
213 |
sawspace = FALSE; |
|
214 |
} /* a command line arg */ |
|
215 |
}
|
|
216 |
||
217 |
<INITIAL>^#include[[:blank:]]+\/.*\n { |
|
218 |
char *path; |
|
219 |
||
220 |
if ((path = parse_include(yytext)) == NULL) |
|
221 |
yyterminate(); |
|
222 |
||
223 |
LEXTRACE("INCLUDE\n"); |
|
224 |
||
225 |
/* Push current buffer and switch to include file */ |
|
226 |
if (!push_include(path)) |
|
227 |
yyterminate(); |
|
228 |
}
|
|
229 |
||
230 |
<INITIAL>^[[:blank:]]*Defaults([:@>\!]{WORD})? { |
|
231 |
int n; |
|
232 |
for (n = 0; isblank((unsigned char)yytext[n]); n++) |
|
233 |
continue; |
|
234 |
n += 8; |
|
235 |
BEGIN GOTDEFS; |
|
236 |
switch (yytext[n++]) { |
|
237 |
case ':': |
|
238 |
yyless(n); |
|
239 |
LEXTRACE("DEFAULTS_USER "); |
|
240 |
return(DEFAULTS_USER); |
|
241 |
case '>': |
|
242 |
yyless(n); |
|
243 |
LEXTRACE("DEFAULTS_RUNAS "); |
|
244 |
return(DEFAULTS_RUNAS); |
|
245 |
case '@': |
|
246 |
yyless(n); |
|
247 |
LEXTRACE("DEFAULTS_HOST "); |
|
248 |
return(DEFAULTS_HOST); |
|
249 |
case '!': |
|
250 |
yyless(n); |
|
251 |
LEXTRACE("DEFAULTS_CMND "); |
|
252 |
return(DEFAULTS_CMND); |
|
253 |
default: |
|
254 |
LEXTRACE("DEFAULTS "); |
|
255 |
return(DEFAULTS); |
|
256 |
}
|
|
257 |
}
|
|
258 |
||
259 |
<INITIAL>^[[:blank:]]*(Host|Cmnd|User|Runas)_Alias { |
|
260 |
int n; |
|
261 |
for (n = 0; isblank((unsigned char)yytext[n]); n++) |
|
262 |
continue; |
|
263 |
switch (yytext[n]) { |
|
264 |
case 'H': |
|
265 |
LEXTRACE("HOSTALIAS "); |
|
266 |
return(HOSTALIAS); |
|
267 |
case 'C': |
|
268 |
LEXTRACE("CMNDALIAS "); |
|
269 |
return(CMNDALIAS); |
|
270 |
case 'U': |
|
271 |
LEXTRACE("USERALIAS "); |
|
272 |
return(USERALIAS); |
|
273 |
case 'R': |
|
274 |
LEXTRACE("RUNASALIAS "); |
|
275 |
return(RUNASALIAS); |
|
276 |
}
|
|
277 |
}
|
|
278 |
||
279 |
NOPASSWD[[:blank:]]*: { |
|
280 |
/* cmnd does not require passwd for this user */ |
|
281 |
LEXTRACE("NOPASSWD "); |
|
282 |
return(NOPASSWD); |
|
283 |
}
|
|
284 |
||
285 |
PASSWD[[:blank:]]*: { |
|
286 |
/* cmnd requires passwd for this user */ |
|
287 |
LEXTRACE("PASSWD "); |
|
288 |
return(PASSWD); |
|
289 |
}
|
|
290 |
||
291 |
NOEXEC[[:blank:]]*: { |
|
292 |
LEXTRACE("NOEXEC "); |
|
293 |
return(NOEXEC); |
|
294 |
}
|
|
295 |
||
296 |
EXEC[[:blank:]]*: { |
|
297 |
LEXTRACE("EXEC "); |
|
298 |
return(EXEC); |
|
299 |
}
|
|
300 |
||
301 |
SETENV[[:blank:]]*: { |
|
302 |
LEXTRACE("SETENV "); |
|
303 |
return(SETENV); |
|
304 |
}
|
|
305 |
||
306 |
NOSETENV[[:blank:]]*: { |
|
307 |
LEXTRACE("NOSETENV "); |
|
308 |
return(NOSETENV); |
|
309 |
}
|
|
310 |
||
311 |
\+{WORD} { |
|
312 |
/* netgroup */ |
|
313 |
if (!fill(yytext, yyleng)) |
|
314 |
yyterminate(); |
|
315 |
LEXTRACE("NETGROUP "); |
|
316 |
return(NETGROUP); |
|
317 |
}
|
|
318 |
||
319 |
\%{WORD} { |
|
320 |
/* UN*X group */ |
|
321 |
if (!fill(yytext, yyleng)) |
|
322 |
yyterminate(); |
|
323 |
LEXTRACE("USERGROUP "); |
|
324 |
return(USERGROUP); |
|
325 |
}
|
|
326 |
||
327 |
{IPV4ADDR}(\/{IPV4ADDR})? { |
|
328 |
if (!fill(yytext, yyleng)) |
|
329 |
yyterminate(); |
|
330 |
LEXTRACE("NTWKADDR "); |
|
331 |
return(NTWKADDR); |
|
332 |
}
|
|
333 |
||
334 |
{IPV4ADDR}\/([12][0-9]*|3[0-2]*) { |
|
335 |
if (!fill(yytext, yyleng)) |
|
336 |
yyterminate(); |
|
337 |
LEXTRACE("NTWKADDR "); |
|
338 |
return(NTWKADDR); |
|
339 |
}
|
|
340 |
||
341 |
{IPV6ADDR}(\/{IPV6ADDR})? { |
|
342 |
if (!ipv6_valid(yytext)) { |
|
343 |
LEXTRACE("ERROR "); |
|
344 |
return(ERROR); |
|
345 |
}
|
|
346 |
if (!fill(yytext, yyleng)) |
|
347 |
yyterminate(); |
|
348 |
LEXTRACE("NTWKADDR "); |
|
349 |
return(NTWKADDR); |
|
350 |
}
|
|
351 |
||
352 |
{IPV6ADDR}\/([0-9]|[1-9][0-9]|1[01][0-9]|12[0-8]) { |
|
353 |
if (!ipv6_valid(yytext)) { |
|
354 |
LEXTRACE("ERROR "); |
|
355 |
return(ERROR); |
|
356 |
}
|
|
357 |
if (!fill(yytext, yyleng)) |
|
358 |
yyterminate(); |
|
359 |
LEXTRACE("NTWKADDR "); |
|
360 |
return(NTWKADDR); |
|
361 |
}
|
|
362 |
||
363 |
[[:upper:]][[:upper:][:digit:]_]* { |
|
364 |
if (strcmp(yytext, "ALL") == 0) { |
|
365 |
LEXTRACE("ALL "); |
|
366 |
return(ALL); |
|
367 |
}
|
|
368 |
#ifdef HAVE_SELINUX |
|
369 |
/* XXX - restrict type/role to initial state */ |
|
370 |
if (strcmp(yytext, "TYPE") == 0) { |
|
371 |
LEXTRACE("TYPE "); |
|
372 |
return(TYPE); |
|
373 |
}
|
|
374 |
if (strcmp(yytext, "ROLE") == 0) { |
|
375 |
LEXTRACE("ROLE "); |
|
376 |
return(ROLE); |
|
377 |
}
|
|
378 |
#endif /* HAVE_SELINUX */ |
|
379 |
if (!fill(yytext, yyleng)) |
|
380 |
yyterminate(); |
|
381 |
LEXTRACE("ALIAS "); |
|
382 |
return(ALIAS); |
|
383 |
}
|
|
384 |
||
385 |
<GOTDEFS>({PATH}|sudoedit) { |
|
386 |
/* no command args allowed for Defaults!/path */ |
|
387 |
if (!fill_cmnd(yytext, yyleng)) |
|
388 |
yyterminate(); |
|
389 |
LEXTRACE("COMMAND "); |
|
390 |
return(COMMAND); |
|
391 |
}
|
|
392 |
||
393 |
sudoedit { |
|
394 |
BEGIN GOTCMND; |
|
395 |
LEXTRACE("COMMAND "); |
|
396 |
if (!fill_cmnd(yytext, yyleng)) |
|
397 |
yyterminate(); |
|
398 |
} /* sudo -e */ |
|
399 |
||
400 |
{PATH} { |
|
401 |
/* directories can't have args... */ |
|
402 |
if (yytext[yyleng - 1] == '/') { |
|
403 |
LEXTRACE("COMMAND "); |
|
404 |
if (!fill_cmnd(yytext, yyleng)) |
|
405 |
yyterminate(); |
|
406 |
return(COMMAND); |
|
407 |
} else { |
|
408 |
BEGIN GOTCMND; |
|
409 |
LEXTRACE("COMMAND "); |
|
410 |
if (!fill_cmnd(yytext, yyleng)) |
|
411 |
yyterminate(); |
|
412 |
}
|
|
413 |
} /* a pathname */ |
|
414 |
||
415 |
<INITIAL,GOTDEFS>({ID}|{WORD}) { |
|
416 |
/* a word */ |
|
417 |
if (!fill(yytext, yyleng)) |
|
418 |
yyterminate(); |
|
419 |
LEXTRACE("WORD(4) "); |
|
420 |
return(WORD); |
|
421 |
}
|
|
422 |
||
423 |
\( { |
|
424 |
LEXTRACE("( "); |
|
425 |
return ('('); |
|
426 |
}
|
|
427 |
||
428 |
\) { |
|
429 |
LEXTRACE(") "); |
|
430 |
return(')'); |
|
431 |
}
|
|
432 |
||
433 |
, { |
|
434 |
LEXTRACE(", "); |
|
435 |
return(','); |
|
436 |
} /* return ',' */ |
|
437 |
||
438 |
= { |
|
439 |
LEXTRACE("= "); |
|
440 |
return('='); |
|
441 |
} /* return '=' */ |
|
442 |
||
443 |
: { |
|
444 |
LEXTRACE(": "); |
|
445 |
return(':'); |
|
446 |
} /* return ':' */ |
|
447 |
||
448 |
<*>!+ { |
|
449 |
if (yyleng % 2 == 1) |
|
450 |
return('!'); /* return '!' */ |
|
451 |
}
|
|
452 |
||
453 |
<*>\n { |
|
454 |
BEGIN INITIAL; |
|
455 |
++sudolineno; |
|
456 |
LEXTRACE("\n"); |
|
457 |
return(COMMENT); |
|
458 |
} /* return newline */ |
|
459 |
||
460 |
<*>[[:blank:]]+ { /* throw away space/tabs */ |
|
461 |
sawspace = TRUE; /* but remember for fill_args */ |
|
462 |
}
|
|
463 |
||
464 |
<*>\\[[:blank:]]*\n { |
|
465 |
sawspace = TRUE; /* remember for fill_args */ |
|
466 |
++sudolineno; |
|
467 |
LEXTRACE("\n\t"); |
|
468 |
} /* throw away EOL after \ */ |
|
469 |
||
470 |
<INITIAL,STARTDEFS,INDEFS>#([^\n0-9-].*)?\n { |
|
471 |
BEGIN INITIAL; |
|
472 |
++sudolineno; |
|
473 |
LEXTRACE("\n"); |
|
474 |
return(COMMENT); |
|
475 |
} /* return comments */ |
|
476 |
||
477 |
<*>. { |
|
478 |
LEXTRACE("ERROR "); |
|
479 |
return(ERROR); |
|
480 |
} /* parse error */ |
|
481 |
||
482 |
<*><<EOF>> { |
|
483 |
if (YY_START != INITIAL) { |
|
484 |
BEGIN INITIAL; |
|
485 |
LEXTRACE("ERROR "); |
|
486 |
return(ERROR); |
|
487 |
}
|
|
488 |
if (!pop_include()) |
|
489 |
yyterminate(); |
|
490 |
}
|
|
491 |
||
492 |
%%
|
|
493 |
static int |
|
494 |
_fill(src, len, olen) |
|
495 |
char *src; |
|
496 |
int len, olen; |
|
497 |
{
|
|
498 |
int i, j; |
|
499 |
char *dst; |
|
500 |
||
501 |
dst = olen ? realloc(yylval.string, olen + len + 1) : malloc(len + 1); |
|
502 |
if (dst == NULL) { |
|
503 |
yyerror("unable to allocate memory"); |
|
504 |
return(FALSE); |
|
505 |
}
|
|
506 |
yylval.string = dst; |
|
507 |
||
508 |
/* Copy the string and collapse any escaped characters. */ |
|
509 |
dst += olen; |
|
510 |
for (i = 0, j = 0; i < len; i++, j++) { |
|
511 |
if (src[i] == '\\' && i != len - 1) |
|
512 |
dst[j] = src[++i]; |
|
513 |
else
|
|
514 |
dst[j] = src[i]; |
|
515 |
}
|
|
516 |
dst[j] = '\0'; |
|
517 |
return(TRUE); |
|
518 |
}
|
|
519 |
||
520 |
static int |
|
521 |
append(src, len) |
|
522 |
char *src; |
|
523 |
int len; |
|
524 |
{
|
|
525 |
int olen = 0; |
|
526 |
||
527 |
if (yylval.string != NULL) |
|
528 |
olen = strlen(yylval.string); |
|
529 |
||
530 |
return(_fill(src, len, olen)); |
|
531 |
}
|
|
532 |
||
533 |
#define SPECIAL(c) \ |
|
534 |
((c) == ',' || (c) == ':' || (c) == '=' || (c) == ' ' || (c) == '\t' || (c) == '#') |
|
535 |
||
536 |
static int |
|
537 |
fill_cmnd(src, len) |
|
538 |
char *src; |
|
539 |
int len; |
|
540 |
{
|
|
541 |
char *dst; |
|
542 |
int i; |
|
543 |
||
544 |
arg_len = arg_size = 0; |
|
545 |
||
546 |
dst = yylval.command.cmnd = (char *) malloc(len + 1); |
|
547 |
if (yylval.command.cmnd == NULL) { |
|
548 |
yyerror("unable to allocate memory"); |
|
549 |
return(FALSE); |
|
550 |
}
|
|
551 |
||
552 |
/* Copy the string and collapse any escaped sudo-specific characters. */ |
|
553 |
for (i = 0; i < len; i++) { |
|
554 |
if (src[i] == '\\' && i != len - 1 && SPECIAL(src[i + 1])) |
|
555 |
*dst++ = src[++i]; |
|
556 |
else
|
|
557 |
*dst++ = src[i]; |
|
558 |
}
|
|
559 |
*dst = '\0'; |
|
560 |
||
561 |
yylval.command.args = NULL; |
|
562 |
return(TRUE); |
|
563 |
}
|
|
564 |
||
565 |
static int |
|
566 |
fill_args(s, len, addspace) |
|
567 |
char *s; |
|
568 |
int len; |
|
569 |
int addspace; |
|
570 |
{
|
|
571 |
int new_len; |
|
572 |
char *p; |
|
573 |
||
574 |
if (yylval.command.args == NULL) { |
|
575 |
addspace = 0; |
|
576 |
new_len = len; |
|
577 |
} else |
|
578 |
new_len = arg_len + len + addspace; |
|
579 |
||
580 |
if (new_len >= arg_size) { |
|
581 |
/* Allocate more space than we need for subsequent args */ |
|
582 |
while (new_len >= (arg_size += COMMANDARGINC)) |
|
583 |
;
|
|
584 |
||
585 |
p = yylval.command.args ? |
|
586 |
(char *) realloc(yylval.command.args, arg_size) : |
|
587 |
(char *) malloc(arg_size); |
|
588 |
if (p == NULL) { |
|
589 |
efree(yylval.command.args); |
|
590 |
yyerror("unable to allocate memory"); |
|
591 |
return(FALSE); |
|
592 |
} else |
|
593 |
yylval.command.args = p; |
|
594 |
}
|
|
595 |
||
596 |
/* Efficiently append the arg (with a leading space if needed). */ |
|
597 |
p = yylval.command.args + arg_len; |
|
598 |
if (addspace) |
|
599 |
*p++ = ' '; |
|
600 |
if (strlcpy(p, s, arg_size - (p - yylval.command.args)) != len) { |
|
601 |
yyerror("fill_args: buffer overflow"); /* paranoia */ |
|
602 |
return(FALSE); |
|
603 |
}
|
|
604 |
arg_len = new_len; |
|
605 |
return(TRUE); |
|
606 |
}
|
|
607 |
||
608 |
struct sudoers_state { |
|
609 |
YY_BUFFER_STATE bs; |
|
610 |
char *path; |
|
611 |
int lineno; |
|
612 |
};
|
|
613 |
||
614 |
#define MAX_SUDOERS_DEPTH 128 |
|
615 |
#define SUDOERS_STACK_INCREMENT 16 |
|
616 |
||
617 |
static int |
|
618 |
switch_buffer(path) |
|
619 |
char *path; |
|
620 |
{
|
|
621 |
static size_t stacksize, depth; |
|
622 |
static struct sudoers_state *state; |
|
623 |
static int keepopen; |
|
624 |
FILE *fp; |
|
625 |
||
626 |
if (path != NULL) { |
|
627 |
/* push current state */ |
|
628 |
if (depth >= stacksize) { |
|
629 |
if (depth > MAX_SUDOERS_DEPTH) { |
|
630 |
yyerror("too many levels of includes"); |
|
631 |
return(FALSE); |
|
632 |
}
|
|
633 |
stacksize += SUDOERS_STACK_INCREMENT; |
|
634 |
state = (struct sudoers_state *) realloc(state, |
|
635 |
sizeof(state) * stacksize); |
|
636 |
if (state == NULL) { |
|
637 |
yyerror("unable to allocate memory"); |
|
638 |
return(FALSE); |
|
639 |
}
|
|
640 |
}
|
|
641 |
if ((fp = open_sudoers(path, &keepopen)) == NULL) { |
|
642 |
yyerror(path); |
|
643 |
return(FALSE); |
|
644 |
}
|
|
645 |
state[depth].bs = YY_CURRENT_BUFFER; |
|
646 |
state[depth].path = sudoers; |
|
647 |
state[depth].lineno = sudolineno; |
|
648 |
depth++; |
|
649 |
sudolineno = 1; |
|
650 |
sudoers = path; |
|
651 |
yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE)); |
|
652 |
} else { |
|
653 |
/* pop */ |
|
654 |
if (depth == 0) |
|
655 |
return(FALSE); |
|
656 |
depth--; |
|
657 |
if (!keepopen) |
|
658 |
fclose(YY_CURRENT_BUFFER->yy_input_file); |
|
659 |
yy_delete_buffer(YY_CURRENT_BUFFER); |
|
660 |
yy_switch_to_buffer(state[depth].bs); |
|
661 |
efree(sudoers); |
|
662 |
sudoers = state[depth].path; |
|
663 |
sudolineno = state[depth].lineno; |
|
664 |
keepopen = FALSE; |
|
665 |
}
|
|
666 |
return(TRUE); |
|
667 |
}
|
|
668 |
||
669 |
static char * |
|
670 |
parse_include(base) |
|
671 |
char *base; |
|
672 |
{
|
|
673 |
char *cp, *ep, *path; |
|
674 |
int len; |
|
675 |
||
676 |
/* Pull out path from #include line. */ |
|
677 |
cp = base + sizeof("#include"); |
|
678 |
while (isblank((unsigned char) *cp)) |
|
679 |
cp++; |
|
680 |
ep = cp; |
|
681 |
while (*ep != '\0' && !isspace((unsigned char) *ep)) |
|
682 |
ep++; |
|
683 |
||
684 |
/* Make a copy of path and return it. */ |
|
685 |
len = (int)(ep - cp); |
|
686 |
if ((path = malloc(len + 1)) == NULL) |
|
687 |
yyerror("unable to allocate memory"); |
|
688 |
memcpy(path, cp, len); |
|
689 |
path[len] = '\0'; |
|
690 |
||
691 |
/* Push any excess characters (e.g. comment, newline) back to the lexer */ |
|
692 |
if (*ep != '\0') |
|
693 |
yyless((int)(ep - base)); |
|
694 |
||
695 |
return(path); |
|
696 |
}
|
|
697 |
||
698 |
/*
|
|
699 |
* Check to make sure an IPv6 address does not contain multiple instances |
|
700 |
* of the string "::". Assumes strlen(s) >= 1. |
|
701 |
* Returns TRUE if address is valid else FALSE. |
|
702 |
*/
|
|
703 |
static int |
|
704 |
ipv6_valid(s) |
|
705 |
const char *s; |
|
706 |
{
|
|
707 |
int nmatch = 0; |
|
708 |
||
709 |
for (; *s != '\0'; s++) { |
|
710 |
if (s[0] == ':' && s[1] == ':') { |
|
711 |
if (++nmatch > 1) |
|
712 |
break; |
|
713 |
}
|
|
714 |
if (s[0] == '/') |
|
715 |
nmatch = 0; /* reset if we hit netmask */ |
|
716 |
}
|
|
717 |
||
718 |
return (nmatch <= 1); |
|
719 |
}
|