2 * IRC - Internet Relay Chat, ircd/s_conf.c
3 * Copyright (C) 1990 Jarkko Oikarinen and
4 * University of Oulu, Computing Center
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)
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.
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.
21 * @brief ircd configuration file driver
22 * @version $Id: s_conf.c,v 1.81.2.8 2007/04/05 01:52:39 entrope Exp $
31 #include "ircd_features.h"
36 #include "ircd_alloc.h"
37 #include "ircd_chattr.h"
39 #include "ircd_reply.h"
40 #include "ircd_snprintf.h"
41 #include "ircd_string.h"
59 /* #include <assert.h> -- Now using assert in ircd_log.h */
69 /** Global list of all ConfItem structures. */
70 struct ConfItem
*GlobalConfList
;
71 /** Count of items in #GlobalConfList. */
73 /** Global list of service mappings. */
74 struct s_map
*GlobalServiceMapList
;
75 /** Global list of channel quarantines. */
76 struct qline
*GlobalQuarantineList
;
77 /** Global list of spoofhosts. */
78 struct sline
*GlobalSList
= 0;
80 /** Current line number in scanner input. */
83 /** Configuration information for #me. */
84 struct LocalConf localConf
;
85 /** Global list of connection rules. */
86 struct CRuleConf
* cruleConfList
;
87 /** Global list of K-lines. */
88 struct DenyConf
* denyConfList
;
90 /** Tell a user that they are banned, dumping the message from a file.
91 * @param sptr Client being rejected
92 * @param filename Send this file's contents to \a sptr
94 static void killcomment(struct Client
* sptr
, const char* filename
)
101 if (NULL
== (file
= fbopen(filename
, "r"))) {
102 send_reply(sptr
, ERR_NOMOTD
);
103 send_reply(sptr
, SND_EXPLICIT
| ERR_YOUREBANNEDCREEP
,
104 ":Connection from your host is refused on this server.");
108 tm
= localtime((time_t*) &sb
.st_mtime
); /* NetBSD needs cast */
109 while (fbgets(line
, sizeof(line
) - 1, file
)) {
110 char* end
= line
+ strlen(line
);
113 if ('\n' == *end
|| '\r' == *end
)
118 send_reply(sptr
, RPL_MOTD
, line
);
120 send_reply(sptr
, SND_EXPLICIT
| ERR_YOUREBANNEDCREEP
,
121 ":Connection from your host is refused on this server.");
125 /** Allocate a new struct ConfItem and link it to #GlobalConfList.
126 * @return Newly allocated structure.
128 struct ConfItem
* make_conf(int type
)
130 struct ConfItem
* aconf
;
132 aconf
= (struct ConfItem
*) MyMalloc(sizeof(struct ConfItem
));
135 memset(aconf
, 0, sizeof(struct ConfItem
));
136 aconf
->status
= type
;
137 aconf
->next
= GlobalConfList
;
138 GlobalConfList
= aconf
;
142 /** Free a struct ConfItem and any resources it owns.
143 * @param aconf Item to free.
145 void free_conf(struct ConfItem
*aconf
)
147 Debug((DEBUG_DEBUG
, "free_conf: %s %s %d",
148 aconf
->host
? aconf
->host
: "*",
149 aconf
->name
? aconf
->name
: "*",
150 aconf
->address
.port
));
151 if (aconf
->dns_pending
)
152 delete_resolver_queries(aconf
);
153 MyFree(aconf
->username
);
155 MyFree(aconf
->origin_name
);
157 memset(aconf
->passwd
, 0, strlen(aconf
->passwd
));
158 MyFree(aconf
->passwd
);
160 MyFree(aconf
->hub_limit
);
165 /** Disassociate configuration from the client.
166 * @param cptr Client to operate on.
167 * @param aconf ConfItem to detach.
169 static void detach_conf(struct Client
* cptr
, struct ConfItem
* aconf
)
176 assert(0 < aconf
->clients
);
178 lp
= &(cli_confs(cptr
));
181 if ((*lp
)->value
.aconf
== aconf
) {
182 if (aconf
->conn_class
&& (aconf
->status
& CONF_CLIENT_MASK
) && ConfLinks(aconf
) > 0)
185 assert(0 < aconf
->clients
);
186 if (0 == --aconf
->clients
&& IsIllegal(aconf
))
197 /** Parse a user\@host mask into username and host or IP parts.
198 * If \a host contains no username part, set \a aconf->username to
199 * NULL. If the host part of \a host looks like an IP mask, set \a
200 * aconf->addrbits and \a aconf->address to match. Otherwise, set
201 * \a aconf->host, and set \a aconf->addrbits to -1.
202 * @param[in,out] aconf Configuration item to set.
203 * @param[in] host user\@host mask to parse.
205 void conf_parse_userhost(struct ConfItem
*aconf
, char *host
)
208 unsigned char addrbits
;
210 MyFree(aconf
->username
);
212 host_part
= strchr(host
, '@');
215 DupString(aconf
->username
, host
);
218 aconf
->username
= NULL
;
221 DupString(aconf
->host
, host_part
);
222 if (ipmask_parse(aconf
->host
, &aconf
->address
.addr
, &addrbits
))
223 aconf
->addrbits
= addrbits
;
225 aconf
->addrbits
= -1;
228 /** Copies a completed DNS query into its ConfItem.
229 * @param vptr Pointer to struct ConfItem for the block.
230 * @param hp DNS reply, or NULL if the lookup failed.
232 static void conf_dns_callback(void* vptr
, const struct irc_in_addr
*addr
, const char *h_name
)
234 struct ConfItem
* aconf
= (struct ConfItem
*) vptr
;
236 aconf
->dns_pending
= 0;
238 memcpy(&aconf
->address
.addr
, addr
, sizeof(aconf
->address
.addr
));
241 /** Start a nameserver lookup of the conf host. If the conf entry is
242 * currently doing a lookup, do nothing.
243 * @param aconf ConfItem for which to start a request.
245 static void conf_dns_lookup(struct ConfItem
* aconf
)
247 if (!aconf
->dns_pending
) {
248 char buf
[HOSTLEN
+ 1];
250 host_from_uh(buf
, aconf
->host
, HOSTLEN
);
251 gethost_byname(buf
, conf_dns_callback
, aconf
);
252 aconf
->dns_pending
= 1;
257 /** Start lookups of all addresses in the conf line. The origin must
258 * be a numeric IP address. If the remote host field is not an IP
259 * address, start a DNS lookup for it.
260 * @param aconf Connection to do lookups for.
263 lookup_confhost(struct ConfItem
*aconf
)
265 if (EmptyString(aconf
->host
) || EmptyString(aconf
->name
)) {
266 Debug((DEBUG_ERROR
, "Host/server name error: (%s) (%s)",
267 aconf
->host
, aconf
->name
));
270 if (aconf
->origin_name
271 && !ircd_aton(&aconf
->origin
.addr
, aconf
->origin_name
)) {
272 Debug((DEBUG_ERROR
, "Origin name error: (%s) (%s)",
273 aconf
->origin_name
, aconf
->name
));
276 * Do name lookup now on hostnames given and store the
277 * ip numbers in conf structure.
279 if (IsIP6Char(*aconf
->host
)) {
280 if (!ircd_aton(&aconf
->address
.addr
, aconf
->host
)) {
281 Debug((DEBUG_ERROR
, "Host/server name error: (%s) (%s)",
282 aconf
->host
, aconf
->name
));
286 conf_dns_lookup(aconf
);
289 /** Find a server by name or hostname.
290 * @param name Server name to find.
291 * @return Pointer to the corresponding ConfItem, or NULL if none exists.
293 struct ConfItem
* conf_find_server(const char* name
)
295 struct ConfItem
* conf
;
298 for (conf
= GlobalConfList
; conf
; conf
= conf
->next
) {
299 if (CONF_SERVER
== conf
->status
) {
301 * Check first servernames, then try hostnames.
302 * XXX - match returns 0 if there _is_ a match... guess they
303 * haven't decided what true is yet
305 if (0 == match(name
, conf
->name
))
312 /** Evaluate connection rules.
313 * @param name Name of server to check
314 * @param mask Filter for CRule types (only consider if type & \a mask != 0).
315 * @return Name of rule that forbids the connection; NULL if no prohibitions.
317 const char* conf_eval_crule(const char* name
, int mask
)
319 struct CRuleConf
* p
= cruleConfList
;
322 for ( ; p
; p
= p
->next
) {
323 if (0 != (p
->type
& mask
) && 0 == match(p
->hostmask
, name
)) {
324 if (crule_eval(p
->node
))
331 /** Remove all conf entries from the client except those which match
332 * the status field mask.
333 * @param cptr Client to operate on.
334 * @param mask ConfItem types to keep.
336 void det_confs_butmask(struct Client
* cptr
, int mask
)
342 for (link
= cli_confs(cptr
); link
; link
= next
) {
344 if ((link
->value
.aconf
->status
& mask
) == 0)
345 detach_conf(cptr
, link
->value
.aconf
);
349 /** Find the first (best) Client block to attach.
350 * @param cptr Client for whom to check rules.
351 * @return Authorization check result.
353 enum AuthorizationCheckResult
attach_iline(struct Client
* cptr
)
355 struct ConfItem
* aconf
;
359 for (aconf
= GlobalConfList
; aconf
; aconf
= aconf
->next
) {
360 if (aconf
->status
!= CONF_CLIENT
)
362 /* If you change any of this logic, please make corresponding
363 * changes in conf_debug_iline() below.
365 if (aconf
->address
.port
&& aconf
->address
.port
!= cli_listener(cptr
)->addr
.port
)
367 if (aconf
->username
&& match(aconf
->username
, cli_username(cptr
)))
369 if (aconf
->host
&& match(aconf
->host
, cli_sockhost(cptr
)))
371 if ((aconf
->addrbits
>= 0)
372 && !ipmask_check(&cli_ip(cptr
), &aconf
->address
.addr
, aconf
->addrbits
))
374 if (IPcheck_nr(cptr
) > aconf
->maximum
)
375 return ACR_TOO_MANY_FROM_IP
;
377 SetFlag(cptr
, FLAG_DOID
);
378 return attach_conf(cptr
, aconf
);
380 return ACR_NO_AUTHORIZATION
;
383 /** Interpret \a client as a client specifier and show which Client
384 * block(s) match that client.
386 * The client specifier may contain an IP address, hostname, listener
387 * port, or a combination of those separated by commas. IP addresses
388 * and hostnamese may be preceded by "username@"; the last given
389 * username will be used for the match.
391 * @param[in] client Client specifier.
392 * @return Matching Client block structure.
394 struct ConfItem
*conf_debug_iline(const char *client
)
396 struct irc_in_addr address
;
397 struct ConfItem
*aconf
;
398 struct DenyConf
*deny
;
400 unsigned short listener
;
401 char username
[USERLEN
+1], hostname
[HOSTLEN
+1], realname
[REALLEN
+1];
403 /* Initialize variables. */
405 memset(&address
, 0, sizeof(address
));
406 memset(&username
, 0, sizeof(username
));
407 memset(&hostname
, 0, sizeof(hostname
));
408 memset(&realname
, 0, sizeof(realname
));
410 /* Parse client specifier. */
412 struct irc_in_addr tmpaddr
;
415 /* Try to parse as listener port number first. */
416 tmp
= strtol(client
, &sep
, 10);
417 if (tmp
&& (*sep
== '\0' || *sep
== ',')) {
419 client
= sep
+ (*sep
!= '\0');
423 /* Maybe username@ before an IP address or hostname? */
424 tmp
= strcspn(client
, ",@");
425 if (client
[tmp
] == '@') {
428 ircd_strncpy(username
, client
, tmp
);
429 /* and fall through */
433 /* Looks like an IP address? */
434 tmp
= ircd_aton(&tmpaddr
, client
);
435 if (tmp
&& (client
[tmp
] == '\0' || client
[tmp
] == ',')) {
436 memcpy(&address
, &tmpaddr
, sizeof(address
));
437 client
+= tmp
+ (client
[tmp
] != '\0');
442 if (client
[0] == '$' && client
[1] == 'R') {
444 for (tmp
= 0; *client
!= '\0' && *client
!= ',' && tmp
< REALLEN
; ++client
, ++tmp
) {
446 realname
[tmp
] = *++client
;
448 realname
[tmp
] = *client
;
453 /* Else must be a hostname. */
454 tmp
= strcspn(client
, ",");
457 ircd_strncpy(hostname
, client
, tmp
);
458 client
+= tmp
+ (client
[tmp
] != '\0');
461 /* Walk configuration to find matching Client block. */
462 for (aconf
= GlobalConfList
; aconf
; aconf
= aconf
->next
) {
463 if (aconf
->status
!= CONF_CLIENT
)
465 if (aconf
->address
.port
&& aconf
->address
.port
!= listener
) {
466 fprintf(stdout
, "Listener port mismatch: %u != %u\n", aconf
->address
.port
, listener
);
469 if (aconf
->username
&& match(aconf
->username
, username
)) {
470 fprintf(stdout
, "Username mismatch: %s != %s\n", aconf
->username
, username
);
473 if (aconf
->host
&& match(aconf
->host
, hostname
)) {
474 fprintf(stdout
, "Hostname mismatch: %s != %s\n", aconf
->host
, hostname
);
477 if ((aconf
->addrbits
>= 0)
478 && !ipmask_check(&address
, &aconf
->address
.addr
, aconf
->addrbits
)) {
479 fprintf(stdout
, "IP address mismatch: %s != %s\n", aconf
->name
, ircd_ntoa(&address
));
482 fprintf(stdout
, "Match! username=%s host=%s ip=%s class=%s maxlinks=%u password=%s\n",
483 (aconf
->username
? aconf
->username
: "(null)"),
484 (aconf
->host
? aconf
->host
: "(null)"),
485 (aconf
->name
? aconf
->name
: "(null)"),
486 ConfClass(aconf
), aconf
->maximum
,
487 (aconf
->passwd
? aconf
->passwd
: "(null)"));
491 /* If no authorization, say so and exit. */
494 fprintf(stdout
, "No authorization found.\n");
498 /* Look for a Kill block with the user's name on it. */
499 for (deny
= denyConfList
; deny
; deny
= deny
->next
) {
500 if (deny
->usermask
&& match(deny
->usermask
, username
))
502 if (deny
->realmask
&& match(deny
->realmask
, realname
))
504 if (deny
->bits
> 0) {
505 if (!ipmask_check(&address
, &deny
->address
, deny
->bits
))
507 } else if (deny
->hostmask
&& match(deny
->hostmask
, hostname
))
510 /* Looks like a match; report it. */
511 fprintf(stdout
, "Denied! usermask=%s realmask=\"%s\" hostmask=%s (bits=%u)\n",
512 deny
->usermask
? deny
->usermask
: "(null)",
513 deny
->realmask
? deny
->realmask
: "(null)",
514 deny
->hostmask
? deny
->hostmask
: "(null)",
521 /** Check whether a particular ConfItem is already attached to a
523 * @param aconf ConfItem to search for
524 * @param cptr Client to check
525 * @return Non-zero if \a aconf is attached to \a cptr, zero if not.
527 static int is_attached(struct ConfItem
*aconf
, struct Client
*cptr
)
531 for (lp
= cli_confs(cptr
); lp
; lp
= lp
->next
) {
532 if (lp
->value
.aconf
== aconf
)
538 /** Associate a specific configuration entry to a *local* client (this
539 * is the one which used in accepting the connection). Note, that this
540 * automatically changes the attachment if there was an old one...
541 * @param cptr Client to attach \a aconf to
542 * @param aconf ConfItem to attach
543 * @return Authorization check result.
545 enum AuthorizationCheckResult
attach_conf(struct Client
*cptr
, struct ConfItem
*aconf
)
549 if (is_attached(aconf
, cptr
))
550 return ACR_ALREADY_AUTHORIZED
;
551 if (IsIllegal(aconf
))
552 return ACR_NO_AUTHORIZATION
;
553 if ((aconf
->status
& (CONF_OPERATOR
| CONF_CLIENT
)) &&
554 ConfLinks(aconf
) >= ConfMaxLinks(aconf
) && ConfMaxLinks(aconf
) > 0)
555 return ACR_TOO_MANY_IN_CLASS
; /* Use this for printing error message */
557 lp
->next
= cli_confs(cptr
);
558 lp
->value
.aconf
= aconf
;
559 cli_confs(cptr
) = lp
;
561 if (aconf
->status
& CONF_CLIENT_MASK
)
566 /** Return our LocalConf configuration structure.
567 * @return A pointer to #localConf.
569 const struct LocalConf
* conf_get_local(void)
574 /** Attach ConfItems to a client if the name passed matches that for
575 * the ConfItems or is an exact match for them.
576 * @param cptr Client getting the ConfItem attachments.
577 * @param name Filter to match ConfItem::name.
578 * @param statmask Filter to limit ConfItem::status.
579 * @return First ConfItem attached to \a cptr.
581 struct ConfItem
* attach_confs_byname(struct Client
* cptr
, const char* name
,
584 struct ConfItem
* tmp
;
585 struct ConfItem
* first
= NULL
;
589 if (HOSTLEN
< strlen(name
))
592 for (tmp
= GlobalConfList
; tmp
; tmp
= tmp
->next
) {
593 if (0 != (tmp
->status
& statmask
) && !IsIllegal(tmp
)) {
594 assert(0 != tmp
->name
);
595 if (0 == match(tmp
->name
, name
) || 0 == ircd_strcmp(tmp
->name
, name
)) {
596 if (ACR_OK
== attach_conf(cptr
, tmp
) && !first
)
604 /** Attach ConfItems to a client if the host passed matches that for
605 * the ConfItems or is an exact match for them.
606 * @param cptr Client getting the ConfItem attachments.
607 * @param host Filter to match ConfItem::host.
608 * @param statmask Filter to limit ConfItem::status.
609 * @return First ConfItem attached to \a cptr.
611 struct ConfItem
* attach_confs_byhost(struct Client
* cptr
, const char* host
,
614 struct ConfItem
* tmp
;
615 struct ConfItem
* first
= 0;
618 if (HOSTLEN
< strlen(host
))
621 for (tmp
= GlobalConfList
; tmp
; tmp
= tmp
->next
) {
622 if (0 != (tmp
->status
& statmask
) && !IsIllegal(tmp
)) {
623 assert(0 != tmp
->host
);
624 if (0 == match(tmp
->host
, host
) || 0 == ircd_strcmp(tmp
->host
, host
)) {
625 if (ACR_OK
== attach_conf(cptr
, tmp
) && !first
)
633 /** Find a ConfItem that has the same name and user+host fields as
634 * specified. Requires an exact match for \a name.
635 * @param name Name to match
636 * @param cptr Client to match against
637 * @param statmask Filter for ConfItem::status
638 * @return First found matching ConfItem.
640 struct ConfItem
* find_conf_exact(const char* name
, struct Client
*cptr
, int statmask
)
642 struct ConfItem
*tmp
;
644 for (tmp
= GlobalConfList
; tmp
; tmp
= tmp
->next
) {
645 if (!(tmp
->status
& statmask
) || !tmp
->name
|| !tmp
->host
||
646 0 != ircd_strcmp(tmp
->name
, name
))
649 && (EmptyString(cli_username(cptr
))
650 || match(tmp
->username
, cli_username(cptr
))))
652 if (tmp
->addrbits
< 0)
654 if (match(tmp
->host
, cli_sockhost(cptr
)))
657 else if (!ipmask_check(&cli_ip(cptr
), &tmp
->address
.addr
, tmp
->addrbits
))
659 if ((tmp
->status
& CONF_OPERATOR
)
660 && (MaxLinks(tmp
->conn_class
) > 0)
661 && (tmp
->clients
>= MaxLinks(tmp
->conn_class
)))
668 /** Find a ConfItem from a list that has a name that matches \a name.
669 * @param lp List to search in.
670 * @param name Filter for ConfItem::name field; matches either exactly
672 * @param statmask Filter for ConfItem::status.
673 * @return First matching ConfItem from \a lp.
675 struct ConfItem
* find_conf_byname(struct SLink
* lp
, const char* name
,
678 struct ConfItem
* tmp
;
681 if (HOSTLEN
< strlen(name
))
684 for (; lp
; lp
= lp
->next
) {
685 tmp
= lp
->value
.aconf
;
686 if (0 != (tmp
->status
& statmask
)) {
687 assert(0 != tmp
->name
);
688 if (0 == ircd_strcmp(tmp
->name
, name
) || 0 == match(tmp
->name
, name
))
695 /** Find a ConfItem from a list that has a host that matches \a host.
696 * @param lp List to search in.
697 * @param host Filter for ConfItem::host field; matches as a glob.
698 * @param statmask Filter for ConfItem::status.
699 * @return First matching ConfItem from \a lp.
701 struct ConfItem
* find_conf_byhost(struct SLink
* lp
, const char* host
,
704 struct ConfItem
* tmp
= NULL
;
707 if (HOSTLEN
< strlen(host
))
710 for (; lp
; lp
= lp
->next
) {
711 tmp
= lp
->value
.aconf
;
712 if (0 != (tmp
->status
& statmask
)) {
713 assert(0 != tmp
->host
);
714 if (0 == match(tmp
->host
, host
))
721 /** Find a ConfItem from a list that has an address equal to \a ip.
722 * @param lp List to search in.
723 * @param ip Filter for ConfItem::address field; matches exactly.
724 * @param statmask Filter for ConfItem::status.
725 * @return First matching ConfItem from \a lp.
727 struct ConfItem
* find_conf_byip(struct SLink
* lp
, const struct irc_in_addr
* ip
,
730 struct ConfItem
* tmp
;
732 for (; lp
; lp
= lp
->next
) {
733 tmp
= lp
->value
.aconf
;
734 if (0 != (tmp
->status
& statmask
)
735 && !irc_in_addr_cmp(&tmp
->address
.addr
, ip
))
741 /** Free all CRules from #cruleConfList. */
742 void conf_erase_crule_list(void)
744 struct CRuleConf
* next
;
745 struct CRuleConf
* p
= cruleConfList
;
747 for ( ; p
; p
= next
) {
749 crule_free(&p
->node
);
757 /** Return #cruleConfList.
758 * @return #cruleConfList
760 const struct CRuleConf
* conf_get_crule_list(void)
762 return cruleConfList
;
765 /** Free all deny rules from #denyConfList. */
766 void conf_erase_deny_list(void)
768 struct DenyConf
* next
;
769 struct DenyConf
* p
= denyConfList
;
770 for ( ; p
; p
= next
) {
781 /** Return #denyConfList.
782 * @return #denyConfList
784 const struct DenyConf
* conf_get_deny_list(void)
789 /** Find any existing quarantine for the named channel.
790 * @param chname Channel name to search for.
791 * @return Reason for channel's quarantine, or NULL if none exists.
794 find_quarantine(const char *chname
)
798 for (qline
= GlobalQuarantineList
; qline
; qline
= qline
->next
)
799 if (!ircd_strcmp(qline
->chname
, chname
))
800 return qline
->reason
;
804 /** Free all qline structs from #GlobalQuarantineList. */
805 void clear_quarantines(void)
808 while ((qline
= GlobalQuarantineList
))
810 GlobalQuarantineList
= qline
->next
;
811 MyFree(qline
->reason
);
812 MyFree(qline
->chname
);
817 /** When non-zero, indicates that a configuration error has been seen in this pass. */
818 static int conf_error
;
819 /** When non-zero, indicates that the configuration file was loaded at least once. */
820 static int conf_already_read
;
822 extern void yyparse(void);
823 extern void init_lexer(void);
825 /** Read configuration file.
826 * @return Zero on failure, non-zero on success. */
827 int read_configuration_file(void)
830 feature_unmark(); /* unmark all features for resetting later */
831 clear_nameservers(); /* clear previous list of DNS servers */
832 /* Now just open an fd. The buffering isn't really needed... */
837 feature_mark(); /* reset unmarked features */
838 conf_already_read
= 1;
842 /** Report an error message about the configuration file.
843 * @param msg The error to report.
846 yyerror(const char *msg
)
848 sendto_opmask_butone(0, SNO_ALL
, "Config file parse error line %d: %s",
850 log_write(LS_CONFIG
, L_ERROR
, 0, "Config file parse error line %d: %s",
852 if (!conf_already_read
)
853 fprintf(stderr
, "Config file parse error line %d: %s\n", lineno
, msg
);
857 /** Attach CONF_UWORLD items to a server and everything attached to it. */
859 attach_conf_uworld(struct Client
*cptr
)
863 attach_confs_byhost(cptr
, cli_name(cptr
), CONF_UWORLD
);
864 for (lp
= cli_serv(cptr
)->down
; lp
; lp
= lp
->next
)
865 attach_conf_uworld(lp
->value
.cptr
);
868 /** Free all memory associated with service mapping \a smap.
869 * @param smap[in] The mapping to free.
871 void free_mapping(struct s_map
*smap
)
873 struct nick_host
*nh
, *next
;
874 for (nh
= smap
->services
; nh
; nh
= next
)
880 MyFree(smap
->command
);
881 MyFree(smap
->prepend
);
885 /** Unregister and free all current service mappings. */
886 static void close_mappings(void)
888 struct s_map
*map
, *next
;
890 for (map
= GlobalServiceMapList
; map
; map
= next
) {
892 unregister_mapping(map
);
895 GlobalServiceMapList
= NULL
;
898 /** Reload the configuration file.
899 * @param cptr Client that requested rehash (if a signal, &me).
900 * @param sig Type of rehash (0 = oper-requested, 1 = signal, 2 =
901 * oper-requested but do not restart resolver)
902 * @return CPTR_KILLED if any client was K/G-lined because of the
903 * rehash; otherwise 0.
905 int rehash(struct Client
*cptr
, int sig
)
907 struct ConfItem
** tmp
= &GlobalConfList
;
908 struct ConfItem
* tmp2
;
909 struct Client
* acptr
;
915 sendto_opmask_butone(0, SNO_OLDSNO
,
916 "Got signal SIGHUP, reloading ircd conf. file");
918 while ((tmp2
= *tmp
)) {
921 * Configuration entry is still in use by some
922 * local clients, cannot delete it--mark it so
923 * that it will be deleted when the last client
926 if (CONF_CLIENT
== (tmp2
->status
& CONF_CLIENT
))
932 tmp2
->status
|= CONF_ILLEGAL
;
939 conf_erase_crule_list();
940 conf_erase_deny_list();
944 * delete the juped nicks list
952 mark_listeners_closing();
956 read_configuration_file();
961 log_reopen(); /* reopen log files */
965 class_delete_marked(); /* unless it fails */
968 * Flush out deleted I and P lines although still in use.
970 for (tmp
= &GlobalConfList
; (tmp2
= *tmp
);) {
971 if (CONF_ILLEGAL
== (tmp2
->status
& CONF_ILLEGAL
)) {
981 for (i
= 0; i
<= HighestFd
; i
++) {
982 if ((acptr
= LocalClientArray
[i
])) {
983 assert(!IsMe(acptr
));
985 det_confs_butmask(acptr
, ~(CONF_UWORLD
| CONF_ILLEGAL
));
986 /* Because admin's are getting so uppity about people managing to
987 * get past K/G's etc, we'll "fix" the bug by actually explaining
990 if ((found_g
= find_kill(acptr
, 0))) {
991 sendto_opmask_butone(0, found_g
== -2 ? SNO_GLINE
: SNO_OPERKILL
,
992 found_g
== -2 ? "G-line active for %s%s" :
993 "K-line active for %s%s",
994 IsUnknown(acptr
) ? "Unregistered Client ":"",
995 get_client_name(acptr
, SHOW_IP
));
996 if (exit_client(cptr
, acptr
, &me
, found_g
== -2 ? "G-lined" :
997 "K-lined") == CPTR_KILLED
)
1003 attach_conf_uworld(&me
);
1008 /** Read configuration file for the very first time.
1009 * @return Non-zero on success, zero on failure.
1014 if (read_configuration_file()) {
1016 * make sure we're sane to start if the config
1017 * file read didn't get everything we need.
1018 * XXX - should any of these abort the server?
1019 * TODO: add warning messages
1021 if (0 == localConf
.name
|| 0 == localConf
.numeric
)
1026 if (0 == localConf
.location1
)
1027 DupString(localConf
.location1
, "");
1028 if (0 == localConf
.location2
)
1029 DupString(localConf
.location2
, "");
1030 if (0 == localConf
.contact
)
1031 DupString(localConf
.contact
, "");
1038 /** Searches for a K/G-line for a client. If one is found, notify the
1039 * user and disconnect them.
1040 * @param cptr Client to search for.
1041 * @param glinecheck Whether we check for glines.
1042 * @return 0 if client is accepted; -1 if client was locally denied
1043 * (K-line); -2 if client was globally denied (G-line).
1045 int find_kill(struct Client
*cptr
, int glinecheck
)
1049 const char* realname
;
1050 struct DenyConf
* deny
;
1051 struct Gline
* agline
= NULL
;
1055 if (!cli_user(cptr
))
1058 host
= cli_sockhost(cptr
);
1059 name
= cli_user(cptr
)->username
;
1060 realname
= cli_info(cptr
);
1062 assert(strlen(host
) <= HOSTLEN
);
1063 assert((name
? strlen(name
) : 0) <= HOSTLEN
);
1064 assert((realname
? strlen(realname
) : 0) <= REALLEN
);
1066 /* 2000-07-14: Rewrote this loop for massive speed increases.
1069 for (deny
= denyConfList
; deny
; deny
= deny
->next
) {
1070 if (deny
->usermask
&& match(deny
->usermask
, name
))
1072 if (deny
->realmask
&& match(deny
->realmask
, realname
))
1074 if (deny
->bits
> 0) {
1075 if (!ipmask_check(&cli_ip(cptr
), &deny
->address
, deny
->bits
))
1077 } else if (deny
->hostmask
&& match(deny
->hostmask
, host
))
1080 if (EmptyString(deny
->message
))
1081 send_reply(cptr
, SND_EXPLICIT
| ERR_YOUREBANNEDCREEP
,
1082 ":Connection from your host is refused on this server.");
1084 if (deny
->flags
& DENY_FLAGS_FILE
)
1085 killcomment(cptr
, deny
->message
);
1087 send_reply(cptr
, SND_EXPLICIT
| ERR_YOUREBANNEDCREEP
, ":%s.", deny
->message
);
1092 /* added glinecheck to define if we check for glines too, shouldn't happen
1093 * when rehashing as it is causing problems with big servers and lots of glines.
1094 * Think of a 18000 user leaf with 18000 glines present, this will probably
1095 * cause the server to split from the net.
1098 if (glinecheck
&& (agline
= gline_lookup(cptr
, 0)) && GlineIsActive(agline
)) {
1100 * find active glines
1101 * added a check against the user's IP address to find_gline() -Kev
1103 send_reply(cptr
, SND_EXPLICIT
| ERR_YOUREBANNEDCREEP
, ":%s.", GlineReason(agline
));
1110 /** Attempt to attach Client blocks to \a cptr. If attach_iline()
1111 * fails for the client, emit a debugging message.
1112 * @param cptr Client to check for access.
1113 * @return Access check result.
1115 enum AuthorizationCheckResult
conf_check_client(struct Client
*cptr
)
1117 enum AuthorizationCheckResult acr
= ACR_OK
;
1119 if ((acr
= attach_iline(cptr
))) {
1120 Debug((DEBUG_DNS
, "ch_cl: access denied: %s[%s]",
1121 cli_name(cptr
), cli_sockhost(cptr
)));
1127 /** Check access for a server given its name (passed in cptr struct).
1128 * Must check for all C/N lines which have a name which matches the
1129 * name given and a host which matches. A host alias which is the
1130 * same as the server name is also acceptable in the host field of a
1132 * @param cptr Peer server to check.
1133 * @return 0 if accepted, -1 if access denied.
1135 int conf_check_server(struct Client
*cptr
)
1137 struct ConfItem
* c_conf
= NULL
;
1140 Debug((DEBUG_DNS
, "sv_cl: check access for %s[%s]",
1141 cli_name(cptr
), cli_sockhost(cptr
)));
1143 if (IsUnknown(cptr
) && !attach_confs_byname(cptr
, cli_name(cptr
), CONF_SERVER
)) {
1144 Debug((DEBUG_DNS
, "No C/N lines for %s", cli_sockhost(cptr
)));
1147 lp
= cli_confs(cptr
);
1149 * We initiated this connection so the client should have a C and N
1150 * line already attached after passing through the connect_server()
1153 if (IsConnecting(cptr
) || IsHandshake(cptr
)) {
1154 c_conf
= find_conf_byname(lp
, cli_name(cptr
), CONF_SERVER
);
1156 sendto_opmask_butone(0, SNO_OLDSNO
,
1157 "Connect Error: lost Connect block for %s",
1159 det_confs_butmask(cptr
, 0);
1164 /* Try finding the Connect block by DNS name and IP next. */
1165 if (!c_conf
&& !(c_conf
= find_conf_byhost(lp
, cli_sockhost(cptr
), CONF_SERVER
)))
1166 c_conf
= find_conf_byip(lp
, &cli_ip(cptr
), CONF_SERVER
);
1169 * Attach by IP# only if all other checks have failed.
1170 * It is quite possible to get here with the strange things that can
1171 * happen when using DNS in the way the irc server does. -avalon
1174 c_conf
= find_conf_byip(lp
, &cli_ip(cptr
), CONF_SERVER
);
1176 * detach all conf lines that got attached by attach_confs()
1178 det_confs_butmask(cptr
, 0);
1180 * if no Connect block, then deny access
1183 Debug((DEBUG_DNS
, "sv_cl: access denied: %s[%s@%s]",
1184 cli_name(cptr
), cli_username(cptr
), cli_sockhost(cptr
)));
1188 * attach the Connect block to the client structure for later use.
1190 attach_conf(cptr
, c_conf
);
1192 if (!irc_in_addr_valid(&c_conf
->address
.addr
))
1193 memcpy(&c_conf
->address
.addr
, &cli_ip(cptr
), sizeof(c_conf
->address
.addr
));
1195 Debug((DEBUG_DNS
, "sv_cl: access ok: %s[%s]",
1196 cli_name(cptr
), cli_sockhost(cptr
)));
1200 void clear_slines(void)
1202 struct sline
*sline
;
1203 while ((sline
= GlobalSList
)) {
1204 GlobalSList
= sline
->next
;
1205 MyFree(sline
->spoofhost
);
1206 if (!EmptyString(sline
->passwd
))
1207 MyFree(sline
->passwd
);
1208 if (!EmptyString(sline
->realhost
))
1209 MyFree(sline
->realhost
);
1210 if (!EmptyString(sline
->username
))
1211 MyFree(sline
->username
);
1217 * conf_check_slines()
1219 * Check S lines for the specified client, passed in cptr struct.
1220 * If the client's IP is S-lined, process the substitution here.
1226 * 0 = No S-line found
1227 * 1 = S-line found and substitution done.
1235 conf_check_slines(struct Client
*cptr
)
1237 struct sline
*sconf
;
1240 for (sconf
= GlobalSList
; sconf
; sconf
= sconf
->next
) {
1241 if (sconf
->flags
== SLINE_FLAGS_IP
) {
1242 if (!ipmask_check(&(cli_ip(cptr
)), &(sconf
->address
), sconf
->bits
))
1244 } else if (sconf
->flags
== SLINE_FLAGS_HOSTNAME
) {
1245 if ((match(sconf
->realhost
, cli_sockhost(cptr
)) != 0) &&
1246 (match(sconf
->realhost
, cli_sock_ip(cptr
)) != 0)) /* wildcarded IP address */
1252 if (match(sconf
->username
, cli_user(cptr
)->username
) == 0) {
1253 /* Ignore user part if u@h. */
1254 if ((hostonly
= strchr(sconf
->spoofhost
, '@')))
1257 hostonly
= sconf
->spoofhost
;
1262 ircd_strncpy(cli_user(cptr
)->host
, hostonly
, HOSTLEN
);
1263 log_write(LS_USER
, L_INFO
, LOG_NOSNOTICE
, "S-Line (%s@%s) by (%#R)",
1264 cli_user(cptr
)->username
, hostonly
, cptr
);
1271 void free_spoofhost(struct sline
*spoof
) {
1272 MyFree(spoof
->spoofhost
);
1273 MyFree(spoof
->passwd
);
1274 MyFree(spoof
->realhost
);
1275 MyFree(spoof
->username
);