]>
Commit | Line | Data |
---|---|---|
189935b1 | 1 | /* |
2 | * ircd_parser.y: A yacc/bison parser for ircd config files. | |
3 | * This is part of ircu, an Internet Relay Chat server. | |
4 | * The contents of this file are Copyright 2001 Diane Bruce, | |
5 | * Andrew Miller, the ircd-hybrid team and the ircu team. | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation; either version 2 of the License, or | |
9 | * (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program; if not, write to the Free Software | |
18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | |
19 | * USA. | |
20 | * $Id: ircd_parser.y,v 1.56.2.1 2005/10/06 00:37:31 entrope Exp $ | |
21 | */ | |
22 | %{ | |
23 | ||
24 | #include "config.h" | |
25 | #include "s_conf.h" | |
26 | #include "class.h" | |
27 | #include "client.h" | |
28 | #include "crule.h" | |
29 | #include "ircd_features.h" | |
30 | #include "fileio.h" | |
31 | #include "gline.h" | |
32 | #include "hash.h" | |
33 | #include "ircd.h" | |
34 | #include "ircd_alloc.h" | |
35 | #include "ircd_auth.h" | |
36 | #include "ircd_chattr.h" | |
37 | #include "ircd_log.h" | |
38 | #include "ircd_reply.h" | |
39 | #include "ircd_snprintf.h" | |
40 | #include "ircd_string.h" | |
41 | #include "list.h" | |
42 | #include "listener.h" | |
43 | #include "match.h" | |
44 | #include "motd.h" | |
45 | #include "numeric.h" | |
46 | #include "numnicks.h" | |
47 | #include "opercmds.h" | |
48 | #include "parse.h" | |
49 | #include "res.h" | |
50 | #include "s_bsd.h" | |
51 | #include "s_conf.h" | |
52 | #include "s_debug.h" | |
53 | #include "s_misc.h" | |
54 | #include "send.h" | |
55 | #include "struct.h" | |
56 | #include "sys.h" | |
57 | #include <stdlib.h> | |
58 | #include <stdio.h> | |
59 | #include <string.h> | |
60 | #include <arpa/inet.h> | |
61 | #define MAX_STRINGS 80 /* Maximum number of feature params. */ | |
62 | extern struct LocalConf localConf; | |
63 | extern struct DenyConf* denyConfList; | |
64 | extern struct CRuleConf* cruleConfList; | |
65 | extern struct ServerConf* serverConfList; | |
66 | extern struct s_map* GlobalServiceMapList; | |
67 | extern struct qline* GlobalQuarantineList; | |
68 | ||
69 | int yylex(void); | |
70 | /* Now all the globals we need :/... */ | |
71 | int tping, tconn, maxlinks, sendq, port, invert, stringno, flags; | |
72 | char *name, *pass, *host, *ip, *username, *origin, *hub_limit; | |
73 | char *stringlist[MAX_STRINGS]; | |
74 | struct ConnectionClass *c_class; | |
75 | struct DenyConf *dconf; | |
76 | struct ServerConf *sconf; | |
77 | struct s_map *smap; | |
78 | struct Privs privs; | |
79 | struct Privs privs_dirty; | |
80 | ||
81 | static void parse_error(char *pattern,...) { | |
82 | static char error_buffer[1024]; | |
83 | va_list vl; | |
84 | va_start(vl,pattern); | |
85 | ircd_vsnprintf(NULL, error_buffer, sizeof(error_buffer), pattern, vl); | |
86 | va_end(vl); | |
87 | yyerror(error_buffer); | |
88 | } | |
89 | ||
90 | %} | |
91 | ||
92 | %token <text> QSTRING | |
93 | %token <num> NUMBER | |
94 | ||
95 | %token GENERAL | |
96 | %token ADMIN | |
97 | %token LOCATION | |
98 | %token CONTACT | |
99 | %token CONNECT | |
100 | %token CLASS | |
101 | %token CHANNEL | |
102 | %token PINGFREQ | |
103 | %token CONNECTFREQ | |
104 | %token MAXLINKS | |
105 | %token MAXHOPS | |
106 | %token SENDQ | |
107 | %token NAME | |
108 | %token HOST | |
109 | %token IP | |
110 | %token USERNAME | |
111 | %token PASS | |
112 | %token LOCAL | |
113 | %token SECONDS | |
114 | %token MINUTES | |
115 | %token HOURS | |
116 | %token DAYS | |
117 | %token WEEKS | |
118 | %token MONTHS | |
119 | %token YEARS | |
120 | %token DECADES | |
121 | %token BYTES | |
122 | %token KBYTES | |
123 | %token MBYTES | |
124 | %token GBYTES | |
125 | %token TBYTES | |
126 | %token SERVER | |
127 | %token PORT | |
128 | %token MASK | |
129 | %token HUB | |
130 | %token LEAF | |
131 | %token UWORLD | |
132 | %token YES | |
133 | %token NO | |
134 | %token OPER | |
135 | %token VHOST | |
136 | %token HIDDEN | |
137 | %token MOTD | |
138 | %token JUPE | |
139 | %token NICK | |
140 | %token NUMERIC | |
141 | %token DESCRIPTION | |
142 | %token CLIENT | |
143 | %token KILL | |
144 | %token CRULE | |
145 | %token REAL | |
146 | %token REASON | |
147 | %token TFILE | |
148 | %token RULE | |
149 | %token ALL | |
150 | %token FEATURES | |
151 | %token QUARANTINE | |
152 | %token PSEUDO | |
153 | %token PREPEND | |
154 | %token USERMODE | |
155 | %token IAUTH | |
156 | %token TIMEOUT | |
157 | %token FAST | |
158 | %token AUTOCONNECT | |
159 | /* and now a lot of privileges... */ | |
160 | %token TPRIV_CHAN_LIMIT TPRIV_MODE_LCHAN TPRIV_DEOP_LCHAN TPRIV_WALK_LCHAN | |
161 | %token TPRIV_LOCAL_KILL TPRIV_REHASH TPRIV_RESTART TPRIV_DIE | |
162 | %token TPRIV_GLINE TPRIV_LOCAL_GLINE TPRIV_LOCAL_JUPE TPRIV_LOCAL_BADCHAN | |
163 | %token TPRIV_LOCAL_OPMODE TPRIV_OPMODE TPRIV_SET TPRIV_WHOX TPRIV_BADCHAN | |
164 | %token TPRIV_SEE_CHAN TPRIV_SHOW_INVIS TPRIV_SHOW_ALL_INVIS TPRIV_PROPAGATE | |
165 | %token TPRIV_UNLIMIT_QUERY TPRIV_DISPLAY TPRIV_SEE_OPERS TPRIV_WIDE_GLINE | |
166 | %token TPRIV_FORCE_OPMODE TPRIV_FORCE_LOCAL_OPMODE TPRIV_APASS_OPMODE | |
167 | /* and some types... */ | |
168 | %type <num> sizespec | |
169 | %type <num> timespec timefactor factoredtimes factoredtime | |
170 | %type <num> expr yesorno privtype | |
171 | %left '+' '-' | |
172 | %left '*' '/' | |
173 | ||
174 | %union{ | |
175 | char *text; | |
176 | int num; | |
177 | } | |
178 | ||
179 | %% | |
180 | /* Blocks in the config file... */ | |
181 | blocks: blocks block | block; | |
182 | block: adminblock | generalblock | classblock | connectblock | | |
183 | uworldblock | operblock | portblock | jupeblock | clientblock | | |
184 | killblock | cruleblock | motdblock | featuresblock | quarantineblock | | |
185 | pseudoblock | iauthblock | error ';'; | |
186 | ||
187 | /* The timespec, sizespec and expr was ripped straight from | |
188 | * ircd-hybrid-7. */ | |
189 | timespec: expr | factoredtimes; | |
190 | ||
191 | factoredtimes: factoredtimes factoredtime | |
192 | { | |
193 | $$ = $1 + $2; | |
194 | } | factoredtime; | |
195 | ||
196 | factoredtime: expr timefactor | |
197 | { | |
198 | $$ = $1 * $2; | |
199 | }; | |
200 | ||
201 | timefactor: SECONDS { $$ = 1; } | |
202 | | MINUTES { $$ = 60; } | |
203 | | HOURS { $$ = 60 * 60; } | |
204 | | DAYS { $$ = 60 * 60 * 24; } | |
205 | | WEEKS { $$ = 60 * 60 * 24 * 7; } | |
206 | | MONTHS { $$ = 60 * 60 * 24 * 7 * 4; } | |
207 | | YEARS { $$ = 60 * 60 * 24 * 365; } | |
208 | | DECADES { $$ = 60 * 60 * 24 * 365 * 10; }; | |
209 | ||
210 | ||
211 | sizespec: expr { | |
212 | $$ = $1; | |
213 | } | |
214 | | expr BYTES { | |
215 | $$ = $1; | |
216 | } | |
217 | | expr KBYTES { | |
218 | $$ = $1 * 1024; | |
219 | } | |
220 | | expr MBYTES { | |
221 | $$ = $1 * 1024 * 1024; | |
222 | } | |
223 | | expr GBYTES { | |
224 | $$ = $1 * 1024 * 1024 * 1024; | |
225 | } | |
226 | | expr TBYTES { | |
227 | $$ = $1 * 1024 * 1024 * 1024; | |
228 | } | |
229 | ; | |
230 | ||
231 | /* this is an arithmetic expression */ | |
232 | expr: NUMBER | |
233 | { | |
234 | $$ = $1; | |
235 | } | |
236 | | expr '+' expr { | |
237 | $$ = $1 + $3; | |
238 | } | |
239 | | expr '-' expr { | |
240 | $$ = $1 - $3; | |
241 | } | |
242 | | expr '*' expr { | |
243 | $$ = $1 * $3; | |
244 | } | |
245 | | expr '/' expr { | |
246 | $$ = $1 / $3; | |
247 | } | |
248 | /* leave this out until we find why it makes BSD yacc dump core -larne | |
249 | | '-' expr %prec NEG { | |
250 | $$ = -$2; | |
251 | } */ | |
252 | | '(' expr ')' { | |
253 | $$ = $2; | |
254 | } | |
255 | ; | |
256 | ||
257 | jupeblock: JUPE '{' jupeitems '}' ';' ; | |
258 | jupeitems: jupeitem jupeitems | jupeitem; | |
259 | jupeitem: jupenick; | |
260 | jupenick: NICK '=' QSTRING ';' | |
261 | { | |
262 | addNickJupes($3); | |
263 | MyFree($3); | |
264 | }; | |
265 | ||
266 | generalblock: GENERAL | |
267 | { | |
268 | /* Zero out the vhost addresses, in case they were removed. */ | |
269 | memset(&VirtualHost_v4.addr, 0, sizeof(VirtualHost_v4.addr)); | |
270 | memset(&VirtualHost_v6.addr, 0, sizeof(VirtualHost_v6.addr)); | |
271 | } '{' generalitems '}' ';' { | |
272 | if (localConf.name == NULL) | |
273 | parse_error("Your General block must contain a name."); | |
274 | if (localConf.numeric == 0) | |
275 | parse_error("Your General block must contain a numeric (between 1 and 4095)."); | |
276 | }; | |
277 | generalitems: generalitem generalitems | generalitem; | |
278 | generalitem: generalnumeric | generalname | generalvhost | generaldesc; | |
279 | generalnumeric: NUMERIC '=' NUMBER ';' | |
280 | { | |
281 | if (localConf.numeric == 0) | |
282 | localConf.numeric = $3; | |
283 | else if (localConf.numeric != $3) | |
284 | parse_error("Redefinition of server numeric %i (%i)", $3, | |
285 | localConf.numeric); | |
286 | }; | |
287 | ||
288 | generalname: NAME '=' QSTRING ';' | |
289 | { | |
290 | if (localConf.name == NULL) | |
291 | localConf.name = $3; | |
292 | else { | |
293 | if (strcmp(localConf.name, $3)) | |
294 | parse_error("Redefinition of server name %s (%s)", $3, | |
295 | localConf.name); | |
296 | MyFree($3); | |
297 | } | |
298 | }; | |
299 | ||
300 | generaldesc: DESCRIPTION '=' QSTRING ';' | |
301 | { | |
302 | MyFree(localConf.description); | |
303 | localConf.description = $3; | |
304 | ircd_strncpy(cli_info(&me), $3, REALLEN); | |
305 | }; | |
306 | ||
307 | generalvhost: VHOST '=' QSTRING ';' | |
308 | { | |
309 | struct irc_in_addr addr; | |
310 | if (!strcmp($3, "*")) { | |
311 | /* This traditionally meant bind to all interfaces and connect | |
312 | * from the default. */ | |
313 | } else if (!ircd_aton(&addr, $3)) | |
314 | parse_error("Invalid virtual host '%s'.", $3); | |
315 | else if (irc_in_addr_is_ipv4(&addr)) | |
316 | memcpy(&VirtualHost_v4.addr, &addr, sizeof(addr)); | |
317 | else | |
318 | memcpy(&VirtualHost_v6.addr, &addr, sizeof(addr)); | |
319 | MyFree($3); | |
320 | }; | |
321 | ||
322 | adminblock: ADMIN '{' adminitems '}' ';' | |
323 | { | |
324 | if (localConf.location1 == NULL) | |
325 | DupString(localConf.location1, ""); | |
326 | if (localConf.location2 == NULL) | |
327 | DupString(localConf.location2, ""); | |
328 | if (localConf.contact == NULL) | |
329 | DupString(localConf.contact, ""); | |
330 | }; | |
331 | adminitems: adminitems adminitem | adminitem; | |
332 | adminitem: adminlocation | admincontact; | |
333 | adminlocation: LOCATION '=' QSTRING ';' | |
334 | { | |
335 | if (localConf.location1 == NULL) | |
336 | localConf.location1 = $3; | |
337 | else if (localConf.location2 == NULL) | |
338 | localConf.location2 = $3; | |
339 | else /* Otherwise just drop it. -A1kmm */ | |
340 | MyFree($3); | |
341 | }; | |
342 | admincontact: CONTACT '=' QSTRING ';' | |
343 | { | |
344 | MyFree(localConf.contact); | |
345 | localConf.contact = $3; | |
346 | }; | |
347 | ||
348 | classblock: CLASS { | |
349 | tping = 90; | |
350 | } '{' classitems '}' ';' | |
351 | { | |
352 | if (name != NULL) | |
353 | { | |
354 | struct ConnectionClass *c_class; | |
355 | add_class(name, tping, tconn, maxlinks, sendq); | |
356 | c_class = find_class(name); | |
357 | MyFree(c_class->default_umode); | |
358 | c_class->default_umode = pass; | |
359 | memcpy(&c_class->privs, &privs, sizeof(c_class->privs)); | |
360 | memcpy(&c_class->privs_dirty, &privs_dirty, sizeof(c_class->privs_dirty)); | |
361 | } | |
362 | else { | |
363 | parse_error("Missing name in class block"); | |
364 | } | |
365 | name = NULL; | |
366 | pass = NULL; | |
367 | tconn = 0; | |
368 | maxlinks = 0; | |
369 | sendq = 0; | |
370 | memset(&privs, 0, sizeof(privs)); | |
371 | memset(&privs_dirty, 0, sizeof(privs_dirty)); | |
372 | }; | |
373 | classitems: classitem classitems | classitem; | |
374 | classitem: classname | classpingfreq | classconnfreq | classmaxlinks | | |
375 | classsendq | classusermode | priv; | |
376 | classname: NAME '=' QSTRING ';' | |
377 | { | |
378 | MyFree(name); | |
379 | name = $3; | |
380 | }; | |
381 | classpingfreq: PINGFREQ '=' timespec ';' | |
382 | { | |
383 | tping = $3; | |
384 | }; | |
385 | classconnfreq: CONNECTFREQ '=' timespec ';' | |
386 | { | |
387 | tconn = $3; | |
388 | }; | |
389 | classmaxlinks: MAXLINKS '=' expr ';' | |
390 | { | |
391 | maxlinks = $3; | |
392 | }; | |
393 | classsendq: SENDQ '=' sizespec ';' | |
394 | { | |
395 | sendq = $3; | |
396 | }; | |
397 | classusermode: USERMODE '=' QSTRING ';' | |
398 | { | |
399 | MyFree(pass); | |
400 | pass = $3; | |
401 | }; | |
402 | ||
403 | connectblock: CONNECT | |
404 | { | |
405 | maxlinks = 65535; | |
406 | flags = CONF_AUTOCONNECT; | |
407 | } '{' connectitems '}' ';' | |
408 | { | |
409 | struct ConfItem *aconf = NULL; | |
410 | if (name == NULL) | |
411 | parse_error("Missing name in connect block"); | |
412 | else if (pass == NULL) | |
413 | parse_error("Missing password in connect block"); | |
414 | else if (host == NULL) | |
415 | parse_error("Missing host in connect block"); | |
416 | else if (strchr(host, '*') || strchr(host, '?')) | |
417 | parse_error("Invalid host '%s' in connect block", host); | |
418 | else if (c_class == NULL) | |
419 | parse_error("Missing or non-existent class in connect block"); | |
420 | else { | |
421 | aconf = make_conf(CONF_SERVER); | |
422 | aconf->name = name; | |
423 | aconf->origin_name = origin; | |
424 | aconf->passwd = pass; | |
425 | aconf->conn_class = c_class; | |
426 | aconf->address.port = port; | |
427 | aconf->host = host; | |
428 | aconf->maximum = maxlinks; | |
429 | aconf->hub_limit = hub_limit; | |
430 | aconf->flags = flags; | |
431 | lookup_confhost(aconf); | |
432 | } | |
433 | if (!aconf) { | |
434 | MyFree(name); | |
435 | MyFree(pass); | |
436 | MyFree(host); | |
437 | MyFree(origin); | |
438 | MyFree(hub_limit); | |
439 | } | |
440 | name = pass = host = origin = hub_limit = NULL; | |
441 | c_class = NULL; | |
442 | port = flags = 0; | |
443 | }; | |
444 | connectitems: connectitem connectitems | connectitem; | |
445 | connectitem: connectname | connectpass | connectclass | connecthost | |
446 | | connectport | connectvhost | connectleaf | connecthub | |
447 | | connecthublimit | connectmaxhops | connectauto; | |
448 | connectname: NAME '=' QSTRING ';' | |
449 | { | |
450 | MyFree(name); | |
451 | name = $3; | |
452 | }; | |
453 | connectpass: PASS '=' QSTRING ';' | |
454 | { | |
455 | MyFree(pass); | |
456 | pass = $3; | |
457 | }; | |
458 | connectclass: CLASS '=' QSTRING ';' | |
459 | { | |
460 | c_class = find_class($3); | |
461 | if (!c_class) | |
462 | parse_error("No such connection class '%s' for Connect block", $3); | |
463 | MyFree($3); | |
464 | }; | |
465 | connecthost: HOST '=' QSTRING ';' | |
466 | { | |
467 | MyFree(host); | |
468 | host = $3; | |
469 | }; | |
470 | connectport: PORT '=' NUMBER ';' | |
471 | { | |
472 | port = $3; | |
473 | }; | |
474 | connectvhost: VHOST '=' QSTRING ';' | |
475 | { | |
476 | MyFree(origin); | |
477 | origin = $3; | |
478 | }; | |
479 | connectleaf: LEAF ';' | |
480 | { | |
481 | maxlinks = 0; | |
482 | }; | |
483 | connecthub: HUB ';' | |
484 | { | |
485 | MyFree(hub_limit); | |
486 | DupString(hub_limit, "*"); | |
487 | }; | |
488 | connecthublimit: HUB '=' QSTRING ';' | |
489 | { | |
490 | MyFree(hub_limit); | |
491 | hub_limit = $3; | |
492 | }; | |
493 | connectmaxhops: MAXHOPS '=' expr ';' | |
494 | { | |
495 | maxlinks = $3; | |
496 | }; | |
497 | connectauto: AUTOCONNECT '=' YES ';' { flags |= CONF_AUTOCONNECT; } | |
498 | | AUTOCONNECT '=' NO ';' { flags &= ~CONF_AUTOCONNECT; }; | |
499 | ||
500 | uworldblock: UWORLD '{' uworlditems '}' ';'; | |
501 | uworlditems: uworlditem uworlditems | uworlditem; | |
502 | uworlditem: uworldname; | |
503 | uworldname: NAME '=' QSTRING ';' | |
504 | { | |
505 | make_conf(CONF_UWORLD)->host = $3; | |
506 | }; | |
507 | ||
508 | operblock: OPER '{' operitems '}' ';' | |
509 | { | |
510 | struct ConfItem *aconf = NULL; | |
511 | if (name == NULL) | |
512 | parse_error("Missing name in operator block"); | |
513 | else if (pass == NULL) | |
514 | parse_error("Missing password in operator block"); | |
515 | else if (host == NULL) | |
516 | parse_error("Missing host in operator block"); | |
517 | else if (c_class == NULL) | |
518 | parse_error("Invalid or missing class in operator block"); | |
519 | else { | |
520 | aconf = make_conf(CONF_OPERATOR); | |
521 | aconf->name = name; | |
522 | aconf->passwd = pass; | |
523 | conf_parse_userhost(aconf, host); | |
524 | aconf->conn_class = c_class; | |
525 | memcpy(&aconf->privs, &privs, sizeof(aconf->privs)); | |
526 | memcpy(&aconf->privs_dirty, &privs_dirty, sizeof(aconf->privs_dirty)); | |
527 | if (!FlagHas(&privs_dirty, PRIV_PROPAGATE) | |
528 | && !FlagHas(&c_class->privs_dirty, PRIV_PROPAGATE)) | |
529 | parse_error("Operator block for %s and class %s have no LOCAL setting", name, c_class->cc_name); | |
530 | } | |
531 | if (!aconf) { | |
532 | MyFree(name); | |
533 | MyFree(pass); | |
534 | MyFree(host); | |
535 | } | |
536 | name = pass = host = NULL; | |
537 | c_class = NULL; | |
538 | memset(&privs, 0, sizeof(privs)); | |
539 | memset(&privs_dirty, 0, sizeof(privs_dirty)); | |
540 | }; | |
541 | operitems: operitem | operitems operitem; | |
542 | operitem: opername | operpass | operhost | operclass | priv; | |
543 | opername: NAME '=' QSTRING ';' | |
544 | { | |
545 | MyFree(name); | |
546 | name = $3; | |
547 | }; | |
548 | operpass: PASS '=' QSTRING ';' | |
549 | { | |
550 | MyFree(pass); | |
551 | pass = $3; | |
552 | }; | |
553 | operhost: HOST '=' QSTRING ';' | |
554 | { | |
555 | MyFree(host); | |
556 | if (!strchr($3, '@')) | |
557 | { | |
558 | int uh_len; | |
559 | host = (char*) MyMalloc((uh_len = strlen($3)+3)); | |
560 | ircd_snprintf(0, host, uh_len, "*@%s", $3); | |
561 | MyFree($3); | |
562 | } | |
563 | else | |
564 | host = $3; | |
565 | }; | |
566 | operclass: CLASS '=' QSTRING ';' | |
567 | { | |
568 | c_class = find_class($3); | |
569 | if (!c_class) | |
570 | parse_error("No such connection class '%s' for Operator block", $3); | |
571 | MyFree($3); | |
572 | }; | |
573 | ||
574 | priv: privtype '=' yesorno ';' | |
575 | { | |
576 | FlagSet(&privs_dirty, $1); | |
577 | if (($3 == 1) ^ invert) | |
578 | FlagSet(&privs, $1); | |
579 | else | |
580 | FlagClr(&privs, $1); | |
581 | invert = 0; | |
582 | }; | |
583 | ||
584 | privtype: TPRIV_CHAN_LIMIT { $$ = PRIV_CHAN_LIMIT; } | | |
585 | TPRIV_MODE_LCHAN { $$ = PRIV_MODE_LCHAN; } | | |
586 | TPRIV_DEOP_LCHAN { $$ = PRIV_DEOP_LCHAN; } | | |
587 | TPRIV_WALK_LCHAN { $$ = PRIV_WALK_LCHAN; } | | |
588 | KILL { $$ = PRIV_KILL; } | | |
589 | TPRIV_LOCAL_KILL { $$ = PRIV_LOCAL_KILL; } | | |
590 | TPRIV_REHASH { $$ = PRIV_REHASH; } | | |
591 | TPRIV_RESTART { $$ = PRIV_RESTART; } | | |
592 | TPRIV_DIE { $$ = PRIV_DIE; } | | |
593 | TPRIV_GLINE { $$ = PRIV_GLINE; } | | |
594 | TPRIV_LOCAL_GLINE { $$ = PRIV_LOCAL_GLINE; } | | |
595 | JUPE { $$ = PRIV_JUPE; } | | |
596 | TPRIV_LOCAL_JUPE { $$ = PRIV_LOCAL_JUPE; } | | |
597 | TPRIV_LOCAL_OPMODE { $$ = PRIV_LOCAL_OPMODE; } | | |
598 | TPRIV_OPMODE { $$ = PRIV_OPMODE; }| | |
599 | TPRIV_SET { $$ = PRIV_SET; } | | |
600 | TPRIV_WHOX { $$ = PRIV_WHOX; } | | |
601 | TPRIV_BADCHAN { $$ = PRIV_BADCHAN; } | | |
602 | TPRIV_LOCAL_BADCHAN { $$ = PRIV_LOCAL_BADCHAN; } | | |
603 | TPRIV_SEE_CHAN { $$ = PRIV_SEE_CHAN; } | | |
604 | TPRIV_SHOW_INVIS { $$ = PRIV_SHOW_INVIS; } | | |
605 | TPRIV_SHOW_ALL_INVIS { $$ = PRIV_SHOW_ALL_INVIS; } | | |
606 | TPRIV_PROPAGATE { $$ = PRIV_PROPAGATE; } | | |
607 | TPRIV_UNLIMIT_QUERY { $$ = PRIV_UNLIMIT_QUERY; } | | |
608 | TPRIV_DISPLAY { $$ = PRIV_DISPLAY; } | | |
609 | TPRIV_SEE_OPERS { $$ = PRIV_SEE_OPERS; } | | |
610 | TPRIV_WIDE_GLINE { $$ = PRIV_WIDE_GLINE; } | | |
611 | LOCAL { $$ = PRIV_PROPAGATE; invert = 1; } | | |
612 | TPRIV_FORCE_OPMODE { $$ = PRIV_FORCE_OPMODE; } | | |
613 | TPRIV_FORCE_LOCAL_OPMODE { $$ = PRIV_FORCE_LOCAL_OPMODE; } | | |
614 | TPRIV_APASS_OPMODE { $$ = PRIV_APASS_OPMODE; } ; | |
615 | ||
616 | yesorno: YES { $$ = 1; } | NO { $$ = 0; }; | |
617 | ||
618 | /* The port block... */ | |
619 | portblock: PORT '{' portitems '}' ';' | |
620 | { | |
621 | if (port > 0 && port <= 0xFFFF) | |
622 | add_listener(port, host, pass, tconn, tping); | |
623 | else | |
624 | parse_error("Port %d is out of range", port); | |
625 | MyFree(host); | |
626 | MyFree(pass); | |
627 | host = pass = NULL; | |
628 | port = tconn = tping = 0; | |
629 | }; | |
630 | portitems: portitem portitems | portitem; | |
631 | portitem: portnumber | portvhost | portmask | portserver | porthidden; | |
632 | portnumber: PORT '=' NUMBER ';' | |
633 | { | |
634 | port = $3; | |
635 | }; | |
636 | ||
637 | portvhost: VHOST '=' QSTRING ';' | |
638 | { | |
639 | MyFree(host); | |
640 | host = $3; | |
641 | }; | |
642 | ||
643 | portmask: MASK '=' QSTRING ';' | |
644 | { | |
645 | MyFree(pass); | |
646 | pass = $3; | |
647 | }; | |
648 | ||
649 | portserver: SERVER '=' YES ';' | |
650 | { | |
651 | tconn = -1; | |
652 | } | SERVER '=' NO ';' | |
653 | { | |
654 | tconn = 0; | |
655 | }; | |
656 | ||
657 | porthidden: HIDDEN '=' YES ';' | |
658 | { | |
659 | tping = -1; | |
660 | } | HIDDEN '=' NO ';' | |
661 | { | |
662 | tping = 0; | |
663 | }; | |
664 | ||
665 | clientblock: CLIENT | |
666 | { | |
667 | maxlinks = 65535; | |
668 | port = 0; | |
669 | } | |
670 | '{' clientitems '}' ';' | |
671 | { | |
672 | struct ConfItem *aconf = 0; | |
673 | struct irc_in_addr addr; | |
674 | unsigned char addrbits = 0; | |
675 | ||
676 | if (!c_class) | |
677 | parse_error("Invalid or missing class in Client block"); | |
678 | else if (ip && !ipmask_parse(ip, &addr, &addrbits)) | |
679 | parse_error("Invalid IP address %s in Client block", ip); | |
680 | else { | |
681 | aconf = make_conf(CONF_CLIENT); | |
682 | aconf->username = username; | |
683 | aconf->host = host; | |
684 | if (ip) | |
685 | memcpy(&aconf->address.addr, &addr, sizeof(aconf->address.addr)); | |
686 | else | |
687 | memset(&aconf->address.addr, 0, sizeof(aconf->address.addr)); | |
688 | aconf->address.port = port; | |
689 | aconf->addrbits = addrbits; | |
690 | aconf->name = ip; | |
691 | aconf->conn_class = c_class; | |
692 | aconf->maximum = maxlinks; | |
693 | aconf->passwd = pass; | |
694 | } | |
695 | if (!aconf) { | |
696 | MyFree(username); | |
697 | MyFree(host); | |
698 | MyFree(ip); | |
699 | MyFree(pass); | |
700 | } | |
701 | host = NULL; | |
702 | username = NULL; | |
703 | c_class = NULL; | |
704 | ip = NULL; | |
705 | pass = NULL; | |
706 | port = 0; | |
707 | }; | |
708 | clientitems: clientitem clientitems | clientitem; | |
709 | clientitem: clienthost | clientip | clientusername | clientclass | clientpass | clientmaxlinks | clientport; | |
710 | clienthost: HOST '=' QSTRING ';' | |
711 | { | |
712 | char *sep = strchr($3, '@'); | |
713 | MyFree(host); | |
714 | if (sep) { | |
715 | *sep++ = '\0'; | |
716 | MyFree(username); | |
717 | DupString(host, sep); | |
718 | username = $3; | |
719 | } else { | |
720 | host = $3; | |
721 | } | |
722 | }; | |
723 | clientip: IP '=' QSTRING ';' | |
724 | { | |
725 | char *sep; | |
726 | sep = strchr($3, '@'); | |
727 | MyFree(ip); | |
728 | if (sep) { | |
729 | *sep++ = '\0'; | |
730 | MyFree(username); | |
731 | DupString(ip, sep); | |
732 | username = $3; | |
733 | } else { | |
734 | ip = $3; | |
735 | } | |
736 | }; | |
737 | clientusername: USERNAME '=' QSTRING ';' | |
738 | { | |
739 | MyFree(username); | |
740 | username = $3; | |
741 | }; | |
742 | clientclass: CLASS '=' QSTRING ';' | |
743 | { | |
744 | c_class = find_class($3); | |
745 | if (!c_class) | |
746 | parse_error("No such connection class '%s' for Class block", $3); | |
747 | MyFree($3); | |
748 | }; | |
749 | clientpass: PASS '=' QSTRING ';' | |
750 | { | |
751 | MyFree(pass); | |
752 | pass = $3; | |
753 | }; | |
754 | clientmaxlinks: MAXLINKS '=' expr ';' | |
755 | { | |
756 | maxlinks = $3; | |
757 | }; | |
758 | clientport: PORT '=' expr ';' | |
759 | { | |
760 | port = $3; | |
761 | }; | |
762 | ||
763 | killblock: KILL | |
764 | { | |
765 | dconf = (struct DenyConf*) MyCalloc(1, sizeof(*dconf)); | |
766 | } '{' killitems '}' ';' | |
767 | { | |
768 | if (dconf->usermask || dconf->hostmask ||dconf->realmask) { | |
769 | dconf->next = denyConfList; | |
770 | denyConfList = dconf; | |
771 | } | |
772 | else | |
773 | { | |
774 | MyFree(dconf->usermask); | |
775 | MyFree(dconf->hostmask); | |
776 | MyFree(dconf->realmask); | |
777 | MyFree(dconf->message); | |
778 | MyFree(dconf); | |
779 | parse_error("Kill block must match on at least one of username, host or realname"); | |
780 | } | |
781 | dconf = NULL; | |
782 | }; | |
783 | killitems: killitem killitems | killitem; | |
784 | killitem: killuhost | killreal | killusername | killreasonfile | killreason; | |
785 | killuhost: HOST '=' QSTRING ';' | |
786 | { | |
787 | char *h; | |
788 | MyFree(dconf->hostmask); | |
789 | MyFree(dconf->usermask); | |
790 | if ((h = strchr($3, '@')) == NULL) | |
791 | { | |
792 | DupString(dconf->usermask, "*"); | |
793 | dconf->hostmask = $3; | |
794 | } | |
795 | else | |
796 | { | |
797 | *h++ = '\0'; | |
798 | DupString(dconf->hostmask, h); | |
799 | dconf->usermask = $3; | |
800 | } | |
801 | ipmask_parse(dconf->hostmask, &dconf->address, &dconf->bits); | |
802 | }; | |
803 | ||
804 | killusername: USERNAME '=' QSTRING ';' | |
805 | { | |
806 | MyFree(dconf->usermask); | |
807 | dconf->usermask = $3; | |
808 | }; | |
809 | ||
810 | killreal: REAL '=' QSTRING ';' | |
811 | { | |
812 | MyFree(dconf->realmask); | |
813 | dconf->realmask = $3; | |
814 | }; | |
815 | ||
816 | killreason: REASON '=' QSTRING ';' | |
817 | { | |
818 | dconf->flags &= ~DENY_FLAGS_FILE; | |
819 | MyFree(dconf->message); | |
820 | dconf->message = $3; | |
821 | }; | |
822 | ||
823 | killreasonfile: TFILE '=' QSTRING ';' | |
824 | { | |
825 | dconf->flags |= DENY_FLAGS_FILE; | |
826 | MyFree(dconf->message); | |
827 | dconf->message = $3; | |
828 | }; | |
829 | ||
830 | cruleblock: CRULE | |
831 | { | |
832 | tconn = CRULE_AUTO; | |
833 | } '{' cruleitems '}' ';' | |
834 | { | |
835 | struct CRuleNode *node = NULL; | |
836 | if (host == NULL) | |
837 | parse_error("Missing host in crule block"); | |
838 | else if (pass == NULL) | |
839 | parse_error("Missing rule in crule block"); | |
840 | else if ((node = crule_parse(pass)) == NULL) | |
841 | parse_error("Invalid rule '%s' in crule block", pass); | |
842 | else | |
843 | { | |
844 | struct CRuleConf *p = (struct CRuleConf*) MyMalloc(sizeof(*p)); | |
845 | p->hostmask = host; | |
846 | p->rule = pass; | |
847 | p->type = tconn; | |
848 | p->node = node; | |
849 | p->next = cruleConfList; | |
850 | cruleConfList = p; | |
851 | } | |
852 | if (!node) | |
853 | { | |
854 | MyFree(host); | |
855 | MyFree(pass); | |
856 | } | |
857 | host = pass = NULL; | |
858 | tconn = 0; | |
859 | }; | |
860 | ||
861 | cruleitems: cruleitem cruleitems | cruleitem; | |
862 | cruleitem: cruleserver | crulerule | cruleall; | |
863 | ||
864 | cruleserver: SERVER '=' QSTRING ';' | |
865 | { | |
866 | MyFree(host); | |
867 | collapse($3); | |
868 | host = $3; | |
869 | }; | |
870 | ||
871 | crulerule: RULE '=' QSTRING ';' | |
872 | { | |
873 | MyFree(pass); | |
874 | pass = $3; | |
875 | }; | |
876 | ||
877 | cruleall: ALL '=' YES ';' | |
878 | { | |
879 | tconn = CRULE_ALL; | |
880 | } | ALL '=' NO ';' | |
881 | { | |
882 | tconn = CRULE_AUTO; | |
883 | }; | |
884 | ||
885 | motdblock: MOTD '{' motditems '}' ';' | |
886 | { | |
887 | if (host != NULL && pass != NULL) | |
888 | motd_add(host, pass); | |
889 | MyFree(host); | |
890 | MyFree(pass); | |
891 | host = pass = NULL; | |
892 | }; | |
893 | ||
894 | motditems: motditem motditems | motditem; | |
895 | motditem: motdhost | motdfile; | |
896 | motdhost: HOST '=' QSTRING ';' | |
897 | { | |
898 | host = $3; | |
899 | }; | |
900 | ||
901 | motdfile: TFILE '=' QSTRING ';' | |
902 | { | |
903 | pass = $3; | |
904 | }; | |
905 | ||
906 | featuresblock: FEATURES '{' featureitems '}' ';'; | |
907 | featureitems: featureitems featureitem | featureitem; | |
908 | ||
909 | featureitem: QSTRING | |
910 | { | |
911 | stringlist[0] = $1; | |
912 | stringno = 1; | |
913 | } '=' stringlist ';'; | |
914 | ||
915 | stringlist: QSTRING | |
916 | { | |
917 | stringlist[1] = $1; | |
918 | stringno = 2; | |
919 | } posextrastrings | |
920 | { | |
921 | unsigned int ii; | |
922 | feature_set(NULL, (const char * const *)stringlist, stringno); | |
923 | for (ii = 0; ii < stringno; ++ii) | |
924 | MyFree(stringlist[ii]); | |
925 | }; | |
926 | posextrastrings: /* empty */ | extrastrings; | |
927 | extrastrings: extrastrings extrastring | extrastring; | |
928 | extrastring: QSTRING | |
929 | { | |
930 | if (stringno < MAX_STRINGS) | |
931 | stringlist[stringno++] = $1; | |
932 | else | |
933 | MyFree($1); | |
934 | }; | |
935 | ||
936 | quarantineblock: QUARANTINE '{' quarantineitems '}' ';'; | |
937 | quarantineitems: quarantineitems quarantineitem | quarantineitem; | |
938 | quarantineitem: QSTRING '=' QSTRING ';' | |
939 | { | |
940 | struct qline *qconf = MyCalloc(1, sizeof(*qconf)); | |
941 | qconf->chname = $1; | |
942 | qconf->reason = $3; | |
943 | qconf->next = GlobalQuarantineList; | |
944 | GlobalQuarantineList = qconf; | |
945 | }; | |
946 | ||
947 | pseudoblock: PSEUDO QSTRING '{' | |
948 | { | |
949 | smap = MyCalloc(1, sizeof(struct s_map)); | |
950 | smap->command = $2; | |
951 | } | |
952 | pseudoitems '}' ';' | |
953 | { | |
954 | int valid = 0; | |
955 | ||
956 | if (!smap->name) | |
957 | parse_error("Missing name in pseudo %s block", smap->command); | |
958 | else if (!smap->services) | |
959 | parse_error("Missing nick in pseudo %s block", smap->command); | |
960 | else | |
961 | valid = 1; | |
962 | if (valid && register_mapping(smap)) | |
963 | { | |
964 | smap->next = GlobalServiceMapList; | |
965 | GlobalServiceMapList = smap; | |
966 | } | |
967 | else | |
968 | { | |
969 | free_mapping(smap); | |
970 | } | |
971 | smap = NULL; | |
972 | }; | |
973 | ||
974 | pseudoitems: pseudoitem pseudoitems | pseudoitem; | |
975 | pseudoitem: pseudoname | pseudoprepend | pseudonick | pseudoflags; | |
976 | pseudoname: NAME '=' QSTRING ';' | |
977 | { | |
978 | MyFree(smap->name); | |
979 | smap->name = $3; | |
980 | }; | |
981 | pseudoprepend: PREPEND '=' QSTRING ';' | |
982 | { | |
983 | MyFree(smap->prepend); | |
984 | smap->prepend = $3; | |
985 | }; | |
986 | pseudonick: NICK '=' QSTRING ';' | |
987 | { | |
988 | char *sep = strchr($3, '@'); | |
989 | ||
990 | if (sep != NULL) { | |
991 | size_t slen = strlen($3); | |
992 | struct nick_host *nh = MyMalloc(sizeof(*nh) + slen); | |
993 | memcpy(nh->nick, $3, slen + 1); | |
994 | nh->nicklen = sep - $3; | |
995 | nh->next = smap->services; | |
996 | smap->services = nh; | |
997 | } | |
998 | MyFree($3); | |
999 | }; | |
1000 | pseudoflags: FAST ';' | |
1001 | { | |
1002 | smap->flags |= SMAP_FAST; | |
1003 | }; | |
1004 | ||
1005 | iauthblock: IAUTH '{' | |
1006 | { | |
1007 | tconn = 60; | |
1008 | tping = 60; | |
1009 | } iauthitems '}' ';' | |
1010 | { | |
1011 | if (!host) | |
1012 | parse_error("Missing host in iauth block"); | |
1013 | else if (!port) | |
1014 | parse_error("Missing port in iauth block"); | |
1015 | else | |
1016 | iauth_connect(host, port, pass, tconn, tping); | |
1017 | MyFree(pass); | |
1018 | MyFree(host); | |
1019 | pass = host = NULL; | |
1020 | port = tconn = tping = 0; | |
1021 | }; | |
1022 | ||
1023 | iauthitems: iauthitem iauthitems | iauthitem; | |
1024 | iauthitem: iauthpass | iauthhost | iauthport | iauthconnfreq | iauthtimeout; | |
1025 | iauthpass: PASS '=' QSTRING ';' | |
1026 | { | |
1027 | MyFree(pass); | |
1028 | pass = $3; | |
1029 | }; | |
1030 | iauthhost: HOST '=' QSTRING ';' | |
1031 | { | |
1032 | MyFree(host); | |
1033 | host = $3; | |
1034 | }; | |
1035 | iauthport: PORT '=' NUMBER ';' | |
1036 | { | |
1037 | port = $3; | |
1038 | }; | |
1039 | iauthconnfreq: CONNECTFREQ '=' timespec ';' | |
1040 | { | |
1041 | tconn = $3; | |
1042 | }; | |
1043 | iauthtimeout: TIMEOUT '=' timespec ';' | |
1044 | { | |
1045 | tping = $3; | |
1046 | }; |