]> jfr.im git - irc.git/blame - software/ircd/www.irc.org/ftp/irc/org/Old/irc2.11.2p1/ircd/s_conf.c
init
[irc.git] / software / ircd / www.irc.org / ftp / irc / org / Old / irc2.11.2p1 / ircd / s_conf.c
CommitLineData
3bd189cb
JR
1/************************************************************************
2 * IRC - Internet Relay Chat, ircd/s_conf.c
3 * Copyright (C) 1990 Jarkko Oikarinen and
4 * University of Oulu, Computing Center
5 *
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 1, or (at your option)
9 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21/* -- avalon -- 20 Feb 1992
22 * Reversed the order of the params for attach_conf().
23 * detach_conf() and attach_conf() are now the same:
24 * function_conf(aClient *, aConfItem *)
25 */
26
27/* -- Jto -- 20 Jun 1990
28 * Added gruner's overnight fix..
29 */
30
31/* -- Jto -- 16 Jun 1990
32 * Moved matches to ../common/match.c
33 */
34
35/* -- Jto -- 03 Jun 1990
36 * Added Kill fixes from gruner@lan.informatik.tu-muenchen.de
37 * Added jarlek's msgbase fix (I still don't understand it... -- Jto)
38 */
39
40/* -- Jto -- 13 May 1990
41 * Added fixes from msa:
42 * Comments and return value to init_conf()
43 */
44
45/*
46 * -- Jto -- 12 May 1990
47 * Added close() into configuration file (was forgotten...)
48 */
49
50#ifndef lint
51static const volatile char rcsid[] = "@(#)$Id: s_conf.c,v 1.187 2008/06/24 22:24:52 chopin Exp $";
52#endif
53
54#include "os.h"
55#include "s_defines.h"
56#define S_CONF_C
57#include "s_externs.h"
58#undef S_CONF_C
59#ifdef ENABLE_CIDR_LIMITS
60#include "patricia_ext.h"
61#endif
62
63#ifdef TIMEDKLINES
64static int check_time_interval (char *, char *);
65#endif
66static int lookup_confhost (aConfItem *);
67
68#ifdef CONFIG_DIRECTIVE_INCLUDE
69#include "config_read.c"
70#endif
71
72aConfItem *conf = NULL;
73aConfItem *kconf = NULL;
74char *networkname = NULL;
75#ifdef TKLINE
76aConfItem *tkconf = NULL;
77#endif
78
79/* Parse I-lines flags from string.
80 * D - Restricted, if no DNS.
81 * I - Restricted, if no ident.
82 * R - Restricted.
83 * E - Kline exempt.
84 * N - Do not resolve hostnames (show as IP).
85 * F - Fallthrough to next I:line when password not matched
86 */
87long iline_flags_parse(char *string)
88{
89 long tmp = 0;
90
91 if (!string)
92 {
93 return 0;
94 }
95
96 if (index(string,'D'))
97 {
98 tmp |= CFLAG_RNODNS;
99 }
100 if (index(string,'I'))
101 {
102 tmp |= CFLAG_RNOIDENT;
103 }
104 if (index(string,'R'))
105 {
106 tmp |= CFLAG_RESTRICTED;
107 }
108 if (index(string,'E'))
109 {
110 tmp |= CFLAG_KEXEMPT;
111 }
112#ifdef XLINE
113 if (index(string,'e'))
114 {
115 tmp |= CFLAG_XEXEMPT;
116 }
117#endif
118 if (index(string,'N'))
119 {
120 tmp |= CFLAG_NORESOLVE;
121 }
122 if (index(string,'M'))
123 {
124 tmp |= CFLAG_NORESOLVEMATCH;
125 }
126 if (index(string,'F'))
127 {
128 tmp |= CFLAG_FALL;
129 }
130
131 return tmp;
132}
133
134/* convert iline flags to human readable string */
135char *iline_flags_to_string(long flags)
136{
137 static char ifsbuf[BUFSIZE];
138 char *s = ifsbuf;
139
140 if (flags & CFLAG_RNODNS)
141 {
142 *s++ = 'D';
143 }
144 if (flags & CFLAG_RNOIDENT)
145 {
146 *s++ = 'I';
147 }
148 if (flags & CFLAG_RESTRICTED)
149 {
150 *s++ = 'R';
151 }
152 if (flags & CFLAG_KEXEMPT)
153 {
154 *s++ = 'E';
155 }
156#ifdef XLINE
157 if (flags & CFLAG_XEXEMPT)
158 {
159 *s++ = 'e';
160 }
161#endif
162 if (flags & CFLAG_NORESOLVE)
163 {
164 *s++ = 'N';
165 }
166 if (flags & CFLAG_NORESOLVEMATCH)
167 {
168 *s++ = 'M';
169 }
170 if (flags & CFLAG_FALL)
171 {
172 *s++ = 'F';
173 }
174 if (s == ifsbuf)
175 {
176 *s++ = '-';
177 }
178 *s++ = '\0';
179
180 return ifsbuf;
181}
182/* Convert P-line flags from string
183 * D - delayed port
184 * S - server only port
185 */
186long pline_flags_parse(char *string)
187{
188 long tmp = 0;
189 if (index(string, 'D'))
190 {
191 tmp |= PFLAG_DELAYED;
192 }
193 if (index(string, 'S'))
194 {
195 tmp |= PFLAG_SERVERONLY;
196 }
197 return tmp;
198}
199/* Convert P-line flags from integer to string
200 */
201char *pline_flags_to_string(long flags)
202{
203 static char pfsbuf[BUFSIZE];
204 char *s = pfsbuf;
205
206 if (flags & PFLAG_DELAYED)
207 {
208 *s++ = 'D';
209 }
210
211 if (flags & PFLAG_SERVERONLY)
212 {
213 *s++ = 'S';
214 }
215
216 if (s == pfsbuf)
217 {
218 *s++ = '-';
219 }
220
221 *s++ = '\0';
222 return pfsbuf;
223}
224
225/* convert oline flags to human readable string */
226char *oline_flags_to_string(long flags)
227{
228 static char ofsbuf[BUFSIZE];
229 char *s = ofsbuf;
230
231 if (flags & ACL_LOCOP)
232 *s++ = 'L';
233 if (flags & ACL_KILLREMOTE)
234 *s++ = 'K';
235 else if (flags & ACL_KILLLOCAL)
236 *s++ = 'k';
237 if (flags & ACL_SQUITREMOTE)
238 *s++ ='S';
239 else if (flags & ACL_SQUITLOCAL)
240 *s++ ='s';
241 if (flags & ACL_CONNECTREMOTE)
242 *s++ ='C';
243 else if (flags & ACL_CONNECTLOCAL)
244 *s++ ='c';
245 if (flags & ACL_CLOSE)
246 *s++ ='l';
247 if (flags & ACL_HAZH)
248 *s++ ='h';
249 if (flags & ACL_DNS)
250 *s++ ='d';
251 if (flags & ACL_REHASH)
252 *s++ ='r';
253 if (flags & ACL_RESTART)
254 *s++ ='R';
255 if (flags & ACL_DIE)
256 *s++ ='D';
257 if (flags & ACL_SET)
258 *s++ ='e';
259 if (flags & ACL_TKLINE)
260 *s++ ='T';
261 if (flags & ACL_KLINE)
262 *s++ ='q';
263#ifdef CLIENTS_CHANNEL
264 if (flags & ACL_CLIENTS)
265 *s++ ='&';
266#endif
267 if (flags & ACL_NOPENALTY)
268 *s++ = 'P';
269 if (flags & ACL_CANFLOOD)
270 *s++ = 'p';
271 if (flags & ACL_TRACE)
272 *s++ = 't';
273#ifdef ENABLE_SIDTRACE
274 if (flags & ACL_SIDTRACE)
275 *s++ = 'v';
276#endif
277 if (s == ofsbuf)
278 *s++ = '-';
279 *s++ = '\0';
280 return ofsbuf;
281}
282/* convert string from config to flags */
283long oline_flags_parse(char *string)
284{
285 long tmp = 0;
286 char *s;
287
288 for (s = string; *s; s++)
289 {
290 switch(*s)
291 {
292 case 'L': tmp |= ACL_LOCOP; break;
293 case 'A': tmp |= (ACL_ALL &
294 ~(ACL_LOCOP|ACL_CLIENTS|ACL_NOPENALTY|ACL_CANFLOOD));
295 break;
296 case 'K': tmp |= ACL_KILL; break;
297 case 'k': tmp |= ACL_KILLLOCAL; break;
298 case 'S': tmp |= ACL_SQUIT; break;
299 case 's': tmp |= ACL_SQUITLOCAL; break;
300 case 'C': tmp |= ACL_CONNECT; break;
301 case 'c': tmp |= ACL_CONNECTLOCAL; break;
302 case 'l': tmp |= ACL_CLOSE; break;
303 case 'h': tmp |= ACL_HAZH; break;
304 case 'd': tmp |= ACL_DNS; break;
305 case 'r': tmp |= ACL_REHASH; break;
306 case 'R': tmp |= ACL_RESTART; break;
307 case 'D': tmp |= ACL_DIE; break;
308 case 'e': tmp |= ACL_SET; break;
309 case 'T': tmp |= ACL_TKLINE; break;
310 case 'q': tmp |= ACL_KLINE; break;
311#ifdef CLIENTS_CHANNEL
312 case '&': tmp |= ACL_CLIENTS; break;
313#endif
314 case 'P': tmp |= ACL_NOPENALTY; break;
315 case 'p': tmp |= ACL_CANFLOOD; break;
316 case 't': tmp |= ACL_TRACE; break;
317#ifdef ENABLE_SIDTRACE
318 case 'v': tmp |= ACL_SIDTRACE; break;
319#endif
320 }
321 }
322 if (tmp & ACL_LOCOP)
323 tmp &= ~ACL_ALL_REMOTE;
324#ifdef OPER_KILL
325# ifndef OPER_KILL_REMOTE
326 tmp &= ~ACL_KILLREMOTE;
327# endif
328#else
329 tmp &= ~ACL_KILL;
330#endif
331#ifndef OPER_REHASH
332 tmp &= ~ACL_REHASH;
333#endif
334#ifndef OPER_SQUIT
335 tmp &= ~ACL_SQUIT;
336#endif
337#ifndef OPER_CONNECT
338 tmp &= ~ACL_CONNECT;
339#endif
340#ifndef OPER_RESTART
341 tmp &= ~ACL_RESTART;
342#endif
343#ifndef OPER_DIE
344 tmp &= ~ACL_DIE;
345#endif
346#ifndef OPER_SET
347 tmp &= ~ACL_SET;
348#endif
349#ifndef OPER_TKLINE
350 tmp &= ~ACL_TKLINE;
351#endif
352#ifndef OPER_KLINE
353 tmp &= ~ACL_KLINE;
354#endif
355 return tmp;
356}
357/*
358 * remove all conf entries from the client except those which match
359 * the status field mask.
360 */
361void det_confs_butmask(aClient *cptr, int mask)
362{
363 Reg Link *tmp, *tmp2;
364
365 for (tmp = cptr->confs; tmp; tmp = tmp2)
366 {
367 tmp2 = tmp->next;
368 if ((tmp->value.aconf->status & mask) == 0)
369 (void)detach_conf(cptr, tmp->value.aconf);
370 }
371}
372
373/*
374 * Match address by #IP bitmask (10.11.12.128/27)
375 * Now should work for IPv6 too.
376 * returns -1 on error, 0 on match, 1 when NO match.
377 */
378int match_ipmask(char *mask, aClient *cptr, int maskwithusername)
379{
380 int m;
381 char *p;
382 struct IN_ADDR addr;
383 char dummy[128];
384 char *omask;
385 u_long lmask;
386#ifdef INET6
387 int j;
388#endif
389
390 omask = mask;
391 strncpyzt(dummy, mask, sizeof(dummy));
392 mask = dummy;
393 if (maskwithusername && (p = index(mask, '@')))
394 {
395 *p = '\0';
396 if (match(mask, cptr->username))
397 return 1;
398 mask = p + 1;
399 }
400 if (!(p = index(mask, '/')))
401 goto badmask;
402 *p = '\0';
403
404 if (sscanf(p + 1, "%d", &m) != 1)
405 {
406 goto badmask;
407 }
408 if (!m)
409 return 0; /* x.x.x.x/0 always matches */
410#ifndef INET6
411 if (m < 0 || m > 32)
412 goto badmask;
413 lmask = htonl((u_long)0xffffffffL << (32 - m));
414 addr.s_addr = inetaddr(mask);
415 return ((addr.s_addr ^ cptr->ip.s_addr) & lmask) ? 1 : 0;
416#else
417 if (m < 0 || m > 128)
418 goto badmask;
419
420 if (inetpton(AF_INET6, mask, (void *)addr.s6_addr) != 1)
421 {
422 return -1;
423 }
424
425 /* Make sure that the ipv4 notation still works. */
426 if (IN6_IS_ADDR_V4MAPPED(&addr))
427 {
428 if (m <= 32)
429 m += 96;
430 if (m <= 96)
431 goto badmask;
432 }
433
434 j = m & 0x1F; /* number not mutliple of 32 bits */
435 m >>= 5; /* number of 32 bits */
436
437 if (m && memcmp((void *)(addr.s6_addr),
438 (void *)(cptr->ip.s6_addr), m << 2))
439 return 1;
440
441 if (j)
442 {
443 lmask = htonl((u_long)0xffffffffL << (32 - j));
444 if ((((u_int32_t *)(addr.s6_addr))[m] ^
445 ((u_int32_t *)(cptr->ip.s6_addr))[m]) & lmask)
446 return 1;
447 }
448
449 return 0;
450#endif
451badmask:
452 if (maskwithusername)
453 sendto_flag(SCH_ERROR, "Ignoring bad mask: %s", omask);
454 return -1;
455}
456
457/*
458 * find the first (best) I line to attach.
459 */
460
461#define UHConfMatch(x, y, z) (match((x), (index((x), '@') ? (y) : (y)+(z))))
462
463int attach_Iline(aClient *cptr, struct hostent *hp, char *sockhost)
464{
465 Reg aConfItem *aconf;
466 char uhost[HOSTLEN+USERLEN+2];
467 char uaddr[HOSTLEN+USERLEN+2];
468 int ulen = strlen(cptr->username) + 1; /* for '@' */
469 int retval = -2; /* EXITC_NOILINE in register_user() */
470
471 /* We fill uaddr and uhost now, before aconf loop. */
472 sprintf(uaddr, "%s@%s", cptr->username, sockhost);
473 if (hp)
474 {
475 char fullname[HOSTLEN+1];
476
477 /* If not for add_local_domain, I wouldn't need this
478 ** fullname. Can't we add_local_domain somewhere in
479 ** dns code? --B. */
480 strncpyzt(fullname, hp->h_name, sizeof(fullname));
481 add_local_domain(fullname, HOSTLEN - strlen(fullname));
482 Debug((DEBUG_DNS, "a_il: %s->%s", sockhost, fullname));
483 sprintf(uhost, "%s@%s", cptr->username, fullname);
484 }
485 /* all uses of uhost are guarded by if (hp), so no need to zero it. */
486
487 for (aconf = conf; aconf; aconf = aconf->next)
488 {
489 if ((aconf->status != CONF_CLIENT))
490 {
491 continue;
492 }
493 if (aconf->port && aconf->port != cptr->acpt->port)
494 {
495 continue;
496 }
497 /* aconf->name can be NULL with wrong I:line in the config
498 ** (without all required fields). If aconf->host can be NULL,
499 ** I don't know. Anyway, this is an error! --B. */
500 if (!aconf->host || !aconf->name)
501 {
502 /* Try another I:line. */
503 continue;
504 }
505
506 /* If anything in aconf->name... */
507 if (*aconf->name)
508 {
509 int namematched = 0;
510
511 if (hp)
512 {
513 if (!UHConfMatch(aconf->name, uhost, ulen))
514 {
515 namematched = 1;
516 }
517 }
518 /* Note: here we could do else (!hp) and try to
519 ** check if aconf->name is '*' or '*@*' and
520 ** if so, allow the client. But not doing so
521 ** gives us nice opportunity to distinguish
522 ** between '*' in aconf->name (requires DNS)
523 ** and empty aconf->name (matches any). --B. */
524
525 /* Require name to match before checking addr fields. */
526 if (namematched == 0)
527 {
528 /* Try another I:line. */
529 continue;
530 }
531 } /* else empty aconf->name, match any hostname. */
532
533 if (*aconf->host)
534 {
535#ifdef UNIXPORT
536 if (IsUnixSocket(cptr) && aconf->host[0] == '/')
537 {
538 if (match(aconf->host, uaddr+ulen))
539 {
540 /* Try another I:line. */
541 continue;
542 }
543 }
544 else
545#endif
546 if (strchr(aconf->host, '/')) /* 1.2.3.0/24 */
547 {
548
549 /* match_ipmask takes care of checking
550 ** possible username if aconf->host has '@' */
551 if (match_ipmask(aconf->host, cptr, 1))
552 {
553 /* Try another I:line. */
554 continue;
555 }
556 }
557 else /* 1.2.3.* */
558 {
559 if (UHConfMatch(aconf->host, uaddr, ulen))
560 {
561 /* Try another I:line. */
562 continue;
563 }
564 }
565 } /* else empty aconf->host, match any ipaddr */
566
567 /* Password check, if I:line has it. If 'F' flag, try another
568 ** I:line, otherwise bail out and reject client. */
569 if (!BadPtr(aconf->passwd) &&
570 !StrEq(cptr->passwd, aconf->passwd))
571 {
572 if (IsConfFallThrough(aconf))
573 {
574 continue;
575 }
576 else
577 {
578 sendto_one(cptr, replies[ERR_PASSWDMISMATCH],
579 ME, BadTo(cptr->name));
580 retval = -8; /* EXITC_BADPASS */
581 break;
582 }
583 }
584
585 /* Various cases of +r. */
586 if (IsConfRestricted(aconf) ||
587 (!hp && IsConfRNoDNS(aconf)) ||
588 (!(cptr->flags & FLAGS_GOTID) && IsConfRNoIdent(aconf)))
589 {
590 SetRestricted(cptr);
591 }
592 if (IsConfKlineExempt(aconf))
593 {
594 SetKlineExempt(cptr);
595 }
596#ifdef XLINE
597 if (IsConfXlineExempt(aconf))
598 {
599 ClearXlined(cptr);
600 }
601#endif
602
603 /* Copy uhost (hostname) over sockhost, if conf flag permits. */
604 if (hp && !IsConfNoResolve(aconf))
605 {
606 get_sockhost(cptr, uhost+ulen);
607 }
608 /* Note that attach_conf() should not return -2. */
609 if ((retval = attach_conf(cptr, aconf)) < -1)
610 {
611 find_bounce(cptr, ConfClass(aconf), -1);
612 }
613 break;
614 }
615 if (retval == -2)
616 {
617 find_bounce(cptr, 0, -2);
618 }
619 return retval;
620}
621
622/*
623 * Find the single N line and return pointer to it (from list).
624 * If more than one then return NULL pointer.
625 */
626aConfItem *count_cnlines(Link *lp)
627{
628 Reg aConfItem *aconf, *cline = NULL, *nline = NULL;
629
630 for (; lp; lp = lp->next)
631 {
632 aconf = lp->value.aconf;
633 if (!(aconf->status & CONF_SERVER_MASK))
634 continue;
635 if ((aconf->status == CONF_CONNECT_SERVER ||
636 aconf->status == CONF_ZCONNECT_SERVER) && !cline)
637 cline = aconf;
638 else if (aconf->status == CONF_NOCONNECT_SERVER && !nline)
639 nline = aconf;
640 }
641 return nline;
642}
643
644#ifdef ENABLE_CIDR_LIMITS
645static int add_cidr_limit(aClient *cptr, aConfItem *aconf)
646{
647 patricia_node_t *pnode;
648
649 if(aconf->class->cidr_amount == 0 || aconf->class->cidr_len == 0)
650 return -1;
651
652 pnode = patricia_match_ip(ConfCidrTree(aconf), &cptr->ip);
653
654 /* doesnt exist, create and then allow */
655 if(pnode == NULL)
656 {
657 pnode = patricia_make_and_lookup_ip(ConfCidrTree(aconf),
658 &cptr->ip,
659 aconf->class->cidr_len);
660
661 if(pnode == NULL)
662 return -1;
663
664 pnode->data++;
665 return 1;
666 }
667
668 if((long)pnode->data >= aconf->class->cidr_amount)
669 return 0;
670
671 pnode->data++;
672 return 1;
673}
674
675static void remove_cidr_limit(aClient *cptr, aConfItem *aconf)
676{
677 patricia_node_t *pnode;
678
679 if(ConfMaxCidrAmount(aconf) == 0 || ConfCidrLen(aconf) == 0)
680 return;
681
682 pnode = patricia_match_ip(ConfCidrTree(aconf), &cptr->ip);
683
684 if(pnode == NULL)
685 return;
686
687 pnode->data--;
688
689 if(((unsigned long) pnode->data) == 0)
690 patricia_remove(ConfCidrTree(aconf), pnode);
691}
692#endif /* ENABLE_CIDR_LIMITS */
693
694/*
695** detach_conf
696** Disassociate configuration from the client.
697** Also removes a class from the list if marked for deleting.
698*/
699int detach_conf(aClient *cptr, aConfItem *aconf)
700{
701 Reg Link **lp, *tmp;
702 aConfItem **aconf2,*aconf3;
703
704 lp = &(cptr->confs);
705
706 while (*lp)
707 {
708 if ((*lp)->value.aconf == aconf)
709 {
710 if ((aconf) && (Class(aconf)))
711 {
712 if (aconf->status & CONF_CLIENT_MASK)
713 {
714 if (ConfLinks(aconf) > 0)
715 --ConfLinks(aconf);
716#ifdef ENABLE_CIDR_LIMITS
717 if ((aconf->status & CONF_CLIENT))
718 remove_cidr_limit(cptr, aconf);
719#endif
720 }
721
722 if (ConfMaxLinks(aconf) == -1 &&
723 ConfLinks(aconf) == 0)
724 {
725 free_class(Class(aconf));
726 Class(aconf) = NULL;
727 }
728 }
729 if (aconf && --aconf->clients <= 0 && IsIllegal(aconf))
730 {
731 /* Remove the conf entry from the Conf linked list */
732 for (aconf2 = &conf; (aconf3 = *aconf2); )
733 {
734 if (aconf3 == aconf)
735 {
736 *aconf2 = aconf3->next;
737 aconf3->next = NULL;
738 free_conf(aconf);
739 }
740 else
741 {
742 aconf2 = &aconf3->next;
743 }
744 }
745 }
746 tmp = *lp;
747 *lp = tmp->next;
748 free_link(tmp);
749 istat.is_conflink--;
750 return 0;
751 }
752 else
753 lp = &((*lp)->next);
754 }
755 return -1;
756}
757
758static int is_attached(aConfItem *aconf, aClient *cptr)
759{
760 Reg Link *lp;
761
762 for (lp = cptr->confs; lp; lp = lp->next)
763 if (lp->value.aconf == aconf)
764 break;
765
766 return (lp) ? 1 : 0;
767}
768
769/*
770** attach_conf
771** Associate a specific configuration entry to a *local*
772** client (this is the one which used in accepting the
773** connection). Note, that this automaticly changes the
774** attachment if there was an old one...
775** Non-zero return value is used in register_user().
776*/
777int attach_conf(aClient *cptr, aConfItem *aconf)
778{
779 Reg Link *lp;
780
781 if (is_attached(aconf, cptr))
782 return 1;
783 if (IsIllegal(aconf))
784 return -1; /* EXITC_FAILURE, hmm */
785 if ((aconf->status & (CONF_OPERATOR | CONF_CLIENT )))
786 {
787 if (
788#ifdef YLINE_LIMITS_OLD_BEHAVIOUR
789 aconf->clients >= ConfMaxLinks(aconf)
790#else
791 ConfLinks(aconf) >= ConfMaxLinks(aconf)
792#endif
793 && ConfMaxLinks(aconf) > 0)
794 return -3; /* EXITC_YLINEMAX */
795 }
796
797 if ((aconf->status & CONF_CLIENT))
798 {
799 int hcnt = 0, ucnt = 0;
800 int ghcnt = 0, gucnt = 0;
801 anUser *user = NULL;
802 /* check on local/global limits per host and per user@host */
803
804#ifdef ENABLE_CIDR_LIMITS
805 if(!add_cidr_limit(cptr, aconf))
806 return -4; /* EXITC_LHMAX */
807#endif
808 /*
809 ** local limits first to save CPU if any is hit.
810 ** host check is done on the IP address.
811 ** user check is done on the IDENT reply.
812 */
813 if (ConfMaxHLocal(aconf) > 0 || ConfMaxUHLocal(aconf) > 0 ||
814 ConfMaxHGlobal(aconf) > 0 || ConfMaxUHGlobal(aconf) > 0 )
815 {
816#ifdef YLINE_LIMITS_IPHASH
817 for ((user = hash_find_ip(cptr->user->sip, NULL));
818 user; user = user->iphnext)
819 if (!mycmp(cptr->user->sip, user->sip))
820#else
821 for ((user = hash_find_hostname(cptr->sockhost, NULL));
822 user; user = user->hhnext)
823 if (!mycmp(cptr->sockhost, user->host))
824#endif
825 {
826 ghcnt++;
827 if (ConfMaxHGlobal(aconf) > 0 &&
828 ghcnt >= ConfMaxHGlobal(aconf))
829 {
830 return -6; /* EXITC_GHMAX */
831 }
832 if (MyConnect(user->bcptr))
833 {
834 hcnt++;
835 if (ConfMaxHLocal(aconf) > 0 &&
836 hcnt >= ConfMaxHLocal(aconf))
837 {
838 return -4; /* EXITC_LHMAX */
839 }
840 if (!mycmp(user->bcptr->auth,
841 cptr->auth))
842 {
843 ucnt++;
844 gucnt++;
845 }
846 }
847 else
848 {
849 if (!mycmp(user->username,
850 cptr->user->username
851 ))
852 {
853 gucnt++;
854 }
855 }
856 if (ConfMaxUHLocal(aconf) > 0 &&
857 ucnt >= ConfMaxUHLocal(aconf))
858 {
859 return -5; /* EXITC_LUHMAX */
860 }
861
862 if (ConfMaxUHGlobal(aconf) > 0 &&
863 gucnt >= ConfMaxUHGlobal(aconf))
864 {
865 return -7; /* EXITC_GUHMAX */
866 }
867 }
868 }
869 }
870
871
872 lp = make_link();
873 istat.is_conflink++;
874 lp->next = cptr->confs;
875 lp->value.aconf = aconf;
876 cptr->confs = lp;
877 cptr->ping = get_client_ping(cptr);
878 aconf->clients++;
879 if (aconf->status & CONF_CLIENT_MASK)
880 ConfLinks(aconf)++;
881 return 0;
882}
883
884
885aConfItem *find_admin(void)
886{
887 Reg aConfItem *aconf;
888
889 for (aconf = conf; aconf; aconf = aconf->next)
890 if (aconf->status & CONF_ADMIN)
891 break;
892
893 return (aconf);
894}
895
896aConfItem *find_me(void)
897{
898 Reg aConfItem *aconf;
899 for (aconf = conf; aconf; aconf = aconf->next)
900 if (aconf->status & CONF_ME)
901 break;
902
903 return (aconf);
904}
905
906/*
907 * attach_confs
908 * Attach a CONF line to a client if the name passed matches that for
909 * the conf file (for non-C/N lines) or is an exact match (C/N lines
910 * only). The difference in behaviour is to stop C:*::* and N:*::*.
911 */
912aConfItem *attach_confs(aClient *cptr, char *name, int statmask)
913{
914 Reg aConfItem *tmp;
915 aConfItem *first = NULL;
916 int len = strlen(name);
917
918 if (!name || len > HOSTLEN)
919 return NULL;
920 for (tmp = conf; tmp; tmp = tmp->next)
921 {
922 if ((tmp->status & statmask) && !IsIllegal(tmp) &&
923 ((tmp->status & (CONF_SERVER_MASK|CONF_HUB)) == 0) &&
924 tmp->name && !match(tmp->name, name))
925 {
926 if (!attach_conf(cptr, tmp) && !first)
927 first = tmp;
928 }
929 else if ((tmp->status & statmask) && !IsIllegal(tmp) &&
930 (tmp->status & (CONF_SERVER_MASK|CONF_HUB)) &&
931 tmp->name && !mycmp(tmp->name, name))
932 {
933 if (!attach_conf(cptr, tmp) && !first)
934 first = tmp;
935 }
936 }
937 return (first);
938}
939
940/*
941 * Added for new access check meLazy
942 */
943aConfItem *attach_confs_host(aClient *cptr, char *host, int statmask)
944{
945 Reg aConfItem *tmp;
946 aConfItem *first = NULL;
947 int len = strlen(host);
948
949 if (!host || len > HOSTLEN)
950 return NULL;
951
952 for (tmp = conf; tmp; tmp = tmp->next)
953 {
954 if ((tmp->status & statmask) && !IsIllegal(tmp) &&
955 (tmp->status & CONF_SERVER_MASK) == 0 &&
956 (!tmp->host || match(tmp->host, host) == 0))
957 {
958 if (!attach_conf(cptr, tmp) && !first)
959 first = tmp;
960 }
961 else if ((tmp->status & statmask) && !IsIllegal(tmp) &&
962 (tmp->status & CONF_SERVER_MASK) &&
963 (tmp->host && mycmp(tmp->host, host) == 0))
964 {
965 if (!attach_conf(cptr, tmp) && !first)
966 first = tmp;
967 }
968 }
969 return (first);
970}
971
972/*
973 * find a conf entry which matches the hostname and has the same name.
974 */
975aConfItem *find_conf_exact(char *name, char *user, char *host,
976 int statmask)
977{
978 Reg aConfItem *tmp;
979 char userhost[USERLEN+HOSTLEN+3];
980
981 sprintf(userhost, "%s@%s", user, host);
982
983 for (tmp = conf; tmp; tmp = tmp->next)
984 {
985 if (!(tmp->status & statmask) || !tmp->name || !tmp->host ||
986 mycmp(tmp->name, name))
987 continue;
988 /*
989 ** Accept if the *real* hostname (usually sockecthost)
990 ** socket host) matches *either* host or name field
991 ** of the configuration.
992 */
993 if (match(tmp->host, userhost))
994 continue;
995 if (tmp->status & CONF_OPERATOR)
996 {
997 if (tmp->clients < MaxLinks(Class(tmp)))
998 return tmp;
999 else
1000 continue;
1001 }
1002 else
1003 return tmp;
1004 }
1005 return NULL;
1006}
1007
1008/*
1009 * find an O-line which matches the hostname and has the same "name".
1010 */
1011aConfItem *find_Oline(char *name, aClient *cptr)
1012{
1013 Reg aConfItem *tmp;
1014 char userhost[USERLEN+HOSTLEN+3];
1015 char userip[USERLEN+HOSTLEN+3];
1016
1017 sprintf(userhost, "%s@%s", cptr->username, cptr->sockhost);
1018 sprintf(userip, "%s@%s", cptr->username,
1019#ifdef INET6
1020 (char *)inetntop(AF_INET6, (char *)&cptr->ip, ipv6string,
1021 sizeof(ipv6string))
1022#else
1023 (char *)inetntoa((char *)&cptr->ip)
1024#endif
1025 );
1026
1027
1028 for (tmp = conf; tmp; tmp = tmp->next)
1029 {
1030 if (!(tmp->status & (CONF_OPS)) || !tmp->name || !tmp->host ||
1031 mycmp(tmp->name, name))
1032 continue;
1033 /*
1034 ** Accept if the *real* hostname matches the host field or
1035 ** the ip does.
1036 */
1037 if (match(tmp->host, userhost) && match(tmp->host, userip) &&
1038 (!strchr(tmp->host, '/')
1039 || match_ipmask(tmp->host, cptr, 1)))
1040 continue;
1041 if (tmp->clients < MaxLinks(Class(tmp)))
1042 return tmp;
1043 }
1044 return NULL;
1045}
1046
1047
1048aConfItem *find_conf_name(char *name, int statmask)
1049{
1050 Reg aConfItem *tmp;
1051
1052 for (tmp = conf; tmp; tmp = tmp->next)
1053 {
1054 /*
1055 ** Accept if the hostname matches name field
1056 ** of the configuration.
1057 */
1058 if ((tmp->status & statmask) &&
1059 (!tmp->name || match(tmp->name, name) == 0))
1060 return tmp;
1061 }
1062 return NULL;
1063}
1064
1065aConfItem *find_conf(Link *lp, char *name, int statmask)
1066{
1067 Reg aConfItem *tmp;
1068 int namelen = name ? strlen(name) : 0;
1069
1070 if (namelen > HOSTLEN)
1071 return (aConfItem *) 0;
1072
1073 for (; lp; lp = lp->next)
1074 {
1075 tmp = lp->value.aconf;
1076 if ((tmp->status & statmask) &&
1077 (((tmp->status & (CONF_SERVER_MASK|CONF_HUB)) &&
1078 tmp->name && !mycmp(tmp->name, name)) ||
1079 ((tmp->status & (CONF_SERVER_MASK|CONF_HUB)) == 0 &&
1080 tmp->name && !match(tmp->name, name))))
1081 return tmp;
1082 }
1083 return NULL;
1084}
1085
1086/*
1087 * Added for new access check meLazy
1088 */
1089aConfItem *find_conf_host(Link *lp, char *host, int statmask)
1090{
1091 Reg aConfItem *tmp;
1092 int hostlen = host ? strlen(host) : 0;
1093
1094 if (hostlen > HOSTLEN || BadPtr(host))
1095 return (aConfItem *)NULL;
1096 for (; lp; lp = lp->next)
1097 {
1098 tmp = lp->value.aconf;
1099 if (tmp->status & statmask &&
1100 (!(tmp->status & CONF_SERVER_MASK || tmp->host) ||
1101 (tmp->host && !match(tmp->host, host))))
1102 return tmp;
1103 }
1104 return NULL;
1105}
1106
1107aConfItem *find_conf_host_sid(Link *lp, char *host, char *sid, int statmask)
1108{
1109 Reg aConfItem *tmp;
1110 int hostlen = host ? strlen(host) : 0;
1111
1112 if (hostlen > HOSTLEN || BadPtr(host))
1113 return (aConfItem *)NULL;
1114 for (; lp; lp = lp->next)
1115 {
1116 tmp = lp->value.aconf;
1117 if (tmp->status & statmask &&
1118 (!(tmp->status & CONF_SERVER_MASK || tmp->host) ||
1119 (tmp->host && !match(tmp->host, host))) &&
1120 (!tmp->passwd || !tmp->passwd[0] ||
1121 !match(tmp->passwd, sid)) )
1122 {
1123 return tmp;
1124 }
1125 }
1126 return NULL;
1127}
1128
1129/*
1130 * find_conf_ip
1131 *
1132 * Find a conf line using the IP# stored in it to search upon.
1133 * Added 1/8/92 by Avalon.
1134 */
1135aConfItem *find_conf_ip(Link *lp, char *ip, char *user, int statmask)
1136{
1137 Reg aConfItem *tmp;
1138 Reg char *s;
1139
1140 for (; lp; lp = lp->next)
1141 {
1142 tmp = lp->value.aconf;
1143 if (!(tmp->status & statmask))
1144 continue;
1145 s = index(tmp->host, '@');
1146 *s = '\0';
1147 if (match(tmp->host, user))
1148 {
1149 *s = '@';
1150 continue;
1151 }
1152 *s = '@';
1153 if (!bcmp((char *)&tmp->ipnum, ip, sizeof(struct IN_ADDR)))
1154 return tmp;
1155 }
1156 return NULL;
1157}
1158
1159/*
1160 * find_conf_entry
1161 *
1162 * - looks for a match on all given fields.
1163 */
1164aConfItem *find_conf_entry(aConfItem *aconf, u_int mask)
1165{
1166 Reg aConfItem *bconf;
1167
1168 for (bconf = conf, mask &= ~CONF_ILLEGAL; bconf; bconf = bconf->next)
1169 {
1170 if (!(bconf->status & mask) || (bconf->port != aconf->port))
1171 continue;
1172
1173 if ((BadPtr(bconf->host) && !BadPtr(aconf->host)) ||
1174 (BadPtr(aconf->host) && !BadPtr(bconf->host)))
1175 continue;
1176 if (!BadPtr(bconf->host) && mycmp(bconf->host, aconf->host))
1177 continue;
1178
1179 if ((BadPtr(bconf->passwd) && !BadPtr(aconf->passwd)) ||
1180 (BadPtr(aconf->passwd) && !BadPtr(bconf->passwd)))
1181 continue;
1182 if (!BadPtr(bconf->passwd) &&
1183 mycmp(bconf->passwd, aconf->passwd))
1184 continue;
1185
1186 if ((BadPtr(bconf->name) && !BadPtr(aconf->name)) ||
1187 (BadPtr(aconf->name) && !BadPtr(bconf->name)))
1188 continue;
1189 if (!BadPtr(bconf->name) && mycmp(bconf->name, aconf->name))
1190 continue;
1191 break;
1192 }
1193 return bconf;
1194}
1195
1196/*
1197 * rehash
1198 *
1199 * Actual REHASH service routine. Called with sig == 0 if it has been called
1200 * as a result of an operator issuing this command, else assume it has been
1201 * called as a result of the server receiving a HUP signal.
1202 */
1203int rehash(aClient *cptr, aClient *sptr, int sig)
1204{
1205 Reg aConfItem **tmp = &conf, *tmp2 = NULL;
1206 Reg aClass *cltmp;
1207 Reg aClient *acptr;
1208 Reg int i;
1209 int ret = 0;
1210
1211 if (sig == 1)
1212 {
1213 sendto_flag(SCH_NOTICE,
1214 "Got signal SIGHUP, reloading ircd.conf file");
1215 logfiles_close();
1216 logfiles_open();
1217#ifdef ULTRIX
1218 if (fork() > 0)
1219 exit(0);
1220 write_pidfile();
1221#endif
1222 }
1223
1224 for (i = 0; i <= highest_fd; i++)
1225 if ((acptr = local[i]) && !IsMe(acptr))
1226 {
1227 /*
1228 * Nullify any references from client structures to
1229 * this host structure which is about to be freed.
1230 * Could always keep reference counts instead of
1231 * this....-avalon
1232 */
1233 acptr->hostp = NULL;
1234 }
1235
1236 while ((tmp2 = *tmp))
1237 if (tmp2->clients || tmp2->status & CONF_LISTEN_PORT)
1238 {
1239 /*
1240 ** Configuration entry is still in use by some
1241 ** local clients, cannot delete it--mark it so
1242 ** that it will be deleted when the last client
1243 ** exits...
1244 */
1245 if (!(tmp2->status & (CONF_LISTEN_PORT|CONF_CLIENT)))
1246 {
1247 *tmp = tmp2->next;
1248 tmp2->next = NULL;
1249 }
1250 else
1251 tmp = &tmp2->next;
1252 tmp2->status |= CONF_ILLEGAL;
1253 }
1254 else
1255 {
1256 *tmp = tmp2->next;
1257 free_conf(tmp2);
1258 }
1259
1260 tmp = &kconf;
1261 while ((tmp2 = *tmp))
1262 {
1263 *tmp = tmp2->next;
1264 free_conf(tmp2);
1265 }
1266
1267 /*
1268 * We don't delete the class table, rather mark all entries
1269 * for deletion. The table is cleaned up by check_class. - avalon
1270 */
1271 for (cltmp = NextClass(FirstClass()); cltmp; cltmp = NextClass(cltmp))
1272 MaxLinks(cltmp) = -1;
1273
1274 if (sig == 'a')
1275 start_iauth(2); /* 2 means kill iauth first */
1276 if (sig == 'd')
1277 {
1278 flush_cache();
1279 close(resfd);
1280 resfd = init_resolver(0x1f);
1281 }
1282#ifdef TKLINE
1283 if (sig == 't')
1284 tkline_expire(1);
1285#endif
1286 (void) initconf(0);
1287 close_listeners();
1288 reopen_listeners();
1289
1290 /*
1291 * Flush *unused* config entries.
1292 */
1293 for (tmp = &conf; (tmp2 = *tmp); )
1294 if (!(tmp2->status & CONF_ILLEGAL) || (tmp2->clients > 0))
1295 tmp = &tmp2->next;
1296 else
1297 {
1298 *tmp = tmp2->next;
1299 tmp2->next = NULL;
1300 free_conf(tmp2);
1301 }
1302
1303 read_motd(IRCDMOTD_PATH);
1304 if (rehashed == 1)
1305 {
1306 /* queue another rehash for later */
1307 rehashed = 2;
1308 }
1309 else if (rehashed == 0)
1310 {
1311 rehashed = 1;
1312 }
1313 mysrand(timeofday);
1314 return ret;
1315}
1316
1317/*
1318 * openconf
1319 *
1320 * returns -1 on any error or else the fd opened from which to read the
1321 * configuration file from. This may either be the file direct or one end
1322 * of a pipe from m4.
1323 */
1324int openconf(void)
1325{
1326#ifdef M4_PREPROC
1327 int pi[2], i;
1328# ifdef HAVE_GNU_M4
1329 char *includedir, *includedirptr;
1330
1331 includedir = strdup(IRCDM4_PATH);
1332 includedirptr = strrchr(includedir, '/');
1333 if (includedirptr)
1334 *includedirptr = '\0';
1335# endif
1336#else
1337 int ret;
1338#endif
1339
1340#ifdef M4_PREPROC
1341 if (pipe(pi) == -1)
1342 return -1;
1343 switch(vfork())
1344 {
1345 case -1 :
1346 if (serverbooting)
1347 {
1348 fprintf(stderr,
1349 "Fatal Error: Unable to fork() m4 (%s)",
1350 strerror(errno));
1351 }
1352 return -1;
1353 case 0 :
1354 (void)close(pi[0]);
1355 if (pi[1] != 1)
1356 {
1357 (void)dup2(pi[1], 1);
1358 (void)close(pi[1]);
1359 }
1360 /* If the server is booting, stderr is still open and
1361 * user should receive error message */
1362 if (!serverbooting)
1363 {
1364 (void)dup2(1,2);
1365 }
1366 for (i = 3; i < MAXCONNECTIONS; i++)
1367 if (local[i])
1368 (void) close(i);
1369 /*
1370 * m4 maybe anywhere, use execvp to find it. Any error
1371 * goes out with report_error. Could be dangerous,
1372 * two servers running with the same fd's >:-) -avalon
1373 */
1374 (void)execlp(M4_PATH, "m4",
1375#ifdef HAVE_GNU_M4
1376#ifdef USE_M4_PREFIXES
1377 "-P",
1378#endif
1379 "-I", includedir,
1380#endif
1381#ifdef INET6
1382 "-DINET6",
1383#endif
1384 IRCDM4_PATH, configfile, 0);
1385 if (serverbooting)
1386 {
1387 fprintf(stderr,"Fatal Error: Error executing m4 (%s)",
1388 strerror(errno));
1389 }
1390 report_error("Error executing m4 %s:%s", &me);
1391 _exit(-1);
1392 default :
1393 (void)close(pi[1]);
1394 return pi[0];
1395 }
1396#else
1397 if ((ret = open(configfile, O_RDONLY)) == -1)
1398 {
1399 if (serverbooting)
1400 {
1401 fprintf(stderr,
1402 "Fatal Error: Can not open configuration file %s (%s)\n",
1403 configfile,strerror(errno));
1404 }
1405 }
1406 return ret;
1407#endif
1408}
1409
1410/*
1411** char *ipv6_convert(char *orig)
1412** converts the original ip address to an standard form
1413** returns a pointer to a string.
1414*/
1415
1416#ifdef INET6
1417char *ipv6_convert(char *orig)
1418{
1419 char *s, *t, *buf = NULL;
1420 int i, j;
1421 int len = 1; /* for the '\0' in case of no @ */
1422 struct in6_addr addr;
1423
1424 if ((s = strchr(orig, '@')))
1425 {
1426 *s = '\0';
1427 len = strlen(orig) + 2; /* +2 for '@' and '\0' */
1428 buf = (char *)MyMalloc(len);
1429 (void *)strcpy(buf, orig);
1430 buf[len - 2] = '@';
1431 buf[len - 1] = '\0';
1432 *s = '@';
1433 orig = s + 1;
1434 }
1435
1436 if ((s = strchr(orig, '/')))
1437 {
1438 *s = '\0';
1439 s++;
1440 }
1441
1442 i = inetpton(AF_INET6, orig, addr.s6_addr);
1443
1444 if (i > 0)
1445 {
1446 t = inetntop(AF_INET6, addr.s6_addr, ipv6string, sizeof(ipv6string));
1447 }
1448
1449 j = len - 1;
1450 if (!((i > 0) && t))
1451 t = orig;
1452
1453 len += strlen(t);
1454 buf = (char *)MyRealloc(buf, len);
1455 strcpy(buf + j, t);
1456
1457 if (s)
1458 {
1459 *(s-1) = '/'; /* put the '/' back, not sure it's needed tho */
1460 j = len;
1461 len += strlen(s) + 1;
1462 buf = (char *)MyRealloc(buf, len);
1463 buf[j - 1] = '/';
1464 strcpy(buf + j, s);
1465 }
1466
1467 return buf;
1468}
1469#endif
1470
1471/*
1472** initconf()
1473** Read configuration file.
1474**
1475** returns -1, if file cannot be opened
1476** 0, if file opened
1477*/
1478
1479#define MAXCONFLINKS 150
1480
1481int initconf(int opt)
1482{
1483 static char quotes[9][2] = {{'b', '\b'}, {'f', '\f'}, {'n', '\n'},
1484 {'r', '\r'}, {'t', '\t'}, {'v', '\v'},
1485 {'\\', '\\'}, { 0, 0}};
1486 Reg char *tmp, *s;
1487 int fd, i;
1488 char *tmp2 = NULL, *tmp3 = NULL, *tmp4 = NULL;
1489#ifdef ENABLE_CIDR_LIMITS
1490 char *tmp5 = NULL;
1491#endif
1492 int ccount = 0, ncount = 0;
1493 aConfItem *aconf = NULL;
1494#if defined(CONFIG_DIRECTIVE_INCLUDE)
1495 char *line;
1496 aConfig *ConfigTop, *p;
1497 FILE *fdn;
1498#else
1499 char line[512], c[80];
1500#endif
1501
1502 Debug((DEBUG_DEBUG, "initconf(): ircd.conf = %s", configfile));
1503 if ((fd = openconf()) == -1)
1504 {
1505#if defined(M4_PREPROC) && !defined(USE_IAUTH)
1506 (void)wait(0);
1507#endif
1508 return -1;
1509 }
1510#if defined(CONFIG_DIRECTIVE_INCLUDE)
1511 fdn = fdopen(fd, "r");
1512 if (fdn == NULL)
1513 {
1514 if (serverbooting)
1515 {
1516 fprintf(stderr,
1517 "Fatal Error: Can not open configuration file %s (%s)\n",
1518 configfile,strerror(errno));
1519 }
1520 return -1;
1521 }
1522 ConfigTop = config_read(fdn, 0, new_config_file(configfile, NULL, 0));
1523 for(p = ConfigTop; p; p = p->next)
1524#else
1525 (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
1526 while ((i = dgets(fd, line, sizeof(line) - 1)) > 0)
1527#endif
1528 {
1529#if defined(CONFIG_DIRECTIVE_INCLUDE)
1530 line = p->line;
1531#else
1532 line[i] = '\0';
1533 if ((tmp = (char *)index(line, '\n')))
1534 *tmp = 0;
1535 else while(dgets(fd, c, sizeof(c) - 1) > 0)
1536 if ((tmp = (char *)index(c, '\n')))
1537 {
1538 *tmp = 0;
1539 break;
1540 }
1541#endif
1542 /*
1543 * Do quoting of characters and # detection.
1544 */
1545 for (tmp = line; *tmp; tmp++)
1546 {
1547 if (*tmp == '\\')
1548 {
1549 for (i = 0; quotes[i][0]; i++)
1550 if (quotes[i][0] == *(tmp+1))
1551 {
1552 *tmp = quotes[i][1];
1553 break;
1554 }
1555 if (!quotes[i][0])
1556 *tmp = *(tmp+1);
1557 if (!*(tmp+1))
1558 break;
1559 else
1560 for (s = tmp; (*s = *(s+1)); s++)
1561 ;
1562 }
1563 else if (*tmp == '#')
1564 {
1565 *tmp = '\0';
1566 break; /* Ignore the rest of the line */
1567 }
1568 }
1569 if (!*line || line[0] == '#' || line[0] == '\n' ||
1570 line[0] == ' ' || line[0] == '\t')
1571 continue;
1572 /* Could we test if it's conf line at all? -Vesa */
1573 if (line[1] != IRCDCONF_DELIMITER)
1574 {
1575 Debug((DEBUG_ERROR, "Bad config line: %s", line));
1576 continue;
1577 }
1578 if (aconf)
1579 free_conf(aconf);
1580 aconf = make_conf();
1581
1582 if (tmp2)
1583 MyFree(tmp2);
1584 tmp3 = tmp4 = NULL;
1585#ifdef ENABLE_CIDR_LIMITS
1586 tmp5 = NULL;
1587#endif
1588 tmp = getfield(line);
1589 if (!tmp)
1590 continue;
1591 switch (*tmp)
1592 {
1593 case 'A': /* Name, e-mail address of administrator */
1594 case 'a': /* of this server. */
1595 aconf->status = CONF_ADMIN;
1596 break;
1597 case 'B': /* Name of alternate servers */
1598 case 'b':
1599 aconf->status = CONF_BOUNCE;
1600 break;
1601 case 'C': /* Server where I should try to connect */
1602 /* in case of lp failures */
1603 ccount++;
1604 aconf->status = CONF_CONNECT_SERVER;
1605 break;
1606 case 'c':
1607 ccount++;
1608 aconf->status = CONF_ZCONNECT_SERVER;
1609 break;
1610 case 'D': /* auto connect restrictions */
1611 case 'd':
1612 aconf->status = CONF_DENY;
1613 break;
1614 case 'H': /* Hub server line */
1615 case 'h':
1616 aconf->status = CONF_HUB;
1617 break;
1618 case 'i' : /* Restricted client */
1619 aconf->flags |= CFLAG_RESTRICTED;
1620 case 'I':
1621 aconf->status = CONF_CLIENT;
1622 break;
1623 case 'K': /* Kill user line on irc.conf */
1624 aconf->status = CONF_KILL;
1625 break;
1626 case 'k':
1627 aconf->status = CONF_OTHERKILL;
1628 break;
1629 /* Operator. Line should contain at least */
1630 /* password and host where connection is */
1631 case 'L': /* guaranteed leaf server */
1632 case 'l':
1633 aconf->status = CONF_LEAF;
1634 break;
1635 /* Me. Host field is name used for this host */
1636 /* and port number is the number of the port */
1637 case 'M':
1638 case 'm':
1639 aconf->status = CONF_ME;
1640 break;
1641 case 'N': /* Server where I should NOT try to */
1642 case 'n': /* connect in case of lp failures */
1643 /* but which tries to connect ME */
1644 ++ncount;
1645 aconf->status = CONF_NOCONNECT_SERVER;
1646 break;
1647 case 'o':
1648 aconf->flags |= ACL_LOCOP;
1649 case 'O':
1650 aconf->status = CONF_OPERATOR;
1651 break;
1652 case 'P': /* listen port line */
1653 case 'p':
1654 aconf->status = CONF_LISTEN_PORT;
1655 break;
1656 case 'Q': /* a server that you don't want in your */
1657 case 'q': /* network. USE WITH CAUTION! */
1658 aconf->status = CONF_QUARANTINED_SERVER;
1659 break;
1660 case 'S': /* Service. Same semantics as */
1661 case 's': /* CONF_OPERATOR */
1662 aconf->status = CONF_SERVICE;
1663 break;
1664 case 'V': /* Server link version requirements */
1665 aconf->status = CONF_VER;
1666 break;
1667 case 'Y':
1668 case 'y':
1669 aconf->status = CONF_CLASS;
1670 break;
1671#ifdef XLINE
1672 case 'X':
1673 aconf->status = CONF_XLINE;
1674 break;
1675#endif
1676 default:
1677 Debug((DEBUG_ERROR, "Error in config file: %s", line));
1678 break;
1679 }
1680 if (IsIllegal(aconf))
1681 continue;
1682
1683 do
1684 {
1685 if ((tmp = getfield(NULL)) == NULL)
1686 break;
1687#ifdef INET6
1688 if (aconf->status &
1689 (CONF_CONNECT_SERVER|CONF_ZCONNECT_SERVER
1690 |CONF_CLIENT|CONF_KILL
1691 |CONF_OTHERKILL|CONF_NOCONNECT_SERVER
1692 |CONF_OPERATOR|CONF_LISTEN_PORT
1693 |CONF_SERVICE))
1694 aconf->host = ipv6_convert(tmp);
1695 else
1696 DupString(aconf->host, tmp);
1697#else
1698 DupString(aconf->host, tmp);
1699#endif
1700 if ((tmp = getfield(NULL)) == NULL)
1701 break;
1702 DupString(aconf->passwd, tmp);
1703 if ((tmp = getfield(NULL)) == NULL)
1704 break;
1705 DupString(aconf->name, tmp);
1706 if ((tmp = getfield(NULL)) == NULL)
1707 break;
1708#ifdef XLINE
1709 if (aconf->status == CONF_XLINE)
1710 {
1711 DupString(aconf->name2, tmp);
1712 if ((tmp = getfield(NULL)) == NULL)
1713 break;
1714 DupString(aconf->name3, tmp);
1715 if ((tmp = getfield(NULL)) == NULL)
1716 break;
1717 DupString(aconf->source_ip, tmp);
1718 break;
1719 }
1720#endif
1721 aconf->port = 0;
1722 if (sscanf(tmp, "0x%x", &aconf->port) != 1 ||
1723 aconf->port == 0)
1724 aconf->port = atoi(tmp);
1725 if (aconf->status == CONF_CONNECT_SERVER)
1726 DupString(tmp2, tmp);
1727 if (aconf->status == CONF_ZCONNECT_SERVER)
1728 DupString(tmp2, tmp);
1729 if ((tmp = getfield(NULL)) == NULL)
1730 break;
1731 Class(aconf) = find_class(atoi(tmp));
1732 /* used in Y: local limits and I: and P: flags */
1733 if ((tmp3 = getfield(NULL)) == NULL)
1734 break;
1735 /* used in Y: global limits */
1736 if((tmp4 = getfield(NULL)) == NULL)
1737 break;
1738#ifdef ENABLE_CIDR_LIMITS
1739 tmp5 = getfield(NULL);
1740#endif
1741 } while (0); /* to use break without compiler warnings */
1742 istat.is_confmem += aconf->host ? strlen(aconf->host)+1 : 0;
1743 istat.is_confmem += aconf->passwd ? strlen(aconf->passwd)+1 :0;
1744 istat.is_confmem += aconf->name ? strlen(aconf->name)+1 : 0;
1745 istat.is_confmem += aconf->name2 ? strlen(aconf->name2)+1 : 0;
1746#ifdef XLINE
1747 istat.is_confmem += aconf->name3 ? strlen(aconf->name3)+1 : 0;
1748#endif
1749 istat.is_confmem += aconf->source_ip ? strlen(aconf->source_ip)+1 : 0;
1750
1751 /*
1752 ** Bounce line fields are mandatory
1753 */
1754 if (aconf->status == CONF_BOUNCE && aconf->port == 0)
1755 continue;
1756 /*
1757 ** If conf line is a class definition, create a class entry
1758 ** for it and make the conf_line illegal and delete it.
1759 */
1760 if (aconf->status & CONF_CLASS)
1761 {
1762 if (atoi(aconf->host) >= 0)
1763 add_class(atoi(aconf->host),
1764 atoi(aconf->passwd),
1765 atoi(aconf->name), aconf->port,
1766 tmp ? atoi(tmp) : 0,
1767 (tmp && index(tmp, '.')) ?
1768 atoi(index(tmp, '.') + 1) : 0,
1769 tmp3 ? atoi(tmp3) : 1,
1770 (tmp3 && index(tmp3, '.')) ?
1771 atoi(index(tmp3, '.') + 1) : 1,
1772 tmp4 ? atoi(tmp4) : 1,
1773 (tmp4 && index(tmp4, '.')) ?
1774 atoi(index(tmp4, '.') + 1) : 1
1775#ifdef ENABLE_CIDR_LIMITS
1776 , tmp5
1777#endif
1778 );
1779 continue;
1780 }
1781 /*
1782 ** associate each conf line with a class by using a pointer
1783 ** to the correct class record. -avalon
1784 */
1785 if (aconf->status & (CONF_CLIENT_MASK|CONF_LISTEN_PORT))
1786 {
1787 if (Class(aconf) == 0)
1788 Class(aconf) = find_class(0);
1789 if (MaxLinks(Class(aconf)) < 0)
1790 Class(aconf) = find_class(0);
1791 }
1792 if (aconf->status & (CONF_LISTEN_PORT|CONF_CLIENT))
1793 {
1794 aConfItem *bconf;
1795
1796 /* any flags in this line? */
1797 if (tmp3)
1798 {
1799 aconf->flags |=
1800 ((aconf->status == CONF_CLIENT) ?
1801 iline_flags_parse(tmp3) :
1802 pline_flags_parse(tmp3));
1803 }
1804
1805 /* trying to find exact conf line in already existing
1806 * conf, so we don't delete old one, just update it */
1807 if (
1808#ifdef FASTER_ILINE_REHASH
1809 (aconf->status & CONF_LISTEN_PORT) &&
1810#endif
1811 (bconf = find_conf_entry(aconf, aconf->status)))
1812 {
1813 /* we remove bconf (already existing) from conf
1814 * so that we can add it back uniformly at the
1815 * end of while(dgets) loop. --B. */
1816 delist_conf(bconf);
1817 bconf->status &= ~CONF_ILLEGAL;
1818 /* aconf is a new item, it can contain +r flag
1819 * (from lowercase i:lines). In any case we
1820 * don't want old flags to remain. --B. */
1821 bconf->flags = aconf->flags;
1822 /* in case class was changed */
1823 if (aconf->status == CONF_CLIENT &&
1824 aconf->class != bconf->class)
1825 {
1826 bconf->class->links -= bconf->clients;
1827 bconf->class = aconf->class;
1828 bconf->class->links += bconf->clients;
1829 }
1830 /* free new one, assign old one to aconf */
1831 free_conf(aconf);
1832 aconf = bconf;
1833 }
1834 else /* no such conf line was found */
1835 {
1836 if (aconf->host &&
1837 aconf->status == CONF_LISTEN_PORT)
1838 {
1839 (void)add_listener(aconf);
1840 }
1841 }
1842 }
1843 if (aconf->status & CONF_SERVICE)
1844 aconf->port &= SERVICE_MASK_ALL;
1845 if (aconf->status & (CONF_SERVER_MASK|CONF_SERVICE))
1846 {
1847 char *hostptr = NULL;
1848
1849 /* since it's u@h syntax, let's ignore user part
1850 in checks below --B. */
1851 hostptr = index(aconf->host, '@');
1852 if (hostptr != NULL)
1853 hostptr++; /* move ptr after '@' */
1854 else
1855 hostptr = aconf->host;
1856
1857 if (ncount > MAXCONFLINKS || ccount > MAXCONFLINKS
1858 || !hostptr || index(hostptr, '*')
1859 || index(hostptr,'?') || !aconf->name)
1860 continue; /* next config line */
1861 }
1862
1863 if (aconf->status &
1864 (CONF_SERVER_MASK|CONF_OPERATOR|CONF_SERVICE))
1865 if (!index(aconf->host, '@') && *aconf->host != '/')
1866 {
1867 char *newhost;
1868 int len = 3; /* *@\0 = 3 */
1869
1870 len += strlen(aconf->host);
1871 newhost = (char *)MyMalloc(len);
1872 sprintf(newhost, "*@%s", aconf->host);
1873 MyFree(aconf->host);
1874 aconf->host = newhost;
1875 istat.is_confmem += 2;
1876 }
1877 if (tmp3 && (aconf->status & CONF_OPERATOR))
1878 {
1879 aconf->flags |= oline_flags_parse(tmp3);
1880 /* remove this when removing o: lines --B. */
1881 if (aconf->flags & ACL_LOCOP)
1882 aconf->flags &= ~ACL_ALL_REMOTE;
1883 }
1884 if (aconf->status & CONF_SERVER_MASK)
1885 {
1886 if (BadPtr(aconf->passwd))
1887 continue;
1888 else if (!(opt & BOOT_QUICK))
1889 (void)lookup_confhost(aconf);
1890 }
1891 if (aconf->status & (CONF_CONNECT_SERVER | CONF_ZCONNECT_SERVER))
1892 {
1893 aconf->ping = (aCPing *)MyMalloc(sizeof(aCPing));
1894 bzero((char *)aconf->ping, sizeof(*aconf->ping));
1895 istat.is_confmem += sizeof(*aconf->ping);
1896 if (tmp2 && index(tmp2, '.'))
1897 aconf->ping->port = atoi(index(tmp2, '.') + 1);
1898 else
1899 aconf->ping->port = aconf->port;
1900 if (tmp2)
1901 {
1902 MyFree(tmp2);
1903 tmp2 = NULL;
1904 }
1905 if (tmp3)
1906 {
1907 DupString(aconf->source_ip, tmp3);
1908 }
1909
1910 }
1911 /*
1912 ** Name cannot be changed after the startup.
1913 ** (or could be allowed, but only if all links are closed
1914 ** first).
1915 ** Configuration info does not override the name and port
1916 ** if previously defined. Note, that "info"-field can be
1917 ** changed by "/rehash".
1918 */
1919 if (aconf->status == CONF_ME)
1920 {
1921 if (me.info != DefInfo)
1922 MyFree(me.info);
1923 me.info = MyMalloc(REALLEN+1);
1924 strncpyzt(me.info, aconf->name, REALLEN+1);
1925 if (me.serv->namebuf[0] == '\0' && aconf->host[0])
1926 strncpyzt(me.serv->namebuf, aconf->host,
1927 sizeof(me.serv->namebuf));
1928 if (me.serv->sid[0] == '\0' && tmp && *tmp)
1929 {
1930 for(i = 0; i < sizeof(me.serv->sid); i++)
1931 me.serv->sid[i] = toupper(tmp[i]);
1932 }
1933
1934 if (aconf->port)
1935 setup_ping(aconf);
1936 }
1937
1938 if (aconf->status == CONF_ADMIN)
1939 {
1940 if (!networkname && tmp && *tmp)
1941 {
1942 if (strlen(tmp) < HOSTLEN)
1943 {
1944 DupString(networkname,tmp);
1945 }
1946 }
1947 }
1948
1949 (void)collapse(aconf->host);
1950 (void)collapse(aconf->name);
1951 Debug((DEBUG_NOTICE,
1952 "Read Init: (%d) (%s) (%s) (%s) (%d) (%d)",
1953 aconf->status, aconf->host, aconf->passwd,
1954 aconf->name, aconf->port,
1955 aconf->class ? ConfClass(aconf) : 0));
1956
1957 if (aconf->status & (CONF_KILL|CONF_OTHERKILL))
1958 {
1959 aconf->next = kconf;
1960 kconf = aconf;
1961 }
1962 else
1963 {
1964 aconf->next = conf;
1965 conf = aconf;
1966 }
1967 aconf = NULL;
1968 }
1969#if defined(CONFIG_DIRECTIVE_INCLUDE)
1970 config_free(ConfigTop);
1971#endif
1972 if (aconf)
1973 free_conf(aconf);
1974 (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
1975#if defined(CONFIG_DIRECTIVE_INCLUDE)
1976 (void)fclose(fdn);
1977#else
1978 (void)close(fd);
1979#endif
1980#if defined(M4_PREPROC) && !defined(USE_IAUTH)
1981 (void)wait(0);
1982#endif
1983 check_class();
1984 nextping = nextconnect = timeofday;
1985 return 0;
1986}
1987
1988/*
1989 * lookup_confhost
1990 * Do (start) DNS lookups of all hostnames in the conf line and convert
1991 * an IP addresses in a.b.c.d number for to IP#s.
1992 */
1993static int lookup_confhost(aConfItem *aconf)
1994{
1995 Reg char *s;
1996 Reg struct hostent *hp;
1997 Link ln;
1998
1999 if (BadPtr(aconf->host) || BadPtr(aconf->name))
2000 goto badlookup;
2001 if ((s = index(aconf->host, '@')))
2002 s++;
2003 else
2004 s = aconf->host;
2005 /*
2006 ** Do name lookup now on hostnames given and store the
2007 ** ip numbers in conf structure.
2008 */
2009 if (!isalpha(*s) && !isdigit(*s))
2010 goto badlookup;
2011
2012 /*
2013 ** Prepare structure in case we have to wait for a
2014 ** reply which we get later and store away.
2015 */
2016 ln.value.aconf = aconf;
2017 ln.flags = ASYNC_CONF;
2018
2019#ifdef INET6
2020 if(inetpton(AF_INET6, s, aconf->ipnum.s6_addr))
2021 ;
2022#else
2023 if (isdigit(*s))
2024 aconf->ipnum.s_addr = inetaddr(s);
2025#endif
2026 else if ((hp = gethost_byname(s, &ln)))
2027 bcopy(hp->h_addr, (char *)&(aconf->ipnum),
2028 sizeof(struct IN_ADDR));
2029#ifdef INET6
2030 else
2031 {
2032 bcopy(minus_one, aconf->ipnum.s6_addr, IN6ADDRSZ);
2033 goto badlookup;
2034 }
2035
2036#else
2037 if (aconf->ipnum.s_addr == -1)
2038 goto badlookup;
2039#endif
2040
2041 return 0;
2042
2043badlookup:
2044#ifdef INET6
2045 if (AND16(aconf->ipnum.s6_addr) == 255)
2046#else
2047 if (aconf->ipnum.s_addr == -1)
2048#endif
2049 bzero((char *)&aconf->ipnum, sizeof(struct IN_ADDR));
2050 Debug((DEBUG_ERROR,"Host/server name error: (%s) (%s)",
2051 aconf->host, aconf->name));
2052 return -1;
2053}
2054
2055int find_kill(aClient *cptr, int timedklines, char **comment)
2056{
2057#ifdef TIMEDKLINES
2058 static char reply[256];
2059 int now = 0;
2060#endif
2061 char *host, *ip, *name, *ident, *check;
2062 aConfItem *tmp;
2063#ifdef TKLINE
2064 int tklines = 1;
2065#endif
2066
2067 if (!cptr->user)
2068 return 0;
2069
2070 if (IsKlineExempt(cptr))
2071 {
2072 return 0;
2073 }
2074
2075 host = cptr->sockhost;
2076#ifdef INET6
2077 ip = (char *) inetntop(AF_INET6, (char *)&cptr->ip, ipv6string,
2078 sizeof(ipv6string));
2079#else
2080 ip = (char *) inetntoa((char *)&cptr->ip);
2081#endif
2082 if (!strcmp(host, ip))
2083 ip = NULL; /* we don't have a name for the ip# */
2084 name = cptr->user->username;
2085 if (IsRestricted(cptr) && name[0] == '+')
2086 {
2087 /*
2088 ** since we added '+' at the begining of valid
2089 ** ident response, remove it here for kline
2090 ** comparison --Beeth
2091 */
2092 name++;
2093 }
2094 ident = cptr->auth;
2095
2096 if (strlen(host) > (size_t) HOSTLEN ||
2097 (name ? strlen(name) : 0) > (size_t) HOSTLEN)
2098 return (0);
2099
2100#ifdef TIMEDKLINES
2101 *reply = '\0';
2102#endif
2103
2104findkline:
2105 tmp =
2106#ifdef TKLINE
2107 tklines ? tkconf :
2108#endif
2109 kconf;
2110 for (; tmp; tmp = tmp->next)
2111 {
2112#ifdef TIMEDKLINES
2113 if (timedklines && (BadPtr(tmp->passwd) || !isdigit(*tmp->passwd)))
2114 continue;
2115#endif
2116 if (!(tmp->status & (
2117#ifdef TKLINE
2118 tklines ? (CONF_TKILL | CONF_TOTHERKILL) :
2119#endif
2120 (CONF_KILL | CONF_OTHERKILL))))
2121 continue; /* should never happen with kconf */
2122 if (!tmp->host || !tmp->name)
2123 continue;
2124#ifdef TKLINE
2125 /* this TK already expired */
2126 if (tklines && tmp->hold < timeofday)
2127 continue;
2128#endif
2129 if (tmp->status == (
2130#ifdef TKLINE
2131 tklines ? CONF_TKILL :
2132#endif
2133 CONF_KILL))
2134 check = name;
2135 else
2136 check = ident;
2137 /* host & IP matching.. */
2138 if (!ip) /* unresolved */
2139 {
2140 if (strchr(tmp->host, '/'))
2141 {
2142 if (match_ipmask((*tmp->host == '=') ?
2143 tmp->host+1: tmp->host, cptr, 1))
2144 continue;
2145 }
2146 else
2147 if (match((*tmp->host == '=') ? tmp->host+1 :
2148 tmp->host, host))
2149 continue;
2150 }
2151 else if (*tmp->host == '=') /* numeric only */
2152 continue;
2153 else /* resolved */
2154 if (strchr(tmp->host, '/'))
2155 {
2156 if (match_ipmask(tmp->host, cptr, 1))
2157 continue;
2158 }
2159 else
2160 if (match(tmp->host, ip) &&
2161 match(tmp->host, host))
2162 continue;
2163
2164 /* user & port matching */
2165 if ((!check || match(tmp->name, check) == 0) &&
2166 (!tmp->port || (tmp->port == cptr->acpt->port)))
2167 {
2168#ifdef TIMEDKLINES
2169 now = 0;
2170 if (!BadPtr(tmp->passwd) && isdigit(*tmp->passwd) &&
2171 !(now = check_time_interval(tmp->passwd, reply)))
2172 continue;
2173 if (now == ERR_YOUWILLBEBANNED)
2174 tmp = NULL;
2175#endif
2176 break;
2177 }
2178 }
2179#ifdef TKLINE
2180 if (!tmp && tklines)
2181 {
2182 tklines = 0;
2183 goto findkline;
2184 }
2185#endif
2186 if (tmp && !BadPtr(tmp->passwd))
2187 {
2188 *comment = tmp->passwd;
2189 }
2190 else
2191 {
2192 *comment = NULL;
2193 }
2194#ifdef TIMEDKLINES
2195 if (*reply)
2196 {
2197 sendto_one(cptr, reply, ME, now, cptr->name);
2198 }
2199 else
2200#endif
2201 if (tmp)
2202 {
2203 sendto_one(cptr, replies[ERR_YOUREBANNEDCREEP],
2204 ME, cptr->name,
2205 BadPtr(tmp->name) ? "*" : tmp->name,
2206 BadPtr(tmp->host) ? "*" : tmp->host,
2207 *comment ? ": " : "",
2208 *comment ? *comment : "");
2209 }
2210
2211 return (tmp ? -1 : 0);
2212}
2213
2214/*
2215 * For type stat, check if both name and host masks match.
2216 * Return -1 for match, 0 for no-match.
2217 */
2218int find_two_masks(char *name, char *host, int stat)
2219{
2220 aConfItem *tmp;
2221
2222 for (tmp = conf; tmp; tmp = tmp->next)
2223 if ((tmp->status == stat) && tmp->host && tmp->name &&
2224 (match(tmp->host, host) == 0) &&
2225 (match(tmp->name, name) == 0))
2226 break;
2227 return (tmp ? -1 : 0);
2228}
2229
2230/*
2231 * For type stat, check if name matches and any char from key matches
2232 * to chars in passwd field.
2233 * Return -1 for match, 0 for no-match.
2234 */
2235int find_conf_flags(char *name, char *key, int stat)
2236{
2237 aConfItem *tmp;
2238 int l;
2239
2240 if (index(key, '/') == NULL)
2241 return 0;
2242 l = ((char *)index(key, '/') - key) + 1;
2243 for (tmp = conf; tmp; tmp = tmp->next)
2244 if ((tmp->status == stat) && tmp->passwd && tmp->name &&
2245 (strncasecmp(key, tmp->passwd, l) == 0) &&
2246 (match(tmp->name, name) == 0) &&
2247 (strpbrk(key + l, tmp->passwd + l)))
2248 break;
2249 return (tmp ? -1 : 0);
2250}
2251
2252#ifdef TIMEDKLINES
2253/*
2254** check against a set of time intervals
2255*/
2256
2257static int check_time_interval(char *interval, char *reply)
2258{
2259 struct tm *tptr;
2260 char *p;
2261 int perm_min_hours, perm_min_minutes,
2262 perm_max_hours, perm_max_minutes;
2263 int now, perm_min, perm_max;
2264
2265 tptr = localtime(&timeofday);
2266 now = tptr->tm_hour * 60 + tptr->tm_min;
2267
2268 while (interval)
2269 {
2270 p = (char *)index(interval, ',');
2271 if (p)
2272 *p = '\0';
2273 if (sscanf(interval, "%2d%2d-%2d%2d",
2274 &perm_min_hours, &perm_min_minutes,
2275 &perm_max_hours, &perm_max_minutes) != 4)
2276 {
2277 if (p)
2278 *p = ',';
2279 return(0);
2280 }
2281 if (p)
2282 *(p++) = ',';
2283 perm_min = 60 * perm_min_hours + perm_min_minutes;
2284 perm_max = 60 * perm_max_hours + perm_max_minutes;
2285 /*
2286 ** The following check allows intervals over midnight ...
2287 */
2288 if ((perm_min < perm_max)
2289 ? (perm_min <= now && now <= perm_max)
2290 : (perm_min <= now || now <= perm_max))
2291 {
2292 (void)sprintf(reply,
2293 ":%%s %%d %%s :%s %d:%02d to %d:%02d.",
2294 "You are not allowed to connect from",
2295 perm_min_hours, perm_min_minutes,
2296 perm_max_hours, perm_max_minutes);
2297 return(ERR_YOUREBANNEDCREEP);
2298 }
2299 if ((perm_min < perm_max)
2300 ? (perm_min <= now + 5 && now + 5 <= perm_max)
2301 : (perm_min <= now + 5 || now + 5 <= perm_max))
2302 {
2303 (void)sprintf(reply, ":%%s %%d %%s :%d minute%s%s",
2304 perm_min-now,(perm_min-now)>1?"s ":" ",
2305 "and you will be denied for further access");
2306 return(ERR_YOUWILLBEBANNED);
2307 }
2308 interval = p;
2309 }
2310 return(0);
2311}
2312#endif /* TIMEDKLINES */
2313
2314/*
2315** find_bounce
2316** send a bounce numeric to a client.
2317** fd is optional, and only makes sense if positive and when cptr is NULL
2318** fd == -1 : not fd, class is a class number.
2319** fd == -2 : not fd, class isn't a class number.
2320*/
2321void find_bounce(aClient *cptr, int class, int fd)
2322{
2323 Reg aConfItem *aconf;
2324
2325 if (fd < 0 && cptr == NULL)
2326 {
2327 /* nowhere to send error to */
2328 return;
2329 }
2330
2331 for (aconf = conf; aconf; aconf = aconf->next)
2332 {
2333 if (aconf->status != CONF_BOUNCE)
2334 {
2335 continue;
2336 }
2337
2338 if (fd >= 0)
2339 {
2340 /*
2341 ** early rejection,
2342 ** connection class and hostname are unknown
2343 */
2344 if (*aconf->host == '\0')
2345 {
2346 char rpl[BUFSIZE];
2347
2348 sprintf(rpl, replies[RPL_BOUNCE], ME, "unknown",
2349 aconf->name, aconf->port);
2350 strcat(rpl, "\r\n");
2351#ifdef INET6
2352 sendto(fd, rpl, strlen(rpl), 0, 0, 0);
2353#else
2354 send(fd, rpl, strlen(rpl), 0);
2355#endif
2356 return;
2357 }
2358 else
2359 {
2360 continue;
2361 }
2362 }
2363
2364 /* fd < 0 */
2365 /*
2366 ** "too many" type rejection, class is known.
2367 ** check if B line is for a class #,
2368 ** and if it is for a hostname.
2369 */
2370 if (fd != -2 &&
2371 !strchr(aconf->host, '.') &&
2372 (isdigit(*aconf->host) || *aconf->host == '-'))
2373 {
2374 if (class != atoi(aconf->host))
2375 {
2376 continue;
2377 }
2378 }
2379 else
2380 {
2381 if (strchr(aconf->host, '/'))
2382 {
2383 if (match_ipmask(aconf->host, cptr, 1))
2384 continue;
2385 }
2386 else if (match(aconf->host, cptr->sockhost))
2387 {
2388 continue;
2389 }
2390 }
2391
2392 sendto_one(cptr, replies[RPL_BOUNCE], ME, BadTo(cptr->name),
2393 aconf->name, aconf->port);
2394 return;
2395 }
2396
2397}
2398
2399/*
2400** find_denied
2401** for a given server name, make sure no D line matches any of the
2402** servers currently present on the net.
2403*/
2404aConfItem *find_denied(char *name, int class)
2405{
2406 aConfItem *aconf;
2407
2408 for (aconf = conf; aconf; aconf = aconf->next)
2409 {
2410 if (aconf->status != CONF_DENY)
2411 continue;
2412 if (!aconf->name)
2413 continue;
2414 if (match(aconf->name, name) && aconf->port != class)
2415 continue;
2416 if (isdigit(*aconf->passwd))
2417 {
2418 aConfItem *aconf2;
2419 int ck = atoi(aconf->passwd);
2420
2421 for (aconf2 = conf; aconf2; aconf2 = aconf2->next)
2422 {
2423 if (aconf2->status != CONF_NOCONNECT_SERVER)
2424 continue;
2425 if (!aconf2->class || ConfClass(aconf2) != ck)
2426 continue;
2427 if (find_client(aconf2->name, NULL))
2428 return aconf2;
2429 }
2430 }
2431 if (aconf->host)
2432 {
2433 aServer *asptr;
2434 char *host = aconf->host;
2435 int reversed = 0;
2436
2437 if (*host == '!')
2438 {
2439 host++;
2440 reversed = 1;
2441 }
2442 for (asptr = svrtop; asptr; asptr = asptr->nexts)
2443 if (!match(host, asptr->bcptr->name))
2444 break;
2445
2446 if (!reversed && asptr)
2447 return aconf;
2448 if (reversed && !asptr)
2449 /* anything but NULL; tho using it may give
2450 ** funny results in calling function */
2451 return conf;
2452 }
2453 }
2454 return NULL;
2455}
2456
2457#ifdef TKLINE
2458/*
2459 * Parses 0w1d2h3m4s timeformat, filling in output variable in seconds.
2460 * Returns 0 if everything went ok.
2461 */
2462int wdhms2sec(char *input, time_t *output)
2463{
2464#ifndef TKLINE_MULTIPLIER
2465#define TKLINE_MULTIPLIER 60
2466#endif
2467 int multi;
2468 int tmp = 0;
2469 char *s;
2470
2471 *output = 0;
2472
2473 if (!input) return 0;
2474
2475 s = input;
2476 while (*s)
2477 {
2478 switch(tolower(*s))
2479 {
2480 case 'w':
2481 multi = 604800; break;
2482 case 'd':
2483 multi = 86400; break;
2484 case 'h':
2485 multi = 3600; break;
2486 case 'm':
2487 multi = 60; break;
2488 case 's':
2489 multi = 1; break;
2490 default:
2491 if (isdigit(*s))
2492 {
2493 tmp = atoi(s);
2494 while (isdigit(*s))
2495 s++;
2496 if (!*s)
2497 {
2498 *output += TKLINE_MULTIPLIER * tmp;
2499 }
2500 continue;
2501 }
2502 else
2503 return -1;
2504 }
2505 *output += multi * tmp;
2506 s++;
2507 }
2508 return 0;
2509}
2510#endif
2511
2512#if defined(TKLINE) || defined(KLINE)
2513/*
2514 * Adds t/kline to t/kconf.
2515 * If tkline already existed, its expire time is updated.
2516 *
2517 * Returns created tkline expire time.
2518 */
2519void do_kline(int tkline, char *who, time_t time, char *user, char *host, char *reason, int status)
2520{
2521 char buff[BUFSIZE];
2522 aClient *acptr;
2523 aConfItem *aconf;
2524 int i, count = 0;
2525
2526 buff[0] = '\0';
2527
2528 /* Check if such u@h already exists in tkconf. */
2529 for (aconf = tkline?tkconf:kconf; aconf; aconf = aconf->next)
2530 {
2531 if (0==strcasecmp(aconf->host, host) &&
2532 0==strcasecmp(aconf->name, user))
2533 {
2534 aconf->hold = timeofday + time;
2535 break;
2536 }
2537 }
2538 if (aconf == NULL)
2539 {
2540 aconf = make_conf();
2541 aconf->next = NULL;
2542 aconf->status = status;
2543 aconf->hold = timeofday + time;
2544 aconf->port = 0;
2545 Class(aconf) = find_class(0);
2546 DupString(aconf->name, BadTo(user));
2547 DupString(aconf->host, BadTo(host));
2548 DupString(aconf->passwd, reason);
2549 istat.is_confmem += strlen(aconf->name) + 1;
2550 istat.is_confmem += strlen(aconf->host) + 1;
2551 istat.is_confmem += strlen(aconf->passwd) + 1;
2552
2553 /* put on top of t/kconf */
2554 if (tkline)
2555 {
2556 if (tkconf)
2557 {
2558 aconf->next = tkconf;
2559 }
2560 tkconf = aconf;
2561 sendto_flag(SCH_TKILL, "TKLINE %s@%s (%u) by %s :%s",
2562 aconf->name, aconf->host, time, who, reason);
2563 }
2564 else
2565 {
2566 if (kconf)
2567 {
2568 aconf->next = kconf;
2569 }
2570 kconf = aconf;
2571 sendto_flag(SCH_TKILL, "KLINE %s@%s by %s :%s",
2572 aconf->name, aconf->host, who, reason);
2573 }
2574 }
2575
2576 /* get rid of klined clients */
2577 for (i = highest_fd; i >= 0; i--)
2578 {
2579 if (!(acptr = local[i]) || !IsPerson(acptr)
2580 || IsKlineExempt(acptr))
2581 {
2582 continue;
2583 }
2584 if (!strcmp(acptr->sockhost, acptr->user->sip))
2585 {
2586 /* unresolved */
2587 if (strchr(aconf->host, '/'))
2588 {
2589 if (match_ipmask(*aconf->host == '=' ?
2590 aconf->host + 1 : aconf->host,
2591 acptr, 1))
2592 {
2593 continue;
2594 }
2595 }
2596 else
2597 {
2598 if (match(*aconf->host == '=' ?
2599 aconf->host + 1 : aconf->host,
2600 acptr->sockhost))
2601 {
2602 continue;
2603 }
2604 }
2605 }
2606 else
2607 {
2608 /* resolved */
2609 if (*aconf->host == '=')
2610 {
2611 /* IP only */
2612 continue;
2613 }
2614 if (strchr(aconf->host, '/'))
2615 {
2616 if (match_ipmask(aconf->host, acptr, 1))
2617 {
2618 continue;
2619 }
2620 }
2621 else
2622 {
2623 if (match(aconf->host, acptr->user->sip)
2624 && match(aconf->host,
2625 acptr->user->host))
2626 {
2627 continue;
2628 }
2629 }
2630 }
2631 if (match(aconf->name, aconf->status == CONF_TOTHERKILL ?
2632 acptr->auth : (IsRestricted(acptr) &&
2633 acptr->user->username[0] == '+' ?
2634 acptr->user->username+1 :
2635 acptr->user->username)) == 0)
2636 {
2637 count++;
2638 sendto_one(acptr, replies[ERR_YOUREBANNEDCREEP],
2639 ME, acptr->name, aconf->name, aconf->host,
2640 ": ", aconf->passwd);
2641 sendto_flag(SCH_TKILL,
2642 "%sKill line active for %s", tkline?"T":"",
2643 get_client_name(acptr, FALSE));
2644 if (buff[0] == '\0')
2645 {
2646 sprintf(buff, "Kill line active: %.80s",
2647 aconf->passwd);
2648 }
2649 acptr->exitc = tkline ? EXITC_TKLINE : EXITC_KLINE;
2650 (void) exit_client(acptr, acptr, &me, buff);
2651 }
2652 }
2653 if (count > 4)
2654 {
2655 sendto_flag(SCH_TKILL, "%sKline reaped %d souls",
2656 tkline?"T":"", count);
2657 }
2658
2659#ifdef TKLINE
2660 /* do next tkexpire, but not more often than once a minute */
2661 if (!nexttkexpire || nexttkexpire > aconf->hold)
2662 {
2663 nexttkexpire = MAX(timeofday + 60, aconf->hold);
2664 }
2665#endif
2666 return;
2667}
2668
2669int prep_kline(int tkline, aClient *cptr, aClient *sptr, int parc, char **parv)
2670{
2671 int status = tkline ? CONF_TKILL : CONF_KILL;
2672 time_t time;
2673 char *user, *host, *reason;
2674 int i = 0;
2675
2676 /* sanity checks */
2677 if (tkline)
2678 {
2679 i = wdhms2sec(parv[1], &time);
2680#ifdef TKLINE_MAXTIME
2681 if (time > TKLINE_MAXTIME)
2682 time = TKLINE_MAXTIME;
2683 if (time < 0) /* overflown, must have wanted bignum :) */
2684 time = TKLINE_MAXTIME;
2685#endif
2686 user = parv[2];
2687 reason = parv[3];
2688 }
2689 else
2690 {
2691 user = parv[1];
2692 reason = parv[2];
2693 }
2694 host = strchr(user, '@');
2695
2696 if (strlen(user) > USERLEN+HOSTLEN+1)
2697 {
2698 /* induce error */
2699 i = 1;
2700 }
2701 if (!strcmp("@*", user) || !strcmp("*@", user) || !strcmp("@", user))
2702 {
2703 /* Note that we don't forbid "*@*", only those, that lack
2704 ** some crucial parts, which can be seen as a typo. --Beeth */
2705 i = 1;
2706 }
2707#ifdef KLINE
2708badkline:
2709#endif
2710 if (i || !host)
2711 {
2712 /* error */
2713 if (!IsPerson(sptr))
2714 {
2715 sendto_one(sptr, ":%s NOTICE %s "
2716 ":T/KLINE: Incorrect format",
2717 ME, parv[0]);
2718 return exit_client(cptr, cptr, &me,
2719 "T/KLINE: Incorrect format");
2720 }
2721 sendto_one(sptr, ":%s NOTICE %s :%sKLINE: Incorrect format",
2722 ME, parv[0], tkline?"T":"");
2723 return 2;
2724 }
2725
2726 /* All seems fine. */
2727 if (*user == '=')
2728 {
2729 status = tkline ? CONF_TOTHERKILL : CONF_OTHERKILL;
2730 user++;
2731 }
2732 *host++ = '\0';
2733#ifdef INET6
2734 host = ipv6_convert(host);
2735#endif
2736 if (strlen(reason) > TOPICLEN)
2737 {
2738 reason[TOPICLEN] = '\0';
2739 }
2740
2741#ifdef KLINE
2742 if (!tkline)
2743 {
2744 int kfd, ksize, kret;
2745 char kbuf[2*BUFSIZE];
2746 char *utmp, *htmp, *rtmp;
2747
2748 if (!strcmp(KLINE_PATH, IRCDCONF_PATH))
2749 {
2750 sendto_flag(SCH_ERROR,
2751 "Invalid kline configuration file.");
2752 return MAXPENALTY;
2753 }
2754 utmp = strchr(user, IRCDCONF_DELIMITER);
2755 htmp = strchr(host, IRCDCONF_DELIMITER);
2756 rtmp = strchr(reason, IRCDCONF_DELIMITER);
2757 if (utmp || htmp || rtmp)
2758 {
2759 /* Too lazy to copy it here. --B. */
2760 i = 1;
2761 goto badkline;
2762 }
2763
2764 kfd = open(KLINE_PATH, O_WRONLY|O_APPEND|O_NDELAY);
2765 if (kfd < 0)
2766 {
2767 sendto_flag(SCH_ERROR,
2768 "Cannot open kline configuration file.");
2769 return MAXPENALTY;
2770 }
2771 ksize = snprintf(kbuf, sizeof(kbuf),
2772 "%c%c%s%c%s%c%s%c0%c #%s%s%s%s%s#%d\n",
2773 (status == CONF_OTHERKILL ? 'k' : 'K'),
2774 IRCDCONF_DELIMITER, host, IRCDCONF_DELIMITER, reason,
2775 IRCDCONF_DELIMITER, user, IRCDCONF_DELIMITER,
2776 IRCDCONF_DELIMITER, sptr->name,
2777 sptr->user ? "!" : "",
2778 sptr->user ? sptr->user->username : "",
2779 sptr->user ? "@" : "",
2780 sptr->user ? sptr->user->host : "", (int)timeofday);
2781 kret = write(kfd, kbuf, ksize);
2782 close(kfd);
2783 if (kret != ksize)
2784 {
2785 sendto_flag(SCH_ERROR, "Error writing (%d!=%d) "
2786 "to kline configuration file.", kret, ksize);
2787 sendto_one(sptr, ":%s NOTICE %s :KLINE: error writing "
2788 "(%d!=%d) to kline configuration file",
2789 ME, parv[0], kret, ksize);
2790 return MAXPENALTY;
2791 }
2792 }
2793#endif /* KLINE */
2794
2795 /* All parameters are now sane. Do the stuff. */
2796 do_kline(tkline, parv[0], time, user, host, reason, status);
2797
2798 return 1;
2799}
2800#endif /* TKLINE || KLINE */
2801
2802#ifdef KLINE
2803int m_kline(aClient *cptr, aClient *sptr, int parc, char **parv)
2804{
2805 if (!is_allowed(sptr, ACL_KLINE))
2806 return m_nopriv(cptr, sptr, parc, parv);
2807 return prep_kline(0, cptr, sptr, parc, parv);
2808}
2809#endif
2810
2811#ifdef TKLINE
2812int m_tkline(aClient *cptr, aClient *sptr, int parc, char **parv)
2813{
2814 if (!is_allowed(sptr, ACL_TKLINE))
2815 return m_nopriv(cptr, sptr, parc, parv);
2816 return prep_kline(1, cptr, sptr, parc, parv);
2817}
2818
2819int m_untkline(aClient *cptr, aClient *sptr, int parc, char **parv)
2820{
2821 aConfItem *tmp, *prev;
2822 char *user, *host;
2823 int deleted = 0;
2824
2825 if (!is_allowed(sptr, ACL_UNTKLINE))
2826 return m_nopriv(cptr, sptr, parc, parv);
2827
2828 user = parv[1];
2829 host = strchr(user, '@');
2830 if (!host)
2831 {
2832 /* error */
2833 if (!IsPerson(sptr))
2834 {
2835 sendto_one(sptr, ":%s NOTICE %s "
2836 ":UNTKLINE: Incorrect format",
2837 ME, parv[0]);
2838 return exit_client(cptr, cptr, &me,
2839 "UNTKLINE: Incorrect format");
2840 }
2841 sendto_one(sptr, ":%s NOTICE %s :UNTKLINE: Incorrect format",
2842 ME, parv[0]);
2843 return 2;
2844 }
2845 if (*user == '=')
2846 {
2847 user++;
2848 }
2849 *host++ = '\0';
2850
2851 for (prev = tkconf, tmp = tkconf; tmp; tmp = tmp->next)
2852 {
2853 if (0==strcasecmp(tmp->host, host) &&
2854 0==strcasecmp(tmp->name, user))
2855 {
2856 if (tmp == tkconf)
2857 tkconf = tmp->next;
2858 else
2859 prev->next = tmp->next;
2860 free_conf(tmp);
2861 deleted = 1;
2862 break;
2863 }
2864 prev = tmp;
2865 }
2866
2867 if (deleted)
2868 {
2869 sendto_flag(SCH_TKILL, "UNTKLINE %s@%s by %s",
2870 user, host, parv[0]);
2871 }
2872 return 1;
2873}
2874
2875time_t tkline_expire(int all)
2876{
2877 aConfItem *tmp = NULL, *tmp2 = tkconf, *prev = tkconf;
2878 time_t min = 0;
2879
2880 while ((tmp = tmp2))
2881 {
2882 tmp2 = tmp->next;
2883 if (all || tmp->hold <= timeofday)
2884 {
2885 if (tmp == tkconf)
2886 tkconf = tmp->next;
2887 else
2888 prev->next = tmp->next;
2889 free_conf(tmp);
2890 continue;
2891 }
2892 if (min == 0 || tmp->hold < min)
2893 {
2894 min = tmp->hold;
2895 }
2896 prev = tmp;
2897 }
2898 if (min && min < nexttkexpire + 60)
2899 min = nexttkexpire + 60;
2900 return min;
2901}
2902#endif /* TKLINE */