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.1 2005/10/06 00:37:31 entrope Exp $
31 #include "ircd_features.h"
36 #include "ircd_alloc.h"
37 #include "ircd_auth.h"
38 #include "ircd_chattr.h"
40 #include "ircd_reply.h"
41 #include "ircd_snprintf.h"
42 #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;
229 /** Copies a completed DNS query into its ConfItem.
230 * @param vptr Pointer to struct ConfItem for the block.
231 * @param hp DNS reply, or NULL if the lookup failed.
233 static void conf_dns_callback(void* vptr
, const struct irc_in_addr
*addr
, const char *h_name
)
235 struct ConfItem
* aconf
= (struct ConfItem
*) vptr
;
237 aconf
->dns_pending
= 0;
239 memcpy(&aconf
->address
.addr
, addr
, sizeof(aconf
->address
.addr
));
242 /** Start a nameserver lookup of the conf host. If the conf entry is
243 * currently doing a lookup, do nothing.
244 * @param aconf ConfItem for which to start a request.
246 static void conf_dns_lookup(struct ConfItem
* aconf
)
248 if (!aconf
->dns_pending
) {
249 char buf
[HOSTLEN
+ 1];
251 host_from_uh(buf
, aconf
->host
, HOSTLEN
);
252 gethost_byname(buf
, conf_dns_callback
, aconf
);
253 aconf
->dns_pending
= 1;
258 /** Start lookups of all addresses in the conf line. The origin must
259 * be a numeric IP address. If the remote host field is not an IP
260 * address, start a DNS lookup for it.
261 * @param aconf Connection to do lookups for.
264 lookup_confhost(struct ConfItem
*aconf
)
266 if (EmptyString(aconf
->host
) || EmptyString(aconf
->name
)) {
267 Debug((DEBUG_ERROR
, "Host/server name error: (%s) (%s)",
268 aconf
->host
, aconf
->name
));
271 if (aconf
->origin_name
272 && !ircd_aton(&aconf
->origin
.addr
, aconf
->origin_name
)) {
273 Debug((DEBUG_ERROR
, "Origin name error: (%s) (%s)",
274 aconf
->origin_name
, aconf
->name
));
277 * Do name lookup now on hostnames given and store the
278 * ip numbers in conf structure.
280 if (IsIP6Char(*aconf
->host
)) {
281 if (!ircd_aton(&aconf
->address
.addr
, aconf
->host
)) {
282 Debug((DEBUG_ERROR
, "Host/server name error: (%s) (%s)",
283 aconf
->host
, aconf
->name
));
287 conf_dns_lookup(aconf
);
290 /** Find a server by name or hostname.
291 * @param name Server name to find.
292 * @return Pointer to the corresponding ConfItem, or NULL if none exists.
294 struct ConfItem
* conf_find_server(const char* name
)
296 struct ConfItem
* conf
;
299 for (conf
= GlobalConfList
; conf
; conf
= conf
->next
) {
300 if (CONF_SERVER
== conf
->status
) {
302 * Check first servernames, then try hostnames.
303 * XXX - match returns 0 if there _is_ a match... guess they
304 * haven't decided what true is yet
306 if (0 == match(name
, conf
->name
))
313 /** Evaluate connection rules.
314 * @param name Name of server to check
315 * @param mask Filter for CRule types (only consider if type & \a mask != 0).
316 * @return Name of rule that forbids the connection; NULL if no prohibitions.
318 const char* conf_eval_crule(const char* name
, int mask
)
320 struct CRuleConf
* p
= cruleConfList
;
323 for ( ; p
; p
= p
->next
) {
324 if (0 != (p
->type
& mask
) && 0 == match(p
->hostmask
, name
)) {
325 if (crule_eval(p
->node
))
332 /** Remove all conf entries from the client except those which match
333 * the status field mask.
334 * @param cptr Client to operate on.
335 * @param mask ConfItem types to keep.
337 void det_confs_butmask(struct Client
* cptr
, int mask
)
343 for (link
= cli_confs(cptr
); link
; link
= next
) {
345 if ((link
->value
.aconf
->status
& mask
) == 0)
346 detach_conf(cptr
, link
->value
.aconf
);
350 /** Find the first (best) Client block to attach.
351 * @param cptr Client for whom to check rules.
352 * @return Authorization check result.
354 enum AuthorizationCheckResult
attach_iline(struct Client
* cptr
)
356 struct ConfItem
* aconf
;
360 for (aconf
= GlobalConfList
; aconf
; aconf
= aconf
->next
) {
361 if (aconf
->status
!= CONF_CLIENT
)
363 /* If you change any of this logic, please make corresponding
364 * changes in conf_debug_iline() below.
366 if (aconf
->address
.port
&& aconf
->address
.port
!= cli_listener(cptr
)->addr
.port
)
368 if (aconf
->username
&& match(aconf
->username
, cli_username(cptr
)))
370 if (aconf
->host
&& match(aconf
->host
, cli_sockhost(cptr
)))
372 if ((aconf
->addrbits
>= 0)
373 && !ipmask_check(&cli_ip(cptr
), &aconf
->address
.addr
, aconf
->addrbits
))
375 if (IPcheck_nr(cptr
) > aconf
->maximum
)
376 return ACR_TOO_MANY_FROM_IP
;
378 SetFlag(cptr
, FLAG_DOID
);
379 return attach_conf(cptr
, aconf
);
381 return ACR_NO_AUTHORIZATION
;
384 /** Interpret \a client as a client specifier and show which Client
385 * block(s) match that client.
387 * The client specifier may contain an IP address, hostname, listener
388 * port, or a combination of those separated by commas. IP addresses
389 * and hostnamese may be preceded by "username@"; the last given
390 * username will be used for the match.
392 * @param[in] client Client specifier.
393 * @return Matching Client block structure.
395 struct ConfItem
*conf_debug_iline(const char *client
)
397 struct irc_in_addr address
;
398 struct ConfItem
*aconf
;
399 struct DenyConf
*deny
;
401 unsigned short listener
;
402 char username
[USERLEN
+1], hostname
[HOSTLEN
+1], realname
[REALLEN
+1];
404 /* Initialize variables. */
406 memset(&address
, 0, sizeof(address
));
407 memset(&username
, 0, sizeof(username
));
408 memset(&hostname
, 0, sizeof(hostname
));
409 memset(&realname
, 0, sizeof(realname
));
411 /* Parse client specifier. */
413 struct irc_in_addr tmpaddr
;
416 /* Try to parse as listener port number first. */
417 tmp
= strtol(client
, &sep
, 10);
418 if (tmp
&& (*sep
== '\0' || *sep
== ',')) {
420 client
= sep
+ (*sep
!= '\0');
424 /* Maybe username@ before an IP address or hostname? */
425 tmp
= strcspn(client
, ",@");
426 if (client
[tmp
] == '@') {
429 ircd_strncpy(username
, client
, tmp
);
430 /* and fall through */
434 /* Looks like an IP address? */
435 tmp
= ircd_aton(&tmpaddr
, client
);
436 if (tmp
&& (client
[tmp
] == '\0' || client
[tmp
] == ',')) {
437 memcpy(&address
, &tmpaddr
, sizeof(address
));
438 client
+= tmp
+ (client
[tmp
] != '\0');
443 if (client
[0] == '$' && client
[1] == 'R') {
445 for (tmp
= 0; *client
!= '\0' && *client
!= ',' && tmp
< REALLEN
; ++client
, ++tmp
) {
447 realname
[tmp
] = *++client
;
449 realname
[tmp
] = *client
;
454 /* Else must be a hostname. */
455 tmp
= strcspn(client
, ",");
458 ircd_strncpy(hostname
, client
, tmp
);
459 client
+= tmp
+ (client
[tmp
] != '\0');
462 /* Walk configuration to find matching Client block. */
463 for (aconf
= GlobalConfList
; aconf
; aconf
= aconf
->next
) {
464 if (aconf
->status
!= CONF_CLIENT
)
466 if (aconf
->address
.port
&& aconf
->address
.port
!= listener
) {
467 fprintf(stdout
, "Listener port mismatch: %u != %u\n", aconf
->address
.port
, listener
);
470 if (aconf
->username
&& match(aconf
->username
, username
)) {
471 fprintf(stdout
, "Username mismatch: %s != %s\n", aconf
->username
, username
);
474 if (aconf
->host
&& match(aconf
->host
, hostname
)) {
475 fprintf(stdout
, "Hostname mismatch: %s != %s\n", aconf
->host
, hostname
);
478 if ((aconf
->addrbits
>= 0)
479 && !ipmask_check(&address
, &aconf
->address
.addr
, aconf
->addrbits
)) {
480 fprintf(stdout
, "IP address mismatch: %s != %s\n", aconf
->name
, ircd_ntoa(&address
));
483 fprintf(stdout
, "Match! username=%s host=%s ip=%s class=%s maxlinks=%u password=%s\n",
484 (aconf
->username
? aconf
->username
: "(null)"),
485 (aconf
->host
? aconf
->host
: "(null)"),
486 (aconf
->name
? aconf
->name
: "(null)"),
487 ConfClass(aconf
), aconf
->maximum
, aconf
->passwd
);
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 && (tmp
->clients
>= MaxLinks(tmp
->conn_class
)))
667 /** Find a ConfItem from a list that has a name that matches \a name.
668 * @param lp List to search in.
669 * @param name Filter for ConfItem::name field; matches either exactly
671 * @param statmask Filter for ConfItem::status.
672 * @return First matching ConfItem from \a lp.
674 struct ConfItem
* find_conf_byname(struct SLink
* lp
, const char* name
,
677 struct ConfItem
* tmp
;
680 if (HOSTLEN
< strlen(name
))
683 for (; lp
; lp
= lp
->next
) {
684 tmp
= lp
->value
.aconf
;
685 if (0 != (tmp
->status
& statmask
)) {
686 assert(0 != tmp
->name
);
687 if (0 == ircd_strcmp(tmp
->name
, name
) || 0 == match(tmp
->name
, name
))
694 /** Find a ConfItem from a list that has a host that matches \a host.
695 * @param lp List to search in.
696 * @param host Filter for ConfItem::host field; matches as a glob.
697 * @param statmask Filter for ConfItem::status.
698 * @return First matching ConfItem from \a lp.
700 struct ConfItem
* find_conf_byhost(struct SLink
* lp
, const char* host
,
703 struct ConfItem
* tmp
= NULL
;
706 if (HOSTLEN
< strlen(host
))
709 for (; lp
; lp
= lp
->next
) {
710 tmp
= lp
->value
.aconf
;
711 if (0 != (tmp
->status
& statmask
)) {
712 assert(0 != tmp
->host
);
713 if (0 == match(tmp
->host
, host
))
720 /** Find a ConfItem from a list that has an address equal to \a ip.
721 * @param lp List to search in.
722 * @param ip Filter for ConfItem::address field; matches exactly.
723 * @param statmask Filter for ConfItem::status.
724 * @return First matching ConfItem from \a lp.
726 struct ConfItem
* find_conf_byip(struct SLink
* lp
, const struct irc_in_addr
* ip
,
729 struct ConfItem
* tmp
;
731 for (; lp
; lp
= lp
->next
) {
732 tmp
= lp
->value
.aconf
;
733 if (0 != (tmp
->status
& statmask
)
734 && !irc_in_addr_cmp(&tmp
->address
.addr
, ip
))
740 /** Free all CRules from #cruleConfList. */
741 void conf_erase_crule_list(void)
743 struct CRuleConf
* next
;
744 struct CRuleConf
* p
= cruleConfList
;
746 for ( ; p
; p
= next
) {
748 crule_free(&p
->node
);
756 /** Return #cruleConfList.
757 * @return #cruleConfList
759 const struct CRuleConf
* conf_get_crule_list(void)
761 return cruleConfList
;
764 /** Free all deny rules from #denyConfList. */
765 void conf_erase_deny_list(void)
767 struct DenyConf
* next
;
768 struct DenyConf
* p
= denyConfList
;
769 for ( ; p
; p
= next
) {
780 /** Return #denyConfList.
781 * @return #denyConfList
783 const struct DenyConf
* conf_get_deny_list(void)
788 /** Find any existing quarantine for the named channel.
789 * @param chname Channel name to search for.
790 * @return Reason for channel's quarantine, or NULL if none exists.
793 find_quarantine(const char *chname
)
797 for (qline
= GlobalQuarantineList
; qline
; qline
= qline
->next
)
798 if (!ircd_strcmp(qline
->chname
, chname
))
799 return qline
->reason
;
803 /** Free all qline structs from #GlobalQuarantineList. */
804 void clear_quarantines(void)
807 while ((qline
= GlobalQuarantineList
))
809 GlobalQuarantineList
= qline
->next
;
810 MyFree(qline
->reason
);
811 MyFree(qline
->chname
);
816 /** When non-zero, indicates that a configuration error has been seen in this pass. */
817 static int conf_error
;
818 /** When non-zero, indicates that the configuration file was loaded at least once. */
819 static int conf_already_read
;
821 extern void yyparse(void);
822 extern void init_lexer(void);
824 /** Read configuration file.
825 * @return Zero on failure, non-zero on success. */
826 int read_configuration_file(void)
829 feature_unmark(); /* unmark all features for resetting later */
830 /* Now just open an fd. The buffering isn't really needed... */
835 feature_mark(); /* reset unmarked features */
836 conf_already_read
= 1;
840 /** Report an error message about the configuration file.
841 * @param msg The error to report.
844 yyerror(const char *msg
)
846 sendto_opmask_butone(0, SNO_ALL
, "Config file parse error line %d: %s",
848 log_write(LS_CONFIG
, L_ERROR
, 0, "Config file parse error line %d: %s",
850 if (!conf_already_read
)
851 fprintf(stderr
, "Config file parse error line %d: %s\n", lineno
, msg
);
855 /** Attach CONF_UWORLD items to a server and everything attached to it. */
857 attach_conf_uworld(struct Client
*cptr
)
861 attach_confs_byhost(cptr
, cli_name(cptr
), CONF_UWORLD
);
862 for (lp
= cli_serv(cptr
)->down
; lp
; lp
= lp
->next
)
863 attach_conf_uworld(lp
->value
.cptr
);
866 /** Free all memory associated with service mapping \a smap.
867 * @param smap[in] The mapping to free.
869 void free_mapping(struct s_map
*smap
)
871 struct nick_host
*nh
, *next
;
872 for (nh
= smap
->services
; nh
; nh
= next
)
878 MyFree(smap
->command
);
879 MyFree(smap
->prepend
);
883 /** Unregister and free all current service mappings. */
884 static void close_mappings(void)
886 struct s_map
*map
, *next
;
888 for (map
= GlobalServiceMapList
; map
; map
= next
) {
890 unregister_mapping(map
);
893 GlobalServiceMapList
= NULL
;
896 /** Reload the configuration file.
897 * @param cptr Client that requested rehash (if a signal, &me).
898 * @param sig Type of rehash (0 = oper-requested, 1 = signal, 2 =
899 * oper-requested but do not restart resolver)
900 * @return CPTR_KILLED if any client was K/G-lined because of the
901 * rehash; otherwise 0.
903 int rehash(struct Client
*cptr
, int sig
)
905 struct ConfItem
** tmp
= &GlobalConfList
;
906 struct ConfItem
* tmp2
;
907 struct Client
* acptr
;
913 sendto_opmask_butone(0, SNO_OLDSNO
,
914 "Got signal SIGHUP, reloading ircd conf. file");
916 while ((tmp2
= *tmp
)) {
919 * Configuration entry is still in use by some
920 * local clients, cannot delete it--mark it so
921 * that it will be deleted when the last client
924 if (CONF_CLIENT
== (tmp2
->status
& CONF_CLIENT
))
930 tmp2
->status
|= CONF_ILLEGAL
;
937 conf_erase_crule_list();
938 conf_erase_deny_list();
942 * delete the juped nicks list
953 mark_listeners_closing();
954 iauth_mark_closing();
957 read_configuration_file();
959 log_reopen(); /* reopen log files */
961 iauth_close_unused();
963 class_delete_marked(); /* unless it fails */
966 * Flush out deleted I and P lines although still in use.
968 for (tmp
= &GlobalConfList
; (tmp2
= *tmp
);) {
969 if (CONF_ILLEGAL
== (tmp2
->status
& CONF_ILLEGAL
)) {
979 for (i
= 0; i
<= HighestFd
; i
++) {
980 if ((acptr
= LocalClientArray
[i
])) {
981 assert(!IsMe(acptr
));
983 det_confs_butmask(acptr
, ~(CONF_UWORLD
| CONF_ILLEGAL
));
984 /* Because admin's are getting so uppity about people managing to
985 * get past K/G's etc, we'll "fix" the bug by actually explaining
988 if ((found_g
= find_kill(acptr
, 0))) {
989 sendto_opmask_butone(0, found_g
== -2 ? SNO_GLINE
: SNO_OPERKILL
,
990 found_g
== -2 ? "G-line active for %s%s" :
991 "K-line active for %s%s",
992 IsUnknown(acptr
) ? "Unregistered Client ":"",
993 get_client_name(acptr
, SHOW_IP
));
994 if (exit_client(cptr
, acptr
, &me
, found_g
== -2 ? "G-lined" :
995 "K-lined") == CPTR_KILLED
)
1001 attach_conf_uworld(&me
);
1006 /** Read configuration file for the very first time.
1007 * @return Non-zero on success, zero on failure.
1012 if (read_configuration_file()) {
1014 * make sure we're sane to start if the config
1015 * file read didn't get everything we need.
1016 * XXX - should any of these abort the server?
1017 * TODO: add warning messages
1019 if (0 == localConf
.name
|| 0 == localConf
.numeric
)
1024 if (0 == localConf
.location1
)
1025 DupString(localConf
.location1
, "");
1026 if (0 == localConf
.location2
)
1027 DupString(localConf
.location2
, "");
1028 if (0 == localConf
.contact
)
1029 DupString(localConf
.contact
, "");
1036 /** Searches for a K/G-line for a client. If one is found, notify the
1037 * user and disconnect them.
1038 * @param cptr Client to search for.
1039 * @param glinecheck Whether we check for glines.
1040 * @return 0 if client is accepted; -1 if client was locally denied
1041 * (K-line); -2 if client was globally denied (G-line).
1043 int find_kill(struct Client
*cptr
, int glinecheck
)
1047 const char* realname
;
1048 struct DenyConf
* deny
;
1049 struct Gline
* agline
= NULL
;
1053 if (!cli_user(cptr
))
1056 host
= cli_sockhost(cptr
);
1057 name
= cli_user(cptr
)->username
;
1058 realname
= cli_info(cptr
);
1060 assert(strlen(host
) <= HOSTLEN
);
1061 assert((name
? strlen(name
) : 0) <= HOSTLEN
);
1062 assert((realname
? strlen(realname
) : 0) <= REALLEN
);
1064 /* 2000-07-14: Rewrote this loop for massive speed increases.
1067 for (deny
= denyConfList
; deny
; deny
= deny
->next
) {
1068 if (deny
->usermask
&& match(deny
->usermask
, name
))
1070 if (deny
->realmask
&& match(deny
->realmask
, realname
))
1072 if (deny
->bits
> 0) {
1073 if (!ipmask_check(&cli_ip(cptr
), &deny
->address
, deny
->bits
))
1075 } else if (deny
->hostmask
&& match(deny
->hostmask
, host
))
1078 if (EmptyString(deny
->message
))
1079 send_reply(cptr
, SND_EXPLICIT
| ERR_YOUREBANNEDCREEP
,
1080 ":Connection from your host is refused on this server.");
1082 if (deny
->flags
& DENY_FLAGS_FILE
)
1083 killcomment(cptr
, deny
->message
);
1085 send_reply(cptr
, SND_EXPLICIT
| ERR_YOUREBANNEDCREEP
, ":%s.", deny
->message
);
1090 /* added glinecheck to define if we check for glines too, shouldn't happen
1091 * when rehashing as it is causing problems with big servers and lots of glines.
1092 * Think of a 18000 user leaf with 18000 glines present, this will probably
1093 * cause the server to split from the net.
1096 if (glinecheck
&& (agline
= gline_lookup(cptr
, 0)) && GlineIsActive(agline
)) {
1098 * find active glines
1099 * added a check against the user's IP address to find_gline() -Kev
1101 send_reply(cptr
, SND_EXPLICIT
| ERR_YOUREBANNEDCREEP
, ":%s.", GlineReason(agline
));
1108 /** Attempt to attach Client blocks to \a cptr. If attach_iline()
1109 * fails for the client, emit a debugging message.
1110 * @param cptr Client to check for access.
1111 * @return Access check result.
1113 enum AuthorizationCheckResult
conf_check_client(struct Client
*cptr
)
1115 enum AuthorizationCheckResult acr
= ACR_OK
;
1117 if ((acr
= attach_iline(cptr
))) {
1118 Debug((DEBUG_DNS
, "ch_cl: access denied: %s[%s]",
1119 cli_name(cptr
), cli_sockhost(cptr
)));
1125 /** Check access for a server given its name (passed in cptr struct).
1126 * Must check for all C/N lines which have a name which matches the
1127 * name given and a host which matches. A host alias which is the
1128 * same as the server name is also acceptable in the host field of a
1130 * @param cptr Peer server to check.
1131 * @return 0 if accepted, -1 if access denied.
1133 int conf_check_server(struct Client
*cptr
)
1135 struct ConfItem
* c_conf
= NULL
;
1138 Debug((DEBUG_DNS
, "sv_cl: check access for %s[%s]",
1139 cli_name(cptr
), cli_sockhost(cptr
)));
1141 if (IsUnknown(cptr
) && !attach_confs_byname(cptr
, cli_name(cptr
), CONF_SERVER
)) {
1142 Debug((DEBUG_DNS
, "No C/N lines for %s", cli_sockhost(cptr
)));
1145 lp
= cli_confs(cptr
);
1147 * We initiated this connection so the client should have a C and N
1148 * line already attached after passing through the connect_server()
1151 if (IsConnecting(cptr
) || IsHandshake(cptr
)) {
1152 c_conf
= find_conf_byname(lp
, cli_name(cptr
), CONF_SERVER
);
1154 sendto_opmask_butone(0, SNO_OLDSNO
,
1155 "Connect Error: lost Connect block for %s",
1157 det_confs_butmask(cptr
, 0);
1162 /* Try finding the Connect block by DNS name and IP next. */
1163 if (!c_conf
&& !(c_conf
= find_conf_byhost(lp
, cli_sockhost(cptr
), CONF_SERVER
)))
1164 c_conf
= find_conf_byip(lp
, &cli_ip(cptr
), CONF_SERVER
);
1167 * Attach by IP# only if all other checks have failed.
1168 * It is quite possible to get here with the strange things that can
1169 * happen when using DNS in the way the irc server does. -avalon
1172 c_conf
= find_conf_byip(lp
, &cli_ip(cptr
), CONF_SERVER
);
1174 * detach all conf lines that got attached by attach_confs()
1176 det_confs_butmask(cptr
, 0);
1178 * if no Connect block, then deny access
1181 Debug((DEBUG_DNS
, "sv_cl: access denied: %s[%s@%s]",
1182 cli_name(cptr
), cli_username(cptr
), cli_sockhost(cptr
)));
1186 * attach the Connect block to the client structure for later use.
1188 attach_conf(cptr
, c_conf
);
1190 if (!irc_in_addr_valid(&c_conf
->address
.addr
))
1191 memcpy(&c_conf
->address
.addr
, &cli_ip(cptr
), sizeof(c_conf
->address
.addr
));
1193 Debug((DEBUG_DNS
, "sv_cl: access ok: %s[%s]",
1194 cli_name(cptr
), cli_sockhost(cptr
)));
1198 void clear_slines(void)
1200 struct sline
*sline
;
1201 while ((sline
= GlobalSList
)) {
1202 GlobalSList
= sline
->next
;
1203 MyFree(sline
->spoofhost
);
1204 if (!EmptyString(sline
->passwd
))
1205 MyFree(sline
->passwd
);
1206 if (!EmptyString(sline
->realhost
))
1207 MyFree(sline
->realhost
);
1208 if (!EmptyString(sline
->username
))
1209 MyFree(sline
->username
);
1215 * conf_check_slines()
1217 * Check S lines for the specified client, passed in cptr struct.
1218 * If the client's IP is S-lined, process the substitution here.
1224 * 0 = No S-line found
1225 * 1 = S-line found and substitution done.
1233 conf_check_slines(struct Client
*cptr
)
1235 struct sline
*sconf
;
1238 for (sconf
= GlobalSList
; sconf
; sconf
= sconf
->next
) {
1239 if (sconf
->flags
== SLINE_FLAGS_IP
) {
1240 if (!ipmask_check(&(cli_ip(cptr
)), &(sconf
->address
), sconf
->bits
))
1242 } else if (sconf
->flags
== SLINE_FLAGS_HOSTNAME
) {
1243 if ((match(sconf
->realhost
, cli_sockhost(cptr
)) != 0) &&
1244 (match(sconf
->realhost
, cli_sock_ip(cptr
)) != 0)) /* wildcarded IP address */
1250 if (match(sconf
->username
, cli_user(cptr
)->username
) == 0) {
1251 /* Ignore user part if u@h. */
1252 if ((hostonly
= strchr(sconf
->spoofhost
, '@')))
1255 hostonly
= sconf
->spoofhost
;
1260 ircd_strncpy(cli_user(cptr
)->host
, hostonly
, HOSTLEN
);
1261 log_write(LS_USER
, L_INFO
, LOG_NOSNOTICE
, "S-Line (%s@%s) by (%#R)",
1262 cli_user(cptr
)->username
, hostonly
, cptr
);
1269 void free_spoofhost(struct sline
*spoof
) {
1270 MyFree(spoof
->spoofhost
);
1271 MyFree(spoof
->passwd
);
1272 MyFree(spoof
->realhost
);
1273 MyFree(spoof
->username
);