X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=ircd%2Fs_conf.c;h=96f2b99efed09ce18333be6e4218e5e1bcb1b2cd;hb=1570a04e15bec6b2945e4351b1e05211aecdcacc;hp=160b4e008230b450f49f8f90ec70b244c71b71f4;hpb=0767fe05aa03fc26c97902bc8f62bc54331834c9;p=ircu2.10.12-pk.git diff --git a/ircd/s_conf.c b/ircd/s_conf.c index 160b4e0..96f2b99 100644 --- a/ircd/s_conf.c +++ b/ircd/s_conf.c @@ -34,7 +34,6 @@ #include "hash.h" #include "ircd.h" #include "ircd_alloc.h" -#include "ircd_auth.h" #include "ircd_chattr.h" #include "ircd_log.h" #include "ircd_reply.h" @@ -49,6 +48,7 @@ #include "opercmds.h" #include "parse.h" #include "res.h" +#include "s_auth.h" #include "s_bsd.h" #include "s_debug.h" #include "s_misc.h" @@ -56,8 +56,7 @@ #include "struct.h" #include "sys.h" -#include -#include +/* #include -- Now using assert in ircd_log.h */ #include #include #include @@ -130,9 +129,7 @@ struct ConfItem* make_conf(int type) aconf = (struct ConfItem*) MyMalloc(sizeof(struct ConfItem)); assert(0 != aconf); -#ifdef DEBUGMODE ++GlobalConfCount; -#endif memset(aconf, 0, sizeof(struct ConfItem)); aconf->status = type; aconf->next = GlobalConfList; @@ -151,15 +148,16 @@ void free_conf(struct ConfItem *aconf) aconf->address.port)); if (aconf->dns_pending) delete_resolver_queries(aconf); + MyFree(aconf->username); MyFree(aconf->host); + MyFree(aconf->origin_name); if (aconf->passwd) memset(aconf->passwd, 0, strlen(aconf->passwd)); MyFree(aconf->passwd); MyFree(aconf->name); + MyFree(aconf->hub_limit); MyFree(aconf); -#ifdef DEBUGMODE --GlobalConfCount; -#endif } /** Disassociate configuration from the client. @@ -223,22 +221,19 @@ void conf_parse_userhost(struct ConfItem *aconf, char *host) aconf->addrbits = addrbits; else aconf->addrbits = -1; - MyFree(host); } /** Copies a completed DNS query into its ConfItem. * @param vptr Pointer to struct ConfItem for the block. * @param hp DNS reply, or NULL if the lookup failed. */ -static void conf_dns_callback(void* vptr, struct DNSReply* hp) +static void conf_dns_callback(void* vptr, const struct irc_in_addr *addr, const char *h_name) { struct ConfItem* aconf = (struct ConfItem*) vptr; assert(aconf); aconf->dns_pending = 0; - if (hp) { - memcpy(&aconf->address.addr, &hp->addr, sizeof(aconf->address.addr)); - MyFree(hp); - } + if (addr) + memcpy(&aconf->address.addr, addr, sizeof(aconf->address.addr)); } /** Start a nameserver lookup of the conf host. If the conf entry is @@ -249,13 +244,9 @@ static void conf_dns_lookup(struct ConfItem* aconf) { if (!aconf->dns_pending) { char buf[HOSTLEN + 1]; - struct DNSQuery query; - query.vptr = aconf; - query.callback = conf_dns_callback; - host_from_uh(buf, aconf->host, HOSTLEN); - buf[HOSTLEN] = '\0'; - gethost_byname(buf, &query); + host_from_uh(buf, aconf->host, HOSTLEN); + gethost_byname(buf, conf_dns_callback, aconf); aconf->dns_pending = 1; } } @@ -353,22 +344,6 @@ void det_confs_butmask(struct Client* cptr, int mask) } } -/** Check client limits and attach Client block. - * If there are more connections from the IP than \a aconf->maximum - * allows, return ACR_TOO_MANY_FROM_IP. Otherwise, attach \a aconf to - * \a cptr. - * @param cptr Client getting \a aconf. - * @param aconf Configuration item to attach. - * @return Authorization check result. - */ -static enum AuthorizationCheckResult -check_limit_and_attach(struct Client* cptr, struct ConfItem* aconf) -{ - if (IPcheck_nr(cptr) > aconf->maximum) - return ACR_TOO_MANY_FROM_IP; - return attach_conf(cptr, aconf); -} - /** Find the first (best) Client block to attach. * @param cptr Client for whom to check rules. * @return Authorization check result. @@ -376,31 +351,169 @@ check_limit_and_attach(struct Client* cptr, struct ConfItem* aconf) enum AuthorizationCheckResult attach_iline(struct Client* cptr) { struct ConfItem* aconf; - struct DNSReply* hp; assert(0 != cptr); - hp = cli_dns_reply(cptr); for (aconf = GlobalConfList; aconf; aconf = aconf->next) { - if (aconf->status != CONF_CLIENT || !aconf->host) + if (aconf->status != CONF_CLIENT) continue; + /* If you change any of this logic, please make corresponding + * changes in conf_debug_iline() below. + */ if (aconf->address.port && aconf->address.port != cli_listener(cptr)->addr.port) continue; - if (aconf->username) { + if (aconf->username && match(aconf->username, cli_username(cptr))) + continue; + if (aconf->host && match(aconf->host, cli_sockhost(cptr))) + continue; + if ((aconf->addrbits >= 0) + && !ipmask_check(&cli_ip(cptr), &aconf->address.addr, aconf->addrbits)) + continue; + if (IPcheck_nr(cptr) > aconf->maximum) + return ACR_TOO_MANY_FROM_IP; + if (aconf->username) SetFlag(cptr, FLAG_DOID); - if (match(aconf->username, cli_username(cptr))) + return attach_conf(cptr, aconf); + } + return ACR_NO_AUTHORIZATION; +} + +/** Interpret \a client as a client specifier and show which Client + * block(s) match that client. + * + * The client specifier may contain an IP address, hostname, listener + * port, or a combination of those separated by commas. IP addresses + * and hostnamese may be preceded by "username@"; the last given + * username will be used for the match. + * + * @param[in] client Client specifier. + * @return Matching Client block structure. + */ +struct ConfItem *conf_debug_iline(const char *client) +{ + struct irc_in_addr address; + struct ConfItem *aconf; + struct DenyConf *deny; + char *sep; + unsigned short listener; + char username[USERLEN+1], hostname[HOSTLEN+1], realname[REALLEN+1]; + + /* Initialize variables. */ + listener = 0; + memset(&address, 0, sizeof(address)); + memset(&username, 0, sizeof(username)); + memset(&hostname, 0, sizeof(hostname)); + memset(&realname, 0, sizeof(realname)); + + /* Parse client specifier. */ + while (*client) { + struct irc_in_addr tmpaddr; + long tmp; + + /* Try to parse as listener port number first. */ + tmp = strtol(client, &sep, 10); + if (tmp && (*sep == '\0' || *sep == ',')) { + listener = tmp; + client = sep + (*sep != '\0'); + continue; + } + + /* Maybe username@ before an IP address or hostname? */ + tmp = strcspn(client, ",@"); + if (client[tmp] == '@') { + if (tmp > USERLEN) + tmp = USERLEN; + ircd_strncpy(username, client, tmp); + /* and fall through */ + client += tmp + 1; + } + + /* Looks like an IP address? */ + tmp = ircd_aton(&tmpaddr, client); + if (tmp && (client[tmp] == '\0' || client[tmp] == ',')) { + memcpy(&address, &tmpaddr, sizeof(address)); + client += tmp + (client[tmp] != '\0'); continue; } - if (hp) { - Debug((DEBUG_DNS, "a_il: %s->%s", cli_sockhost(cptr), hp->h_name)); - if (!match(aconf->host, hp->h_name)) - return check_limit_and_attach(cptr, aconf); + + /* Realname? */ + if (client[0] == '$' && client[1] == 'R') { + client += 2; + for (tmp = 0; *client != '\0' && *client != ',' && tmp < REALLEN; ++client, ++tmp) { + if (*client == '\\') + realname[tmp] = *++client; + else + realname[tmp] = *client; + } + continue; + } + + /* Else must be a hostname. */ + tmp = strcspn(client, ","); + if (tmp > HOSTLEN) + tmp = HOSTLEN; + ircd_strncpy(hostname, client, tmp); + client += tmp + (client[tmp] != '\0'); + } + + /* Walk configuration to find matching Client block. */ + for (aconf = GlobalConfList; aconf; aconf = aconf->next) { + if (aconf->status != CONF_CLIENT) + continue; + if (aconf->address.port && aconf->address.port != listener) { + fprintf(stdout, "Listener port mismatch: %u != %u\n", aconf->address.port, listener); + continue; + } + if (aconf->username && match(aconf->username, username)) { + fprintf(stdout, "Username mismatch: %s != %s\n", aconf->username, username); + continue; + } + if (aconf->host && match(aconf->host, hostname)) { + fprintf(stdout, "Hostname mismatch: %s != %s\n", aconf->host, hostname); + continue; } if ((aconf->addrbits >= 0) - && ipmask_check(&cli_ip(cptr), &aconf->address.addr, aconf->addrbits)) - return check_limit_and_attach(cptr, aconf); + && !ipmask_check(&address, &aconf->address.addr, aconf->addrbits)) { + fprintf(stdout, "IP address mismatch: %s != %s\n", aconf->name, ircd_ntoa(&address)); + continue; + } + fprintf(stdout, "Match! username=%s host=%s ip=%s class=%s maxlinks=%u password=%s\n", + (aconf->username ? aconf->username : "(null)"), + (aconf->host ? aconf->host : "(null)"), + (aconf->name ? aconf->name : "(null)"), + ConfClass(aconf), aconf->maximum, + (aconf->passwd ? aconf->passwd : "(null)")); + break; } - return ACR_NO_AUTHORIZATION; + + /* If no authorization, say so and exit. */ + if (!aconf) + { + fprintf(stdout, "No authorization found.\n"); + return NULL; + } + + /* Look for a Kill block with the user's name on it. */ + for (deny = denyConfList; deny; deny = deny->next) { + if (deny->usermask && match(deny->usermask, username)) + continue; + if (deny->realmask && match(deny->realmask, realname)) + continue; + if (deny->bits > 0) { + if (!ipmask_check(&address, &deny->address, deny->bits)) + continue; + } else if (deny->hostmask && match(deny->hostmask, hostname)) + continue; + + /* Looks like a match; report it. */ + fprintf(stdout, "Denied! usermask=%s realmask=\"%s\" hostmask=%s (bits=%u)\n", + deny->usermask ? deny->usermask : "(null)", + deny->realmask ? deny->realmask : "(null)", + deny->hostmask ? deny->hostmask : "(null)", + deny->bits); + } + + return aconf; } /** Check whether a particular ConfItem is already attached to a @@ -422,7 +535,7 @@ static int is_attached(struct ConfItem *aconf, struct Client *cptr) /** Associate a specific configuration entry to a *local* client (this * is the one which used in accepting the connection). Note, that this - * automaticly changes the attachment if there was an old one... + * automatically changes the attachment if there was an old one... * @param cptr Client to attach \a aconf to * @param aconf ConfItem to attach * @return Authorization check result. @@ -542,6 +655,7 @@ struct ConfItem* find_conf_exact(const char* name, struct Client *cptr, int stat else if (!ipmask_check(&cli_ip(cptr), &tmp->address.addr, tmp->addrbits)) continue; if ((tmp->status & CONF_OPERATOR) + && (MaxLinks(tmp->conn_class) > 0) && (tmp->clients >= MaxLinks(tmp->conn_class))) continue; return tmp; @@ -656,6 +770,7 @@ void conf_erase_deny_list(void) MyFree(p->hostmask); MyFree(p->usermask); MyFree(p->message); + MyFree(p->realmask); MyFree(p); } denyConfList = 0; @@ -701,9 +816,9 @@ void clear_quarantines(void) static int conf_error; /** When non-zero, indicates that the configuration file was loaded at least once. */ static int conf_already_read; -extern FILE *yyin; extern void yyparse(void); -extern void init_lexer(void); +extern int init_lexer(void); +extern void deinit_lexer(void); /** Read configuration file. * @return Zero on failure, non-zero on success. */ @@ -711,11 +826,11 @@ int read_configuration_file(void) { conf_error = 0; feature_unmark(); /* unmark all features for resetting later */ - /* Now just open an fd. The buffering isn't really needed... */ - init_lexer(); + clear_nameservers(); /* clear previous list of DNS servers */ + if (!init_lexer()) + return 0; yyparse(); - fclose(yyin); - yyin = NULL; + deinit_lexer(); feature_mark(); /* reset unmarked features */ conf_already_read = 1; return 1; @@ -736,6 +851,47 @@ yyerror(const char *msg) conf_error = 1; } +/** Attach CONF_UWORLD items to a server and everything attached to it. */ +static void +attach_conf_uworld(struct Client *cptr) +{ + struct DLink *lp; + + attach_confs_byhost(cptr, cli_name(cptr), CONF_UWORLD); + for (lp = cli_serv(cptr)->down; lp; lp = lp->next) + attach_conf_uworld(lp->value.cptr); +} + +/** Free all memory associated with service mapping \a smap. + * @param smap[in] The mapping to free. + */ +void free_mapping(struct s_map *smap) +{ + struct nick_host *nh, *next; + for (nh = smap->services; nh; nh = next) + { + next = nh->next; + MyFree(nh); + } + MyFree(smap->name); + MyFree(smap->command); + MyFree(smap->prepend); + MyFree(smap); +} + +/** Unregister and free all current service mappings. */ +static void close_mappings(void) +{ + struct s_map *map, *next; + + for (map = GlobalServiceMapList; map; map = next) { + next = map->next; + unregister_mapping(map); + free_mapping(map); + } + GlobalServiceMapList = NULL; +} + /** Reload the configuration file. * @param cptr Client that requested rehash (if a signal, &me). * @param sig Type of rehash (0 = oper-requested, 1 = signal, 2 = @@ -788,18 +944,19 @@ int rehash(struct Client *cptr, int sig) clear_quarantines(); - if (sig != 2) - restart_resolver(); - class_mark_delete(); mark_listeners_closing(); - iauth_mark_closing(); + auth_mark_closing(); + close_mappings(); read_configuration_file(); + if (sig != 2) + restart_resolver(); + log_reopen(); /* reopen log files */ - iauth_close_unused(); + auth_close_unused(); close_listeners(); class_delete_marked(); /* unless it fails */ @@ -820,10 +977,8 @@ int rehash(struct Client *cptr, int sig) for (i = 0; i <= HighestFd; i++) { if ((acptr = LocalClientArray[i])) { assert(!IsMe(acptr)); - if (IsServer(acptr)) { + if (IsServer(acptr)) det_confs_butmask(acptr, ~(CONF_UWORLD | CONF_ILLEGAL)); - attach_confs_byname(acptr, cli_name(acptr), CONF_UWORLD); - } /* Because admin's are getting so uppity about people managing to * get past K/G's etc, we'll "fix" the bug by actually explaining * whats going on. @@ -841,6 +996,8 @@ int rehash(struct Client *cptr, int sig) } } + attach_conf_uworld(&me); + return ret; } @@ -905,28 +1062,16 @@ int find_kill(struct Client *cptr) * -- Isomer */ for (deny = denyConfList; deny; deny = deny->next) { - if (0 != match(deny->usermask, name)) + if (deny->usermask && match(deny->usermask, name)) + continue; + if (deny->realmask && match(deny->realmask, realname)) + continue; + if (deny->bits > 0) { + if (!ipmask_check(&cli_ip(cptr), &deny->address, deny->bits)) + continue; + } else if (deny->hostmask && match(deny->hostmask, host)) continue; - if (EmptyString(deny->hostmask)) - break; - - if (deny->flags & DENY_FLAGS_REALNAME) { /* K: by real name */ - if (0 == match(deny->hostmask + 2, realname)) - break; - } else if (deny->flags & DENY_FLAGS_IP) { /* k: by IP */ -#ifdef DEBUGMODE - char tbuf1[SOCKIPLEN], tbuf2[SOCKIPLEN]; - Debug((DEBUG_DEBUG, "ip: %s network: %s/%u", - ircd_ntoa_r(tbuf1, &cli_ip(cptr)), ircd_ntoa_r(tbuf2, &deny->address), deny->bits)); -#endif - if (ipmask_check(&cli_ip(cptr), &deny->address, deny->bits)) - break; - } - else if (0 == match(deny->hostmask, host)) - break; - } - if (deny) { if (EmptyString(deny->message)) send_reply(cptr, SND_EXPLICIT | ERR_YOUREBANNEDCREEP, ":Connection from your host is refused on this server."); @@ -936,19 +1081,17 @@ int find_kill(struct Client *cptr) else send_reply(cptr, SND_EXPLICIT | ERR_YOUREBANNEDCREEP, ":%s.", deny->message); } + return -1; } - else if ((agline = gline_lookup(cptr, 0))) { + + if (!feature_bool(FEAT_DISABLE_GLINES) && (agline = gline_lookup(cptr, 0))) { /* * find active glines * added a check against the user's IP address to find_gline() -Kev */ send_reply(cptr, SND_EXPLICIT | ERR_YOUREBANNEDCREEP, ":%s.", GlineReason(agline)); - } - - if (deny) - return -1; - if (agline) return -2; + } return 0; } @@ -999,35 +1142,18 @@ int conf_check_server(struct Client *cptr) if (IsConnecting(cptr) || IsHandshake(cptr)) { c_conf = find_conf_byname(lp, cli_name(cptr), CONF_SERVER); if (!c_conf) { - sendto_opmask_butone(0, SNO_OLDSNO, "Connect Error: lost C:line for %s", + sendto_opmask_butone(0, SNO_OLDSNO, + "Connect Error: lost Connect block for %s", cli_name(cptr)); det_confs_butmask(cptr, 0); return -1; } } - if (!c_conf) { - if (cli_dns_reply(cptr)) { - struct DNSReply* hp = cli_dns_reply(cptr); - const char* name = hp->h_name; - /* - * If we are missing a C or N line from above, search for - * it under all known hostnames we have for this ip#. - */ - if ((c_conf = find_conf_byhost(lp, hp->h_name, CONF_SERVER))) - ircd_strncpy(cli_sockhost(cptr), name, HOSTLEN); - else - c_conf = find_conf_byip(lp, &hp->addr, CONF_SERVER); - } - else { - /* - * Check for C lines with the hostname portion the ip number - * of the host the server runs on. This also checks the case where - * there is a server connecting from 'localhost'. - */ - c_conf = find_conf_byhost(lp, cli_sockhost(cptr), CONF_SERVER); - } - } + /* Try finding the Connect block by DNS name and IP next. */ + if (!c_conf && !(c_conf = find_conf_byhost(lp, cli_sockhost(cptr), CONF_SERVER))) + c_conf = find_conf_byip(lp, &cli_ip(cptr), CONF_SERVER); + /* * Attach by IP# only if all other checks have failed. * It is quite possible to get here with the strange things that can @@ -1051,7 +1177,6 @@ int conf_check_server(struct Client *cptr) * attach the Connect block to the client structure for later use. */ attach_conf(cptr, c_conf); - attach_confs_byname(cptr, cli_name(cptr), CONF_UWORLD); if (!irc_in_addr_valid(&c_conf->address.addr)) memcpy(&c_conf->address.addr, &cli_ip(cptr), sizeof(c_conf->address.addr));