X-Git-Url: https://jfr.im/git/solanum.git/blobdiff_plain/1d02144f8b93f006b11b2fd198af2af90b3586db..36828ff7205558bda3857b402e1bf0f62783ed1a:/ircd/client.c diff --git a/ircd/client.c b/ircd/client.c index 39d4ea4d..136c30a4 100644 --- a/ircd/client.c +++ b/ircd/client.c @@ -1,5 +1,5 @@ /* - * charybdis: an advanced ircd. + * Solanum: a slightly advanced ircd * client.c: Controls clients. * * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center @@ -21,21 +21,18 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA - * - * $Id: client.c 3514 2007-06-06 16:25:21Z nenolod $ */ #include "stdinc.h" -#include "config.h" +#include "defaults.h" #include "client.h" #include "class.h" -#include "common.h" #include "hash.h" #include "match.h" #include "ircd.h" #include "numeric.h" #include "packet.h" -#include "s_auth.h" +#include "authproc.h" #include "s_conf.h" #include "s_newconf.h" #include "logger.h" @@ -50,11 +47,11 @@ #include "hook.h" #include "msg.h" #include "monitor.h" -#include "blacklist.h" #include "reject.h" #include "scache.h" -#include "irc_dictionary.h" +#include "rb_dictionary.h" #include "sslproc.h" +#include "wsproc.h" #include "s_assert.h" #define DEBUG_EXITED_CLIENTS @@ -79,15 +76,9 @@ static rb_bh *pclient_heap = NULL; static rb_bh *user_heap = NULL; static rb_bh *away_heap = NULL; static char current_uid[IDLEN]; -static int32_t current_connid = 0; - -struct Dictionary *nd_dict = NULL; +static uint32_t current_connid = 0; -enum -{ - D_LINED, - K_LINED -}; +rb_dictionary *nd_dict = NULL; rb_dlink_list dead_list; #ifdef DEBUG_EXITED_CLIENTS @@ -129,9 +120,83 @@ init_client(void) rb_event_addish("exit_aborted_clients", exit_aborted_clients, NULL, 1); rb_event_add("flood_recalc", flood_recalc, NULL, 1); - nd_dict = irc_dictionary_create(irccmp); + nd_dict = rb_dictionary_create("nickdelay", irccmp); +} + +/* + * connid_get - allocate a connid + * + * inputs - none + * outputs - a connid token which is used to represent a logical circuit + * side effects - current_connid is incremented, possibly multiple times. + * the association of the connid to it's client is committed. + */ +uint32_t +connid_get(struct Client *client_p) +{ + s_assert(MyConnect(client_p)); + if (!MyConnect(client_p)) + return 0; + + /* find a connid that is available */ + while (find_cli_connid_hash(++current_connid) != NULL) + { + /* handle wraparound, current_connid must NEVER be 0 */ + if (current_connid == 0) + ++current_connid; + } + + add_to_cli_connid_hash(client_p, current_connid); + rb_dlinkAddAlloc(RB_UINT_TO_POINTER(current_connid), &client_p->localClient->connids); + + return current_connid; } +/* + * connid_put - free a connid + * + * inputs - connid to free + * outputs - nothing + * side effects - connid bookkeeping structures are freed + */ +void +connid_put(uint32_t id) +{ + struct Client *client_p; + + s_assert(id != 0); + if (id == 0) + return; + + client_p = find_cli_connid_hash(id); + if (client_p == NULL) + return; + + del_from_cli_connid_hash(id); + rb_dlinkFindDestroy(RB_UINT_TO_POINTER(id), &client_p->localClient->connids); +} + +/* + * client_release_connids - release any connids still attached to a client + * + * inputs - client to garbage collect + * outputs - none + * side effects - client's connids are garbage collected + */ +void +client_release_connids(struct Client *client_p) +{ + rb_dlink_node *ptr, *ptr2; + + if (client_p->localClient->connids.head) + s_assert(MyConnect(client_p)); + + if (!MyConnect(client_p)) + return; + + RB_DLINK_FOREACH_SAFE(ptr, ptr2, client_p->localClient->connids.head) + connid_put(RB_POINTER_TO_UINT(ptr->data)); +} /* * make_client - create a new Client struct and set it to initial state. @@ -163,17 +228,6 @@ make_client(struct Client *from) client_p->localClient->F = NULL; - if(current_connid+1 == 0) - current_connid++; - - client_p->localClient->connid = ++current_connid; - - if(current_connid+1 == 0) - current_connid++; - - client_p->localClient->zconnid = ++current_connid; - add_to_cli_connid_hash(client_p); - client_p->preClient = rb_bh_alloc(pclient_heap); /* as good a place as any... */ @@ -187,7 +241,7 @@ make_client(struct Client *from) } SetUnknown(client_p); - strcpy(client_p->username, "unknown"); + rb_strlcpy(client_p->username, "unknown", sizeof(client_p->username)); return client_p; } @@ -195,17 +249,15 @@ make_client(struct Client *from) void free_pre_client(struct Client *client_p) { - struct Blacklist *blptr; - s_assert(NULL != client_p); if(client_p->preClient == NULL) return; - blptr = client_p->preClient->dnsbl_listed; - if (blptr != NULL) - unref_blacklist(blptr); - s_assert(rb_dlink_list_length(&client_p->preClient->dnsbl_queries) == 0); + s_assert(client_p->preClient->auth.cid == 0); + + rb_free(client_p->preClient->auth.data); + rb_free(client_p->preClient->auth.reason); rb_bh_free(pclient_heap, client_p->preClient); client_p->preClient = NULL; @@ -232,7 +284,7 @@ free_local_client(struct Client *client_p) client_p->localClient->listener = 0; } - del_from_cli_connid_hash(client_p); + client_release_connids(client_p); if(client_p->localClient->F != NULL) { rb_close(client_p->localClient->F); @@ -248,22 +300,26 @@ free_local_client(struct Client *client_p) rb_free(client_p->localClient->auth_user); rb_free(client_p->localClient->challenge); rb_free(client_p->localClient->fullcaps); - rb_free(client_p->localClient->opername); rb_free(client_p->localClient->mangledhost); - if (client_p->localClient->privset) - privilegeset_unref(client_p->localClient->privset); - if(IsSSL(client_p)) - ssld_decrement_clicount(client_p->localClient->ssl_ctl); + if (IsSSL(client_p)) + ssld_decrement_clicount(client_p->localClient->ssl_ctl); + + rb_free(client_p->localClient->cipher_string); + + if (IsCapable(client_p, CAP_ZIP)) + ssld_decrement_clicount(client_p->localClient->z_ctl); - if(IsCapable(client_p, CAP_ZIP)) - ssld_decrement_clicount(client_p->localClient->z_ctl); + rb_free(client_p->localClient->zipstats); + + if (client_p->localClient->ws_ctl != NULL) + wsockd_decrement_clicount(client_p->localClient->ws_ctl); rb_bh_free(lclient_heap, client_p->localClient); client_p->localClient = NULL; } -void +static void free_client(struct Client *client_p) { s_assert(NULL != client_p); @@ -343,14 +399,14 @@ check_pings_list(rb_dlink_list * list) { if(IsServer(client_p)) { - sendto_realops_snomask(SNO_GENERAL, L_ALL, + sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "No response from %s, closing link", client_p->name); ilog(L_SERVER, "No response from %s, closing link", log_client_name(client_p, HIDE_IP)); } - (void) rb_snprintf(scratch, sizeof(scratch), + (void) snprintf(scratch, sizeof(scratch), "Ping timeout: %d seconds", (int) (rb_current_time() - client_p->localClient->lasttime)); @@ -396,9 +452,8 @@ check_unknowns_list(rb_dlink_list * list) if(IsDead(client_p) || IsClosing(client_p)) continue; - /* still has DNSbls to validate against */ - if(client_p->preClient != NULL && - rb_dlink_list_length(&client_p->preClient->dnsbl_queries) > 0) + /* Still querying with authd */ + if(client_p->preClient != NULL && client_p->preClient->auth.cid != 0) continue; /* @@ -411,7 +466,7 @@ check_unknowns_list(rb_dlink_list * list) { if(IsAnyServer(client_p)) { - sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) ? L_NETWIDE : L_ALL, + sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "No response from %s, closing link", client_p->name); ilog(L_SERVER, @@ -423,7 +478,7 @@ check_unknowns_list(rb_dlink_list * list) } } -static void +void notify_banned_client(struct Client *client_p, struct ConfItem *aconf, int ban) { static const char conn_closed[] = "Connection closed"; @@ -468,19 +523,6 @@ check_banned_lines(void) check_xlines(); } -/* check_klines_event() - * - * inputs - - * outputs - - * side effects - check_klines() is called, kline_queued unset - */ -void -check_klines_event(void *unused) -{ - kline_queued = 0; - check_klines(); -} - /* check_klines * * inputs - @@ -506,16 +548,16 @@ check_klines(void) { if(IsExemptKline(client_p)) { - sendto_realops_snomask(SNO_GENERAL, L_ALL, + sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "KLINE over-ruled for %s, client is kline_exempt [%s@%s]", get_client_name(client_p, HIDE_IP), aconf->user, aconf->host); continue; } - sendto_realops_snomask(SNO_GENERAL, L_ALL, - "KLINE active for %s", - get_client_name(client_p, HIDE_IP)); + sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, + "KLINE active for %s (%s@%s)", + get_client_name(client_p, HIDE_IP), aconf->user, aconf->host); notify_banned_client(client_p, aconf, K_LINED); continue; @@ -523,6 +565,88 @@ check_klines(void) } } + +/* check_one_kline() + * + * This process needs to be kept in sync with find_kline() aka find_conf_by_address(). + * + * inputs - pointer to kline to check + * outputs - + * side effects - all clients will be checked against given kline + */ +void +check_one_kline(struct ConfItem *kline) +{ + struct Client *client_p; + rb_dlink_node *ptr; + rb_dlink_node *next_ptr; + int masktype; + int bits; + struct rb_sockaddr_storage sockaddr; + struct sockaddr_in ip4; + + masktype = parse_netmask(kline->host, (struct sockaddr_storage *)&sockaddr, &bits); + + RB_DLINK_FOREACH_SAFE(ptr, next_ptr, lclient_list.head) + { + int matched = 0; + + client_p = ptr->data; + + if(IsMe(client_p) || !IsPerson(client_p)) + continue; + + if(!match(kline->user, client_p->username)) + continue; + + /* match one kline */ + switch (masktype) { + case HM_IPV4: + case HM_IPV6: + if (IsConfDoSpoofIp(client_p->localClient->att_conf) && + IsConfKlineSpoof(client_p->localClient->att_conf)) + continue; + if (client_p->localClient->ip.ss_family == AF_INET6 && sockaddr.ss_family == AF_INET && + rb_ipv4_from_ipv6((struct sockaddr_in6 *)&client_p->localClient->ip, &ip4) + && comp_with_mask_sock((struct sockaddr *)&ip4, (struct sockaddr *)&sockaddr, bits)) + matched = 1; + else if (client_p->localClient->ip.ss_family == sockaddr.ss_family && + comp_with_mask_sock((struct sockaddr *)&client_p->localClient->ip, + (struct sockaddr *)&sockaddr, bits)) + matched = 1; + break; + case HM_HOST: + if (match(kline->host, client_p->orighost)) + matched = 1; + if (IsConfDoSpoofIp(client_p->localClient->att_conf) && + IsConfKlineSpoof(client_p->localClient->att_conf)) + continue; + if (match(kline->host, client_p->sockhost)) + matched = 1; + break; + } + + if (!matched) + continue; + + if(IsExemptKline(client_p)) + { + sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, + "KLINE over-ruled for %s, client is kline_exempt [%s@%s]", + get_client_name(client_p, HIDE_IP), + kline->user, kline->host); + continue; + } + + sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, + "KLINE active for %s (%s@%s)", + get_client_name(client_p, HIDE_IP), kline->user, kline->host); + + notify_banned_client(client_p, kline, K_LINED); + } +} + + /* check_dlines() * * inputs - @@ -544,14 +668,14 @@ check_dlines(void) if(IsMe(client_p)) continue; - if((aconf = find_dline((struct sockaddr *)&client_p->localClient->ip,client_p->localClient->ip.ss_family)) != NULL) + if((aconf = find_dline((struct sockaddr *)&client_p->localClient->ip, GET_SS_FAMILY(&client_p->localClient->ip))) != NULL) { if(aconf->status & CONF_EXEMPTDLINE) continue; - sendto_realops_snomask(SNO_GENERAL, L_ALL, - "DLINE active for %s", - get_client_name(client_p, HIDE_IP)); + sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, + "DLINE active for %s (%s)", + get_client_name(client_p, HIDE_IP), aconf->host); notify_banned_client(client_p, aconf, D_LINED); continue; @@ -563,7 +687,7 @@ check_dlines(void) { client_p = ptr->data; - if((aconf = find_dline((struct sockaddr *)&client_p->localClient->ip,client_p->localClient->ip.ss_family)) != NULL) + if((aconf = find_dline((struct sockaddr *)&client_p->localClient->ip, GET_SS_FAMILY(&client_p->localClient->ip))) != NULL) { if(aconf->status & CONF_EXEMPTDLINE) continue; @@ -598,15 +722,16 @@ check_xlines(void) { if(IsExemptKline(client_p)) { - sendto_realops_snomask(SNO_GENERAL, L_ALL, + sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "XLINE over-ruled for %s, client is kline_exempt [%s]", get_client_name(client_p, HIDE_IP), aconf->host); continue; } - sendto_realops_snomask(SNO_GENERAL, L_ALL, "XLINE active for %s", - get_client_name(client_p, HIDE_IP)); + sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, + "XLINE active for %s (%s)", + get_client_name(client_p, HIDE_IP), aconf->host); (void) exit_client(client_p, client_p, &me, "Bad user info"); continue; @@ -648,11 +773,11 @@ resv_nick_fnc(const char *mask, const char *reason, int temp_time) nick = client_p->id; /* Tell opers. */ - sendto_realops_snomask(SNO_GENERAL, L_ALL, + sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "RESV forced nick change for %s!%s@%s to %s; nick matched [%s] (%s)", client_p->name, client_p->username, client_p->host, nick, mask, reason); - sendto_realops_snomask(SNO_NCHANGE, L_ALL, + sendto_realops_snomask(SNO_NCHANGE, L_NETWIDE, "Nick change: From %s to %s [%s@%s]", client_p->name, nick, client_p->username, client_p->host); @@ -672,7 +797,7 @@ resv_nick_fnc(const char *mask, const char *reason, int temp_time) /* Do all of the nick-changing gymnastics. */ client_p->tsinfo = rb_current_time(); - add_history(client_p, 1); + whowas_add_history(client_p, 1); monitor_signoff(client_p); @@ -696,7 +821,7 @@ resv_nick_fnc(const char *mask, const char *reason, int temp_time) rb_dlinkDestroy(ptr, &client_p->on_allow_list); } - rb_snprintf(note, sizeof(note), "Nick: %s", nick); + snprintf(note, sizeof(note), "Nick: %s", nick); rb_note(client_p->localClient->F, note); } } @@ -872,7 +997,7 @@ find_chasing(struct Client *source_p, const char *user, int *chasing) if(who || IsDigit(*user)) return who; - if(!(who = get_history(user, (long) KILLCHASETIMELIMIT))) + if(!(who = whowas_get_history(user, (long) KILLCHASETIMELIMIT))) { sendto_one_numeric(source_p, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), user); @@ -926,16 +1051,16 @@ get_client_name(struct Client *client, int showip) switch (showip) { case SHOW_IP: - rb_snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]", + snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]", client->name, client->username, client->sockhost); break; case MASK_IP: - rb_snprintf(nbuf, sizeof(nbuf), "%s[%s@255.255.255.255]", + snprintf(nbuf, sizeof(nbuf), "%s[%s@255.255.255.255]", client->name, client->username); break; default: - rb_snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]", + snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]", client->name, client->username, client->host); } return nbuf; @@ -968,12 +1093,12 @@ log_client_name(struct Client *target_p, int showip) switch (showip) { case SHOW_IP: - rb_snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]", target_p->name, + snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]", target_p->name, target_p->username, target_p->sockhost); break; default: - rb_snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]", target_p->name, + snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]", target_p->name, target_p->username, target_p->host); } @@ -1019,11 +1144,11 @@ free_exited_clients(void *unused) { s_assert(0); sendto_realops_snomask(SNO_GENERAL, L_ALL, - "On abort_list: %s stat: %u flags: %u/%u handler: %c", + "On abort_list: %s stat: %u flags: %llu handler: %c", target_p->name, (unsigned int) target_p->status, - target_p->flags, target_p->flags2, target_p->handler); + (unsigned long long)target_p->flags, target_p->handler); sendto_realops_snomask(SNO_GENERAL, L_ALL, - "Please report this to the charybdis developers!"); + "Please report this to the solanum developers!"); found++; } } @@ -1073,7 +1198,7 @@ free_exited_clients(void *unused) ** already been sent. we make sure to exit a server's dependent clients ** and servers before the server itself; exit_one_client takes care of ** actually removing things off llists. tweaked from +CSr31 -orabidoo -*/ + */ /* * added sanity test code.... source_p->serv might be NULL... */ @@ -1126,7 +1251,7 @@ recurse_remove_clients(struct Client *source_p, const char *comment) ** Remove *everything* that depends on source_p, from all lists, and sending ** all necessary SQUITs. source_p itself is still on the lists, ** and its SQUITs have been sent except for the upstream one -orabidoo -*/ + */ static void remove_dependents(struct Client *client_p, struct Client *source_p, @@ -1163,11 +1288,11 @@ exit_aborted_clients(void *unused) { s_assert(0); sendto_realops_snomask(SNO_GENERAL, L_ALL, - "On dead_list: %s stat: %u flags: %u/%u handler: %c", + "On dead_list: %s stat: %u flags: %llu handler: %c", abt->client->name, (unsigned int) abt->client->status, - abt->client->flags, abt->client->flags2, abt->client->handler); + (unsigned long long)abt->client->flags, abt->client->handler); sendto_realops_snomask(SNO_GENERAL, L_ALL, - "Please report this to the charybdis developers!"); + "Please report this to the solanum developers!"); continue; } } @@ -1177,7 +1302,7 @@ exit_aborted_clients(void *unused) rb_dlinkDelete(ptr, &abort_list); if(IsAnyServer(abt->client)) - sendto_realops_snomask(SNO_GENERAL, L_ALL, + sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Closing link to %s: %s", abt->client->name, abt->notice); @@ -1193,7 +1318,6 @@ exit_aborted_clients(void *unused) /* * dead_link - Adds client to a list of clients that need an exit_client() - * */ void dead_link(struct Client *client_p, int sendqex) @@ -1209,7 +1333,7 @@ dead_link(struct Client *client_p, int sendqex) if(sendqex) rb_strlcpy(abt->notice, "Max SendQ exceeded", sizeof(abt->notice)); else - rb_snprintf(abt->notice, sizeof(abt->notice), "Write error: %s", strerror(errno)); + snprintf(abt->notice, sizeof(abt->notice), "Write error: %s", strerror(errno)); abt->client = client_p; SetIOError(client_p); @@ -1247,8 +1371,8 @@ exit_generic_client(struct Client *client_p, struct Client *source_p, struct Cli /* Clean up allow lists */ del_all_accepts(source_p); - add_history(source_p, 0); - off_history(source_p); + whowas_add_history(source_p, 0); + whowas_off_history(source_p); monitor_signoff(source_p); @@ -1291,15 +1415,22 @@ exit_remote_client(struct Client *client_p, struct Client *source_p, struct Clie } /* - * This assumes IsUnknown(source_p) == TRUE and MyConnect(source_p) == TRUE + * This assumes IsUnknown(source_p) == true and MyConnect(source_p) == true */ static int -exit_unknown_client(struct Client *client_p, struct Client *source_p, struct Client *from, - const char *comment) +exit_unknown_client(struct Client *client_p, /* The local client originating the + * exit or NULL, if this exit is + * generated by this server for + * internal reasons. + * This will not get any of the + * generated messages. */ + struct Client *source_p, /* Client exiting */ + struct Client *from, /* Client firing off this Exit, + * never NULL! */ + const char *comment) { - delete_auth_queries(source_p); - abort_blacklist_queries(source_p); + authd_abort_client(source_p); rb_dlinkDelete(&source_p->localClient->tnode, &unknown_list); if(!IsIOError(source_p)) @@ -1313,7 +1444,8 @@ exit_unknown_client(struct Client *client_p, struct Client *source_p, struct Cli del_from_id_hash(source_p->id, source_p); del_from_hostname_hash(source_p->host, source_p); - del_from_client_hash(source_p->name, source_p); + if (!IsAnyServer(source_p)) + del_from_client_hash(source_p->name, source_p); remove_client_from_list(source_p); SetDead(source_p); rb_dlinkAddAlloc(source_p, &dead_list); @@ -1339,16 +1471,12 @@ exit_remote_server(struct Client *client_p, struct Client *source_p, struct Clie strcat(comment1, source_p->name); } if (IsPerson(from)) - rb_snprintf(newcomment, sizeof(newcomment), "by %s: %s", + snprintf(newcomment, sizeof(newcomment), "by %s: %s", from->name, comment); - if(source_p->serv != NULL) - remove_dependents(client_p, source_p, from, IsPerson(from) ? newcomment : comment, comment1); + remove_dependents(client_p, source_p, from, IsPerson(from) ? newcomment : comment, comment1); - if(source_p->servptr && source_p->servptr->serv) - rb_dlinkDelete(&source_p->lnode, &source_p->servptr->serv->servers); - else - s_assert(0); + rb_dlinkDelete(&source_p->lnode, &source_p->servptr->serv->servers); rb_dlinkFindDestroy(source_p, &global_serv_list); target_p = source_p->from; @@ -1366,6 +1494,7 @@ exit_remote_server(struct Client *client_p, struct Client *source_p, struct Clie del_from_client_hash(source_p->name, source_p); remove_client_from_list(source_p); + scache_split(source_p->serv->nameinfo); SetDead(source_p); @@ -1417,7 +1546,7 @@ exit_local_server(struct Client *client_p, struct Client *source_p, struct Clien /* Always show source here, so the server notices show * which side initiated the split -- jilles */ - rb_snprintf(newcomment, sizeof(newcomment), "by %s: %s", + snprintf(newcomment, sizeof(newcomment), "by %s: %s", from == source_p ? me.name : from->name, comment); if (!IsIOError(source_p)) sendto_one(source_p, "SQUIT %s :%s", use_id(source_p), @@ -1469,7 +1598,7 @@ exit_local_server(struct Client *client_p, struct Client *source_p, struct Clien /* - * This assumes IsPerson(source_p) == TRUE && MyConnect(source_p) == TRUE + * This assumes IsPerson(source_p) == true && MyConnect(source_p) == true */ static int @@ -1544,7 +1673,7 @@ exit_local_client(struct Client *client_p, struct Client *source_p, struct Clien ** ** CLIENT_EXITED if (client_p == source_p) ** 0 if (client_p != source_p) -*/ + */ int exit_client(struct Client *client_p, /* The local client originating the * exit or NULL, if this exit is @@ -1558,6 +1687,8 @@ exit_client(struct Client *client_p, /* The local client originating the const char *comment /* Reason for the exit */ ) { + int ret = -1; + hook_data_client_exit hdata; if(IsClosing(source_p)) return -1; @@ -1578,23 +1709,25 @@ exit_client(struct Client *client_p, /* The local client originating the { /* Local clients of various types */ if(IsPerson(source_p)) - return exit_local_client(client_p, source_p, from, comment); + ret = exit_local_client(client_p, source_p, from, comment); else if(IsServer(source_p)) - return exit_local_server(client_p, source_p, from, comment); + ret = exit_local_server(client_p, source_p, from, comment); /* IsUnknown || IsConnecting || IsHandShake */ else if(!IsReject(source_p)) - return exit_unknown_client(client_p, source_p, from, comment); + ret = exit_unknown_client(client_p, source_p, from, comment); } else { /* Remotes */ if(IsPerson(source_p)) - return exit_remote_client(client_p, source_p, from, comment); + ret = exit_remote_client(client_p, source_p, from, comment); else if(IsServer(source_p)) - return exit_remote_server(client_p, source_p, from, comment); + ret = exit_remote_server(client_p, source_p, from, comment); } - return -1; + call_hook(h_after_client_exit, NULL); + + return ret; } /* @@ -1701,11 +1834,11 @@ show_ip(struct Client *source_p, struct Client *target_p) * to local opers. */ if(!ConfigFileEntry.hide_spoof_ips && - (source_p == NULL || MyOper(source_p))) + (source_p == NULL || HasPrivilege(source_p, "auspex:hostname"))) return 1; return 0; } - else if(IsDynSpoof(target_p) && (source_p != NULL && !IsOper(source_p))) + else if(IsDynSpoof(target_p) && (source_p != NULL && !HasPrivilege(source_p, "auspex:hostname"))) return 0; else return 1; @@ -1799,21 +1932,24 @@ free_user(struct User *user, struct Client *client_p) { if(user->away) rb_free((char *) user->away); + rb_free(user->opername); + if (user->privset) + privilegeset_unref(user->privset); /* * sanity check */ if(user->refcnt < 0 || user->invited.head || user->channel.head) { sendto_realops_snomask(SNO_GENERAL, L_ALL, - "* %#lx user (%s!%s@%s) %#lx %#lx %#lx %lu %d *", - (unsigned long) client_p, + "* %p user (%s!%s@%s) %p %p %p %lu %d *", + client_p, client_p ? client_p-> name : "", client_p->username, client_p->host, - (unsigned long) user, - (unsigned long) user->invited.head, - (unsigned long) user->channel.head, + user, + user->invited.head, + user->channel.head, rb_dlink_list_length(&user->channel), user->refcnt); s_assert(!user->refcnt); @@ -1860,19 +1996,21 @@ init_uid(void) char * generate_uid(void) { + static int flipped = 0; int i; +uid_restart: for(i = 8; i > 3; i--) { if(current_uid[i] == 'Z') { current_uid[i] = '0'; - return current_uid; + goto out; } else if(current_uid[i] != '9') { current_uid[i]++; - return current_uid; + goto out; } else current_uid[i] = 'A'; @@ -1882,11 +2020,18 @@ generate_uid(void) if(current_uid[3] == 'Z') { current_uid[i] = 'A'; - s_assert(0); + flipped = 1; } else current_uid[i]++; - +out: + /* if this happens..well, i'm not sure what to say, but lets handle it correctly */ + if(rb_unlikely(flipped)) + { + /* this slows down uid generation a bit... */ + if(find_id(current_uid) != NULL) + goto uid_restart; + } return current_uid; } @@ -1944,13 +2089,14 @@ close_connection(struct Client *client_p) else ServerStats.is_ni++; + client_release_connids(client_p); + if(client_p->localClient->F != NULL) { /* attempt to flush any pending dbufs. Evil, but .. -- adrian */ if(!IsIOError(client_p)) send_queued(client_p); - del_from_cli_connid_hash(client_p); rb_close(client_p->localClient->F); client_p->localClient->F = NULL; } @@ -1990,7 +2136,7 @@ error_exit_client(struct Client *client_p, int error) { if(error == 0) { - sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) && !IsServer(client_p) ? L_NETWIDE : L_ALL, + sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Server %s closed the connection", client_p->name); @@ -1999,7 +2145,7 @@ error_exit_client(struct Client *client_p, int error) } else { - sendto_realops_snomask(SNO_GENERAL, is_remote_connect(client_p) && !IsServer(client_p) ? L_NETWIDE : L_ALL, + sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Lost connection to %s: %s", client_p->name, strerror(current_error)); ilog(L_SERVER, "Lost connection to %s: %s", @@ -2010,7 +2156,7 @@ error_exit_client(struct Client *client_p, int error) if(error == 0) rb_strlcpy(errmsg, "Remote host closed the connection", sizeof(errmsg)); else - rb_snprintf(errmsg, sizeof(errmsg), "Read error: %s", strerror(current_error)); + snprintf(errmsg, sizeof(errmsg), "Read error: %s", strerror(current_error)); exit_client(client_p, client_p, &me, errmsg); }