xref: /freebsd/usr.sbin/jail/jaillex.l (revision 7ef62cebc2f965b0f640263e179276928885e33d)
1 %{
2 /*-
3  * SPDX-License-Identifier: BSD-2-Clause
4  *
5  * Copyright (c) 2011 James Gritton
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32 
33 #include <err.h>
34 #include <stddef.h>
35 #include <stdlib.h>
36 #include <string.h>
37 
38 #include "jailp.h"
39 #include "y.tab.h"
40 
41 #define YY_DECL int yylex(YYSTYPE *yylval, yyscan_t yyscanner)
42 #define YY_EXTRA_TYPE struct cflex*
43 
44 extern YY_DECL;
45 
46 static ssize_t text2lval(size_t triml, size_t trimr, int tovar,
47     YYSTYPE *yylval, yyscan_t scanner);
48 
49 static int instr;
50 %}
51 
52 %option noyywrap
53 %option noinput
54 %option nounput
55 %option reentrant
56 %option yylineno
57 
58 %start _ DQ
59 
60 %%
61 
62 			/* Whitespace or equivalent */
63 <_>[ \t\r\n]+		instr = 0;
64 <_>#.*			instr = 0;
65 <_>\/\/.*		instr = 0;
66 <_>\/\*([^*]|(\*+([^*\/])))*\*+\/ instr = 0;
67 
68 			/* Reserved tokens */
69 <_>\+=			{
70 				instr = 0;
71 				return PLEQ;
72 			}
73 <_>[,;={}]		{
74 				instr = 0;
75 				return yytext[0];
76 			}
77 
78 			/* Atomic (unquoted) strings */
79 <_,DQ>[A-Za-z0-9_!%&()\-.:<>?@\[\]^`|~]+ |
80 <_,DQ>\\(.|\n|[0-7]{1,3}|x[0-9A-Fa-f]{1,2}) |
81 <_,DQ>[$*+/\\]		{
82 				(void)text2lval(0, 0, 0, yylval, yyscanner);
83 				return instr ? STR1 : (instr = 1, STR);
84 			}
85 
86 			/* Single and double quoted strings */
87 <_>'([^\'\\]|\\(.|\n))*' {
88 				(void)text2lval(1, 1, 0, yylval, yyscanner);
89 				return instr ? STR1 : (instr = 1, STR);
90 			}
91 <_>\"([^"\\]|\\(.|\n))*\" |
92 <DQ>[^\"$\\]([^"\\]|\\(.|\n))*\" {
93 				size_t skip;
94 				ssize_t atvar;
95 
96 				skip = yytext[0] == '"' ? 1 : 0;
97 				atvar = text2lval(skip, 1, 1, yylval,
98 					yyscanner);
99 				if (atvar < 0)
100 					BEGIN _;
101 				else {
102 					/*
103 					 * The string has a variable inside it.
104 					 * Go into DQ mode to get the variable
105 					 * and then the rest of the string.
106 					 */
107 					BEGIN DQ;
108 					yyless(atvar);
109 				}
110 				return instr ? STR1 : (instr = 1, STR);
111 			}
112 <DQ>\"			BEGIN _;
113 
114 			/* Variables, single-word or bracketed */
115 <_,DQ>$[A-Za-z_][A-Za-z_0-9]* {
116 				(void)text2lval(1, 0, 0, yylval, yyscanner);
117 				return instr ? VAR1 : (instr = 1, VAR);
118 			}
119 <_>$\{([^\n{}]|\\(.|\n))*\} |
120 <DQ>$\{([^\n\"{}]|\\(.|\n))*\} {
121 				(void)text2lval(2, 1, 0, yylval, yyscanner);
122 				return instr ? VAR1 : (instr = 1, VAR);
123 			}
124 
125 			/* Partially formed bits worth complaining about */
126 <_>\/\*([^*]|(\*+([^*\/])))*\** {
127 				warnx("%s line %d: unterminated comment",
128 				    yyextra->cfname, yylineno);
129 				yyextra->error = 1;
130 			}
131 <_>'([^\n'\\]|\\.)*	|
132 <_>\"([^\n\"\\]|\\.)*	{
133 				warnx("%s line %d: unterminated string",
134 				    yyextra->cfname, yylineno);
135 				yyextra->error = 1;
136 			}
137 <_>$\{([^\n{}]|\\.)*	|
138 <DQ>$\{([^\n\"{}]|\\.)*	{
139 				warnx("%s line %d: unterminated variable",
140 				    yyextra->cfname, yylineno);
141 				yyextra->error = 1;
142 			}
143 
144 			/* A hack because "<0>" rules aren't allowed */
145 <_>.			return yytext[0];
146 .|\n			{
147 				BEGIN _;
148 				yyless(0);
149 			}
150 
151 %%
152 
153 /*
154  * Copy string from yytext to yylval, handling backslash escapes,
155  * and optionally stopping at the beginning of a variable.
156  */
157 static ssize_t
158 text2lval(size_t triml, size_t trimr, int tovar, YYSTYPE *yylval,
159     yyscan_t scanner)
160 {
161 	char *d;
162 	const char *s, *se;
163 
164 	struct yyguts_t *yyg = scanner;
165 	yylval->cs = d = emalloc(yyleng - trimr - triml + 1);
166 	se = yytext + (yyleng - trimr);
167 	for (s = yytext + triml; s < se; s++, d++) {
168 		if (*s != '\\') {
169 			if (tovar && *s == '$') {
170 				*d = '\0';
171 				return s - yytext;
172 			}
173 			*d = *s;
174 			continue;
175 		}
176 		s++;
177 		if (*s >= '0' && *s <= '7') {
178 			*d = *s - '0';
179 			if (s + 1 < se && s[1] >= '0' && s[1] <= '7') {
180 				*d = 010 * *d + (*++s - '0');
181 				if (s + 1 < se && s[1] >= '0' && s[1] <= '7')
182 					*d = 010 * *d + (*++s - '0');
183 			}
184 			continue;
185 		}
186 		switch (*s) {
187 		case 'a':	*d = '\a';	break;
188 		case 'b':	*d = '\b';	break;
189 		case 'f':	*d = '\f';	break;
190 		case 'n':	*d = '\n';	break;
191 		case 'r':	*d = '\r';	break;
192 		case 't':	*d = '\t';	break;
193 		case 'v':	*d = '\v';	break;
194 		default:	*d = *s;	break;
195 		case '\n':	d--;		break;
196 		case 'x':
197 			*d = 0;
198 			if (s + 1 >= se)
199 				break;
200 			if (s[1] >= '0' && s[1] <= '9')
201 				*d = *++s - '0';
202 			else if (s[1] >= 'A' && s[1] <= 'F')
203 				*d = *++s + (0xA - 'A');
204 			else if (s[1] >= 'a' && s[1] <= 'f')
205 				*d = *++s + (0xa - 'a');
206 			else
207 				break;
208 			if (s + 1 >= se)
209 				break;
210 			if (s[1] >= '0' && s[1] <= '9')
211 				*d = *d * 0x10 + (*++s - '0');
212 			else if (s[1] >= 'A' && s[1] <= 'F')
213 				*d = *d * 0x10 + (*++s + (0xA - 'A'));
214 			else if (s[1] >= 'a' && s[1] <= 'f')
215 				*d = *d * 0x10 + (*++s + (0xa - 'a'));
216 		}
217 	}
218 	*d = '\0';
219 	return -1;
220 }
221