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