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.4 2007/02/25 15:41:49 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
;
78 /** Current line number in scanner input. */
81 /** Configuration information for #me. */
82 struct LocalConf localConf
;
83 /** Global list of connection rules. */
84 struct CRuleConf
* cruleConfList
;
85 /** Global list of K-lines. */
86 struct DenyConf
* denyConfList
;
88 /** Tell a user that they are banned, dumping the message from a file.
89 * @param sptr Client being rejected
90 * @param filename Send this file's contents to \a sptr
92 static void killcomment(struct Client
* sptr
, const char* filename
)
99 if (NULL
== (file
= fbopen(filename
, "r"))) {
100 send_reply(sptr
, ERR_NOMOTD
);
101 send_reply(sptr
, SND_EXPLICIT
| ERR_YOUREBANNEDCREEP
,
102 ":Connection from your host is refused on this server.");
106 tm
= localtime((time_t*) &sb
.st_mtime
); /* NetBSD needs cast */
107 while (fbgets(line
, sizeof(line
) - 1, file
)) {
108 char* end
= line
+ strlen(line
);
111 if ('\n' == *end
|| '\r' == *end
)
116 send_reply(sptr
, RPL_MOTD
, line
);
118 send_reply(sptr
, SND_EXPLICIT
| ERR_YOUREBANNEDCREEP
,
119 ":Connection from your host is refused on this server.");
123 /** Allocate a new struct ConfItem and link it to #GlobalConfList.
124 * @return Newly allocated structure.
126 struct ConfItem
* make_conf(int type
)
128 struct ConfItem
* aconf
;
130 aconf
= (struct ConfItem
*) MyMalloc(sizeof(struct ConfItem
));
133 memset(aconf
, 0, sizeof(struct ConfItem
));
134 aconf
->status
= type
;
135 aconf
->next
= GlobalConfList
;
136 GlobalConfList
= aconf
;
140 /** Free a struct ConfItem and any resources it owns.
141 * @param aconf Item to free.
143 void free_conf(struct ConfItem
*aconf
)
145 Debug((DEBUG_DEBUG
, "free_conf: %s %s %d",
146 aconf
->host
? aconf
->host
: "*",
147 aconf
->name
? aconf
->name
: "*",
148 aconf
->address
.port
));
149 if (aconf
->dns_pending
)
150 delete_resolver_queries(aconf
);
151 MyFree(aconf
->username
);
153 MyFree(aconf
->origin_name
);
155 memset(aconf
->passwd
, 0, strlen(aconf
->passwd
));
156 MyFree(aconf
->passwd
);
158 MyFree(aconf
->hub_limit
);
163 /** Disassociate configuration from the client.
164 * @param cptr Client to operate on.
165 * @param aconf ConfItem to detach.
167 static void detach_conf(struct Client
* cptr
, struct ConfItem
* aconf
)
174 assert(0 < aconf
->clients
);
176 lp
= &(cli_confs(cptr
));
179 if ((*lp
)->value
.aconf
== aconf
) {
180 if (aconf
->conn_class
&& (aconf
->status
& CONF_CLIENT_MASK
) && ConfLinks(aconf
) > 0)
183 assert(0 < aconf
->clients
);
184 if (0 == --aconf
->clients
&& IsIllegal(aconf
))
195 /** Parse a user\@host mask into username and host or IP parts.
196 * If \a host contains no username part, set \a aconf->username to
197 * NULL. If the host part of \a host looks like an IP mask, set \a
198 * aconf->addrbits and \a aconf->address to match. Otherwise, set
199 * \a aconf->host, and set \a aconf->addrbits to -1.
200 * @param[in,out] aconf Configuration item to set.
201 * @param[in] host user\@host mask to parse.
203 void conf_parse_userhost(struct ConfItem
*aconf
, char *host
)
206 unsigned char addrbits
;
208 MyFree(aconf
->username
);
210 host_part
= strchr(host
, '@');
213 DupString(aconf
->username
, host
);
216 aconf
->username
= NULL
;
219 DupString(aconf
->host
, host_part
);
220 if (ipmask_parse(aconf
->host
, &aconf
->address
.addr
, &addrbits
))
221 aconf
->addrbits
= addrbits
;
223 aconf
->addrbits
= -1;
227 /** Copies a completed DNS query into its ConfItem.
228 * @param vptr Pointer to struct ConfItem for the block.
229 * @param hp DNS reply, or NULL if the lookup failed.
231 static void conf_dns_callback(void* vptr
, const struct irc_in_addr
*addr
, const char *h_name
)
233 struct ConfItem
* aconf
= (struct ConfItem
*) vptr
;
235 aconf
->dns_pending
= 0;
237 memcpy(&aconf
->address
.addr
, addr
, sizeof(aconf
->address
.addr
));
240 /** Start a nameserver lookup of the conf host. If the conf entry is
241 * currently doing a lookup, do nothing.
242 * @param aconf ConfItem for which to start a request.
244 static void conf_dns_lookup(struct ConfItem
* aconf
)
246 if (!aconf
->dns_pending
) {
247 char buf
[HOSTLEN
+ 1];
249 host_from_uh(buf
, aconf
->host
, HOSTLEN
);
250 gethost_byname(buf
, conf_dns_callback
, aconf
);
251 aconf
->dns_pending
= 1;
256 /** Start lookups of all addresses in the conf line. The origin must
257 * be a numeric IP address. If the remote host field is not an IP
258 * address, start a DNS lookup for it.
259 * @param aconf Connection to do lookups for.
262 lookup_confhost(struct ConfItem
*aconf
)
264 if (EmptyString(aconf
->host
) || EmptyString(aconf
->name
)) {
265 Debug((DEBUG_ERROR
, "Host/server name error: (%s) (%s)",
266 aconf
->host
, aconf
->name
));
269 if (aconf
->origin_name
270 && !ircd_aton(&aconf
->origin
.addr
, aconf
->origin_name
)) {
271 Debug((DEBUG_ERROR
, "Origin name error: (%s) (%s)",
272 aconf
->origin_name
, aconf
->name
));
275 * Do name lookup now on hostnames given and store the
276 * ip numbers in conf structure.
278 if (IsIP6Char(*aconf
->host
)) {
279 if (!ircd_aton(&aconf
->address
.addr
, aconf
->host
)) {
280 Debug((DEBUG_ERROR
, "Host/server name error: (%s) (%s)",
281 aconf
->host
, aconf
->name
));
285 conf_dns_lookup(aconf
);
288 /** Find a server by name or hostname.
289 * @param name Server name to find.
290 * @return Pointer to the corresponding ConfItem, or NULL if none exists.
292 struct ConfItem
* conf_find_server(const char* name
)
294 struct ConfItem
* conf
;
297 for (conf
= GlobalConfList
; conf
; conf
= conf
->next
) {
298 if (CONF_SERVER
== conf
->status
) {
300 * Check first servernames, then try hostnames.
301 * XXX - match returns 0 if there _is_ a match... guess they
302 * haven't decided what true is yet
304 if (0 == match(name
, conf
->name
))
311 /** Evaluate connection rules.
312 * @param name Name of server to check
313 * @param mask Filter for CRule types (only consider if type & \a mask != 0).
314 * @return Name of rule that forbids the connection; NULL if no prohibitions.
316 const char* conf_eval_crule(const char* name
, int mask
)
318 struct CRuleConf
* p
= cruleConfList
;
321 for ( ; p
; p
= p
->next
) {
322 if (0 != (p
->type
& mask
) && 0 == match(p
->hostmask
, name
)) {
323 if (crule_eval(p
->node
))
330 /** Remove all conf entries from the client except those which match
331 * the status field mask.
332 * @param cptr Client to operate on.
333 * @param mask ConfItem types to keep.
335 void det_confs_butmask(struct Client
* cptr
, int mask
)
341 for (link
= cli_confs(cptr
); link
; link
= next
) {
343 if ((link
->value
.aconf
->status
& mask
) == 0)
344 detach_conf(cptr
, link
->value
.aconf
);
348 /** Find the first (best) Client block to attach.
349 * @param cptr Client for whom to check rules.
350 * @return Authorization check result.
352 enum AuthorizationCheckResult
attach_iline(struct Client
* cptr
)
354 struct ConfItem
* aconf
;
358 for (aconf
= GlobalConfList
; aconf
; aconf
= aconf
->next
) {
359 if (aconf
->status
!= CONF_CLIENT
)
361 /* If you change any of this logic, please make corresponding
362 * changes in conf_debug_iline() below.
364 if (aconf
->address
.port
&& aconf
->address
.port
!= cli_listener(cptr
)->addr
.port
)
366 if (aconf
->username
&& match(aconf
->username
, cli_username(cptr
)))
368 if (aconf
->host
&& match(aconf
->host
, cli_sockhost(cptr
)))
370 if ((aconf
->addrbits
>= 0)
371 && !ipmask_check(&cli_ip(cptr
), &aconf
->address
.addr
, aconf
->addrbits
))
373 if (IPcheck_nr(cptr
) > aconf
->maximum
)
374 return ACR_TOO_MANY_FROM_IP
;
376 SetFlag(cptr
, FLAG_DOID
);
377 return attach_conf(cptr
, aconf
);
379 return ACR_NO_AUTHORIZATION
;
382 /** Interpret \a client as a client specifier and show which Client
383 * block(s) match that client.
385 * The client specifier may contain an IP address, hostname, listener
386 * port, or a combination of those separated by commas. IP addresses
387 * and hostnamese may be preceded by "username@"; the last given
388 * username will be used for the match.
390 * @param[in] client Client specifier.
391 * @return Matching Client block structure.
393 struct ConfItem
*conf_debug_iline(const char *client
)
395 struct irc_in_addr address
;
396 struct ConfItem
*aconf
;
397 struct DenyConf
*deny
;
399 unsigned short listener
;
400 char username
[USERLEN
+1], hostname
[HOSTLEN
+1], realname
[REALLEN
+1];
402 /* Initialize variables. */
404 memset(&address
, 0, sizeof(address
));
405 memset(&username
, 0, sizeof(username
));
406 memset(&hostname
, 0, sizeof(hostname
));
407 memset(&realname
, 0, sizeof(realname
));
409 /* Parse client specifier. */
411 struct irc_in_addr tmpaddr
;
414 /* Try to parse as listener port number first. */
415 tmp
= strtol(client
, &sep
, 10);
416 if (tmp
&& (*sep
== '\0' || *sep
== ',')) {
418 client
= sep
+ (*sep
!= '\0');
422 /* Maybe username@ before an IP address or hostname? */
423 tmp
= strcspn(client
, ",@");
424 if (client
[tmp
] == '@') {
427 ircd_strncpy(username
, client
, tmp
);
428 /* and fall through */
432 /* Looks like an IP address? */
433 tmp
= ircd_aton(&tmpaddr
, client
);
434 if (tmp
&& (client
[tmp
] == '\0' || client
[tmp
] == ',')) {
435 memcpy(&address
, &tmpaddr
, sizeof(address
));
436 client
+= tmp
+ (client
[tmp
] != '\0');
441 if (client
[0] == '$' && client
[1] == 'R') {
443 for (tmp
= 0; *client
!= '\0' && *client
!= ',' && tmp
< REALLEN
; ++client
, ++tmp
) {
445 realname
[tmp
] = *++client
;
447 realname
[tmp
] = *client
;
452 /* Else must be a hostname. */
453 tmp
= strcspn(client
, ",");
456 ircd_strncpy(hostname
, client
, tmp
);
457 client
+= tmp
+ (client
[tmp
] != '\0');
460 /* Walk configuration to find matching Client block. */
461 for (aconf
= GlobalConfList
; aconf
; aconf
= aconf
->next
) {
462 if (aconf
->status
!= CONF_CLIENT
)
464 if (aconf
->address
.port
&& aconf
->address
.port
!= listener
) {
465 fprintf(stdout
, "Listener port mismatch: %u != %u\n", aconf
->address
.port
, listener
);
468 if (aconf
->username
&& match(aconf
->username
, username
)) {
469 fprintf(stdout
, "Username mismatch: %s != %s\n", aconf
->username
, username
);
472 if (aconf
->host
&& match(aconf
->host
, hostname
)) {
473 fprintf(stdout
, "Hostname mismatch: %s != %s\n", aconf
->host
, hostname
);
476 if ((aconf
->addrbits
>= 0)
477 && !ipmask_check(&address
, &aconf
->address
.addr
, aconf
->addrbits
)) {
478 fprintf(stdout
, "IP address mismatch: %s != %s\n", aconf
->name
, ircd_ntoa(&address
));
481 fprintf(stdout
, "Match! username=%s host=%s ip=%s class=%s maxlinks=%u password=%s\n",
482 (aconf
->username
? aconf
->username
: "(null)"),
483 (aconf
->host
? aconf
->host
: "(null)"),
484 (aconf
->name
? aconf
->name
: "(null)"),
485 ConfClass(aconf
), aconf
->maximum
,
486 (aconf
->passwd
? aconf
->passwd
: "(null)"));
490 /* If no authorization, say so and exit. */
493 fprintf(stdout
, "No authorization found.\n");
497 /* Look for a Kill block with the user's name on it. */
498 for (deny
= denyConfList
; deny
; deny
= deny
->next
) {
499 if (deny
->usermask
&& match(deny
->usermask
, username
))
501 if (deny
->realmask
&& match(deny
->realmask
, realname
))
503 if (deny
->bits
> 0) {
504 if (!ipmask_check(&address
, &deny
->address
, deny
->bits
))
506 } else if (deny
->hostmask
&& match(deny
->hostmask
, hostname
))
509 /* Looks like a match; report it. */
510 fprintf(stdout
, "Denied! usermask=%s realmask=\"%s\" hostmask=%s (bits=%u)\n",
511 deny
->usermask
? deny
->usermask
: "(null)",
512 deny
->realmask
? deny
->realmask
: "(null)",
513 deny
->hostmask
? deny
->hostmask
: "(null)",
520 /** Check whether a particular ConfItem is already attached to a
522 * @param aconf ConfItem to search for
523 * @param cptr Client to check
524 * @return Non-zero if \a aconf is attached to \a cptr, zero if not.
526 static int is_attached(struct ConfItem
*aconf
, struct Client
*cptr
)
530 for (lp
= cli_confs(cptr
); lp
; lp
= lp
->next
) {
531 if (lp
->value
.aconf
== aconf
)
537 /** Associate a specific configuration entry to a *local* client (this
538 * is the one which used in accepting the connection). Note, that this
539 * automatically changes the attachment if there was an old one...
540 * @param cptr Client to attach \a aconf to
541 * @param aconf ConfItem to attach
542 * @return Authorization check result.
544 enum AuthorizationCheckResult
attach_conf(struct Client
*cptr
, struct ConfItem
*aconf
)
548 if (is_attached(aconf
, cptr
))
549 return ACR_ALREADY_AUTHORIZED
;
550 if (IsIllegal(aconf
))
551 return ACR_NO_AUTHORIZATION
;
552 if ((aconf
->status
& (CONF_OPERATOR
| CONF_CLIENT
)) &&
553 ConfLinks(aconf
) >= ConfMaxLinks(aconf
) && ConfMaxLinks(aconf
) > 0)
554 return ACR_TOO_MANY_IN_CLASS
; /* Use this for printing error message */
556 lp
->next
= cli_confs(cptr
);
557 lp
->value
.aconf
= aconf
;
558 cli_confs(cptr
) = lp
;
560 if (aconf
->status
& CONF_CLIENT_MASK
)
565 /** Return our LocalConf configuration structure.
566 * @return A pointer to #localConf.
568 const struct LocalConf
* conf_get_local(void)
573 /** Attach ConfItems to a client if the name passed matches that for
574 * the ConfItems or is an exact match for them.
575 * @param cptr Client getting the ConfItem attachments.
576 * @param name Filter to match ConfItem::name.
577 * @param statmask Filter to limit ConfItem::status.
578 * @return First ConfItem attached to \a cptr.
580 struct ConfItem
* attach_confs_byname(struct Client
* cptr
, const char* name
,
583 struct ConfItem
* tmp
;
584 struct ConfItem
* first
= NULL
;
588 if (HOSTLEN
< strlen(name
))
591 for (tmp
= GlobalConfList
; tmp
; tmp
= tmp
->next
) {
592 if (0 != (tmp
->status
& statmask
) && !IsIllegal(tmp
)) {
593 assert(0 != tmp
->name
);
594 if (0 == match(tmp
->name
, name
) || 0 == ircd_strcmp(tmp
->name
, name
)) {
595 if (ACR_OK
== attach_conf(cptr
, tmp
) && !first
)
603 /** Attach ConfItems to a client if the host passed matches that for
604 * the ConfItems or is an exact match for them.
605 * @param cptr Client getting the ConfItem attachments.
606 * @param host Filter to match ConfItem::host.
607 * @param statmask Filter to limit ConfItem::status.
608 * @return First ConfItem attached to \a cptr.
610 struct ConfItem
* attach_confs_byhost(struct Client
* cptr
, const char* host
,
613 struct ConfItem
* tmp
;
614 struct ConfItem
* first
= 0;
617 if (HOSTLEN
< strlen(host
))
620 for (tmp
= GlobalConfList
; tmp
; tmp
= tmp
->next
) {
621 if (0 != (tmp
->status
& statmask
) && !IsIllegal(tmp
)) {
622 assert(0 != tmp
->host
);
623 if (0 == match(tmp
->host
, host
) || 0 == ircd_strcmp(tmp
->host
, host
)) {
624 if (ACR_OK
== attach_conf(cptr
, tmp
) && !first
)
632 /** Find a ConfItem that has the same name and user+host fields as
633 * specified. Requires an exact match for \a name.
634 * @param name Name to match
635 * @param cptr Client to match against
636 * @param statmask Filter for ConfItem::status
637 * @return First found matching ConfItem.
639 struct ConfItem
* find_conf_exact(const char* name
, struct Client
*cptr
, int statmask
)
641 struct ConfItem
*tmp
;
643 for (tmp
= GlobalConfList
; tmp
; tmp
= tmp
->next
) {
644 if (!(tmp
->status
& statmask
) || !tmp
->name
|| !tmp
->host
||
645 0 != ircd_strcmp(tmp
->name
, name
))
648 && (EmptyString(cli_username(cptr
))
649 || match(tmp
->username
, cli_username(cptr
))))
651 if (tmp
->addrbits
< 0)
653 if (match(tmp
->host
, cli_sockhost(cptr
)))
656 else if (!ipmask_check(&cli_ip(cptr
), &tmp
->address
.addr
, tmp
->addrbits
))
658 if ((tmp
->status
& CONF_OPERATOR
)
659 && (tmp
->clients
>= MaxLinks(tmp
->conn_class
)))
666 /** Find a ConfItem from a list that has a name that matches \a name.
667 * @param lp List to search in.
668 * @param name Filter for ConfItem::name field; matches either exactly
670 * @param statmask Filter for ConfItem::status.
671 * @return First matching ConfItem from \a lp.
673 struct ConfItem
* find_conf_byname(struct SLink
* lp
, const char* name
,
676 struct ConfItem
* tmp
;
679 if (HOSTLEN
< strlen(name
))
682 for (; lp
; lp
= lp
->next
) {
683 tmp
= lp
->value
.aconf
;
684 if (0 != (tmp
->status
& statmask
)) {
685 assert(0 != tmp
->name
);
686 if (0 == ircd_strcmp(tmp
->name
, name
) || 0 == match(tmp
->name
, name
))
693 /** Find a ConfItem from a list that has a host that matches \a host.
694 * @param lp List to search in.
695 * @param host Filter for ConfItem::host field; matches as a glob.
696 * @param statmask Filter for ConfItem::status.
697 * @return First matching ConfItem from \a lp.
699 struct ConfItem
* find_conf_byhost(struct SLink
* lp
, const char* host
,
702 struct ConfItem
* tmp
= NULL
;
705 if (HOSTLEN
< strlen(host
))
708 for (; lp
; lp
= lp
->next
) {
709 tmp
= lp
->value
.aconf
;
710 if (0 != (tmp
->status
& statmask
)) {
711 assert(0 != tmp
->host
);
712 if (0 == match(tmp
->host
, host
))
719 /** Find a ConfItem from a list that has an address equal to \a ip.
720 * @param lp List to search in.
721 * @param ip Filter for ConfItem::address field; matches exactly.
722 * @param statmask Filter for ConfItem::status.
723 * @return First matching ConfItem from \a lp.
725 struct ConfItem
* find_conf_byip(struct SLink
* lp
, const struct irc_in_addr
* ip
,
728 struct ConfItem
* tmp
;
730 for (; lp
; lp
= lp
->next
) {
731 tmp
= lp
->value
.aconf
;
732 if (0 != (tmp
->status
& statmask
)
733 && !irc_in_addr_cmp(&tmp
->address
.addr
, ip
))
739 /** Free all CRules from #cruleConfList. */
740 void conf_erase_crule_list(void)
742 struct CRuleConf
* next
;
743 struct CRuleConf
* p
= cruleConfList
;
745 for ( ; p
; p
= next
) {
747 crule_free(&p
->node
);
755 /** Return #cruleConfList.
756 * @return #cruleConfList
758 const struct CRuleConf
* conf_get_crule_list(void)
760 return cruleConfList
;
763 /** Free all deny rules from #denyConfList. */
764 void conf_erase_deny_list(void)
766 struct DenyConf
* next
;
767 struct DenyConf
* p
= denyConfList
;
768 for ( ; p
; p
= next
) {
779 /** Return #denyConfList.
780 * @return #denyConfList
782 const struct DenyConf
* conf_get_deny_list(void)
787 /** Find any existing quarantine for the named channel.
788 * @param chname Channel name to search for.
789 * @return Reason for channel's quarantine, or NULL if none exists.
792 find_quarantine(const char *chname
)
796 for (qline
= GlobalQuarantineList
; qline
; qline
= qline
->next
)
797 if (!ircd_strcmp(qline
->chname
, chname
))
798 return qline
->reason
;
802 /** Free all qline structs from #GlobalQuarantineList. */
803 void clear_quarantines(void)
806 while ((qline
= GlobalQuarantineList
))
808 GlobalQuarantineList
= qline
->next
;
809 MyFree(qline
->reason
);
810 MyFree(qline
->chname
);
815 /** When non-zero, indicates that a configuration error has been seen in this pass. */
816 static int conf_error
;
817 /** When non-zero, indicates that the configuration file was loaded at least once. */
818 static int conf_already_read
;
820 extern void yyparse(void);
821 extern void init_lexer(void);
823 /** Read configuration file.
824 * @return Zero on failure, non-zero on success. */
825 int read_configuration_file(void)
828 feature_unmark(); /* unmark all features for resetting later */
829 clear_nameservers(); /* clear previous list of DNS servers */
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
952 mark_listeners_closing();
956 read_configuration_file();
958 log_reopen(); /* reopen log files */
962 class_delete_marked(); /* unless it fails */
965 * Flush out deleted I and P lines although still in use.
967 for (tmp
= &GlobalConfList
; (tmp2
= *tmp
);) {
968 if (CONF_ILLEGAL
== (tmp2
->status
& CONF_ILLEGAL
)) {
978 for (i
= 0; i
<= HighestFd
; i
++) {
979 if ((acptr
= LocalClientArray
[i
])) {
980 assert(!IsMe(acptr
));
982 det_confs_butmask(acptr
, ~(CONF_UWORLD
| CONF_ILLEGAL
));
983 /* Because admin's are getting so uppity about people managing to
984 * get past K/G's etc, we'll "fix" the bug by actually explaining
987 if ((found_g
= find_kill(acptr
))) {
988 sendto_opmask_butone(0, found_g
== -2 ? SNO_GLINE
: SNO_OPERKILL
,
989 found_g
== -2 ? "G-line active for %s%s" :
990 "K-line active for %s%s",
991 IsUnknown(acptr
) ? "Unregistered Client ":"",
992 get_client_name(acptr
, SHOW_IP
));
993 if (exit_client(cptr
, acptr
, &me
, found_g
== -2 ? "G-lined" :
994 "K-lined") == CPTR_KILLED
)
1000 attach_conf_uworld(&me
);
1005 /** Read configuration file for the very first time.
1006 * @return Non-zero on success, zero on failure.
1011 if (read_configuration_file()) {
1013 * make sure we're sane to start if the config
1014 * file read didn't get everything we need.
1015 * XXX - should any of these abort the server?
1016 * TODO: add warning messages
1018 if (0 == localConf
.name
|| 0 == localConf
.numeric
)
1023 if (0 == localConf
.location1
)
1024 DupString(localConf
.location1
, "");
1025 if (0 == localConf
.location2
)
1026 DupString(localConf
.location2
, "");
1027 if (0 == localConf
.contact
)
1028 DupString(localConf
.contact
, "");
1035 /** Searches for a K/G-line for a client. If one is found, notify the
1036 * user and disconnect them.
1037 * @param cptr Client to search for.
1038 * @return 0 if client is accepted; -1 if client was locally denied
1039 * (K-line); -2 if client was globally denied (G-line).
1041 int find_kill(struct Client
*cptr
)
1045 const char* realname
;
1046 struct DenyConf
* deny
;
1047 struct Gline
* agline
= NULL
;
1051 if (!cli_user(cptr
))
1054 host
= cli_sockhost(cptr
);
1055 name
= cli_user(cptr
)->username
;
1056 realname
= cli_info(cptr
);
1058 assert(strlen(host
) <= HOSTLEN
);
1059 assert((name
? strlen(name
) : 0) <= HOSTLEN
);
1060 assert((realname
? strlen(realname
) : 0) <= REALLEN
);
1062 /* 2000-07-14: Rewrote this loop for massive speed increases.
1065 for (deny
= denyConfList
; deny
; deny
= deny
->next
) {
1066 if (deny
->usermask
&& match(deny
->usermask
, name
))
1068 if (deny
->realmask
&& match(deny
->realmask
, realname
))
1070 if (deny
->bits
> 0) {
1071 if (!ipmask_check(&cli_ip(cptr
), &deny
->address
, deny
->bits
))
1073 } else if (deny
->hostmask
&& match(deny
->hostmask
, host
))
1076 if (EmptyString(deny
->message
))
1077 send_reply(cptr
, SND_EXPLICIT
| ERR_YOUREBANNEDCREEP
,
1078 ":Connection from your host is refused on this server.");
1080 if (deny
->flags
& DENY_FLAGS_FILE
)
1081 killcomment(cptr
, deny
->message
);
1083 send_reply(cptr
, SND_EXPLICIT
| ERR_YOUREBANNEDCREEP
, ":%s.", deny
->message
);
1088 if ((agline
= gline_lookup(cptr
, 0))) {
1090 * find active glines
1091 * added a check against the user's IP address to find_gline() -Kev
1093 send_reply(cptr
, SND_EXPLICIT
| ERR_YOUREBANNEDCREEP
, ":%s.", GlineReason(agline
));
1100 /** Attempt to attach Client blocks to \a cptr. If attach_iline()
1101 * fails for the client, emit a debugging message.
1102 * @param cptr Client to check for access.
1103 * @return Access check result.
1105 enum AuthorizationCheckResult
conf_check_client(struct Client
*cptr
)
1107 enum AuthorizationCheckResult acr
= ACR_OK
;
1109 if ((acr
= attach_iline(cptr
))) {
1110 Debug((DEBUG_DNS
, "ch_cl: access denied: %s[%s]",
1111 cli_name(cptr
), cli_sockhost(cptr
)));
1117 /** Check access for a server given its name (passed in cptr struct).
1118 * Must check for all C/N lines which have a name which matches the
1119 * name given and a host which matches. A host alias which is the
1120 * same as the server name is also acceptable in the host field of a
1122 * @param cptr Peer server to check.
1123 * @return 0 if accepted, -1 if access denied.
1125 int conf_check_server(struct Client
*cptr
)
1127 struct ConfItem
* c_conf
= NULL
;
1130 Debug((DEBUG_DNS
, "sv_cl: check access for %s[%s]",
1131 cli_name(cptr
), cli_sockhost(cptr
)));
1133 if (IsUnknown(cptr
) && !attach_confs_byname(cptr
, cli_name(cptr
), CONF_SERVER
)) {
1134 Debug((DEBUG_DNS
, "No C/N lines for %s", cli_sockhost(cptr
)));
1137 lp
= cli_confs(cptr
);
1139 * We initiated this connection so the client should have a C and N
1140 * line already attached after passing through the connect_server()
1143 if (IsConnecting(cptr
) || IsHandshake(cptr
)) {
1144 c_conf
= find_conf_byname(lp
, cli_name(cptr
), CONF_SERVER
);
1146 sendto_opmask_butone(0, SNO_OLDSNO
,
1147 "Connect Error: lost Connect block for %s",
1149 det_confs_butmask(cptr
, 0);
1154 /* Try finding the Connect block by DNS name and IP next. */
1155 if (!c_conf
&& !(c_conf
= find_conf_byhost(lp
, cli_sockhost(cptr
), CONF_SERVER
)))
1156 c_conf
= find_conf_byip(lp
, &cli_ip(cptr
), CONF_SERVER
);
1159 * Attach by IP# only if all other checks have failed.
1160 * It is quite possible to get here with the strange things that can
1161 * happen when using DNS in the way the irc server does. -avalon
1164 c_conf
= find_conf_byip(lp
, &cli_ip(cptr
), CONF_SERVER
);
1166 * detach all conf lines that got attached by attach_confs()
1168 det_confs_butmask(cptr
, 0);
1170 * if no Connect block, then deny access
1173 Debug((DEBUG_DNS
, "sv_cl: access denied: %s[%s@%s]",
1174 cli_name(cptr
), cli_username(cptr
), cli_sockhost(cptr
)));
1178 * attach the Connect block to the client structure for later use.
1180 attach_conf(cptr
, c_conf
);
1182 if (!irc_in_addr_valid(&c_conf
->address
.addr
))
1183 memcpy(&c_conf
->address
.addr
, &cli_ip(cptr
), sizeof(c_conf
->address
.addr
));
1185 Debug((DEBUG_DNS
, "sv_cl: access ok: %s[%s]",
1186 cli_name(cptr
), cli_sockhost(cptr
)));