Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/VibeDevelopers/Comet.
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730/* * ircd-ratbox: A slightly useful ircd. * s_user.c: User related functions. * * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center * Copyright (C) 1996-2002 Hybrid Development Team * Copyright (C) 2002-2005 ircd-ratbox development team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */
#include "stdinc.h"#include "s_user.h"#include "channel.h"#include "class.h"#include "client.h"#include "hash.h"#include "match.h"#include "ircd.h"#include "listener.h"#include "msg.h"#include "numeric.h"#include "s_conf.h"#include "s_newconf.h"#include "logger.h"#include "s_serv.h"#include "s_stats.h"#include "scache.h"#include "send.h"#include "supported.h"#include "whowas.h"#include "packet.h"#include "reject.h"#include "cache.h"#include "hook.h"#include "monitor.h"#include "snomask.h"#include "substitution.h"#include "chmode.h"#include "s_assert.h"
static void report_and_set_user_flags(struct Client *, struct ConfItem *);void user_welcome(struct Client *source_p);
char umodebuf[128];
static int orphaned_umodes = 0;int user_modes[256] = { /* 0x00 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0F */ /* 0x10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x1F */ /* 0x20 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x2F */ /* 0x30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x3F */ 0, /* @ */ 0, /* A */ UMODE_BOT, /* B */ 0, /* C */ UMODE_DEAF, /* D */ 0, /* E */ 0, /* F */ 0, /* G */ 0, /* H */ 0, /* I */ 0, /* J */ 0, /* K */ 0, /* L */ 0, /* M */ 0, /* N */ 0, /* O */ 0, /* P */ UMODE_NOFORWARD, /* Q */ 0, /* R */ UMODE_SERVICE, /* S */ 0, /* T */ 0, /* U */ 0, /* V */ UMODE_WHOISNOTICE, /* W */ 0, /* X */ 0, /* Y */ UMODE_SECURE, /* Z */ /* 0x5B */ 0, 0, 0, 0, 0, 0, /* 0x60 */ UMODE_ADMIN, /* a */ 0, /* b */ 0, /* c */ 0, /* d */ 0, /* e */ 0, /* f */ 0, /* g */ 0, /* h */ UMODE_INVISIBLE, /* i */ 0, /* j */ 0, /* k */ 0, /* l */ 0, /* m */ 0, /* n */ UMODE_OPER, /* o */ 0, /* p */ 0, /* q */ 0, /* r */ UMODE_SERVNOTICE, /* s */ 0, /* t */ 0, /* u */ 0, /* v */ UMODE_WALLOP, /* w */ 0, /* x */ 0, /* y */ UMODE_OPERWALL, /* z */ /* 0x7B */ 0, 0, 0, 0, 0, /* 0x7F */ /* 0x80 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x9F */ /* 0x90 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x9F */ /* 0xA0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xAF */ /* 0xB0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xBF */ /* 0xC0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xCF */ /* 0xD0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xDF */ /* 0xE0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xEF */ /* 0xF0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 0xFF */};/* *INDENT-ON* */
/* * show_lusers - * * inputs - pointer to client * output - * side effects - display to client user counts etc. */voidshow_lusers(struct Client *source_p){ if(rb_dlink_list_length(&lclient_list) > (unsigned long)MaxClientCount) MaxClientCount = rb_dlink_list_length(&lclient_list);
if((rb_dlink_list_length(&lclient_list) + rb_dlink_list_length(&serv_list)) > (unsigned long)MaxConnectionCount) MaxConnectionCount = rb_dlink_list_length(&lclient_list) + rb_dlink_list_length(&serv_list);
sendto_one_numeric(source_p, RPL_LUSERCLIENT, form_str(RPL_LUSERCLIENT), (Count.total - Count.invisi), Count.invisi, (int)rb_dlink_list_length(&global_serv_list));
if(rb_dlink_list_length(&oper_list) > 0) sendto_one_numeric(source_p, RPL_LUSEROP, form_str(RPL_LUSEROP), (int)rb_dlink_list_length(&oper_list));
if(rb_dlink_list_length(&unknown_list) > 0) sendto_one_numeric(source_p, RPL_LUSERUNKNOWN, form_str(RPL_LUSERUNKNOWN), (int)rb_dlink_list_length(&unknown_list));
if(rb_dlink_list_length(&global_channel_list) > 0) sendto_one_numeric(source_p, RPL_LUSERCHANNELS, form_str(RPL_LUSERCHANNELS), rb_dlink_list_length(&global_channel_list));
sendto_one_numeric(source_p, RPL_LUSERME, form_str(RPL_LUSERME), (int)rb_dlink_list_length(&lclient_list), (int)rb_dlink_list_length(&serv_list));
sendto_one_numeric(source_p, RPL_LOCALUSERS, form_str(RPL_LOCALUSERS), (int)rb_dlink_list_length(&lclient_list), Count.max_loc, (int)rb_dlink_list_length(&lclient_list), Count.max_loc);
sendto_one_numeric(source_p, RPL_GLOBALUSERS, form_str(RPL_GLOBALUSERS), Count.total, Count.max_tot, Count.total, Count.max_tot);
sendto_one_numeric(source_p, RPL_STATSCONN, form_str(RPL_STATSCONN), MaxConnectionCount, MaxClientCount, Count.totalrestartcount);}
/* check if we should exit a client due to authd decision * inputs - client server, client connecting * outputs - true if exited, false if not * side effects - messages/exits client if authd rejected and not exempt */static boolauthd_check(struct Client *client_p, struct Client *source_p){ struct ConfItem *aconf = source_p->localClient->att_conf; rb_dlink_list varlist = { NULL, NULL, 0 }; bool reject = false; char *reason;
if(source_p->preClient->auth.accepted == true) return reject;
substitution_append_var(&varlist, "nick", source_p->name); substitution_append_var(&varlist, "ip", source_p->sockhost); substitution_append_var(&varlist, "host", source_p->host); substitution_append_var(&varlist, "dnsbl-host", source_p->preClient->auth.data); substitution_append_var(&varlist, "network-name", ServerInfo.network_name); reason = substitution_parse(source_p->preClient->auth.reason, &varlist);
switch(source_p->preClient->auth.cause) { case 'B': /* DNSBL */ { struct DNSBLEntry *entry; char *dnsbl_name = source_p->preClient->auth.data;
if(dnsbl_stats != NULL) if((entry = rb_dictionary_retrieve(dnsbl_stats, dnsbl_name)) != NULL) entry->hits++;
if(IsExemptKline(source_p) || IsConfExemptDNSBL(aconf)) { sendto_one_notice(source_p, ":*** Your IP address %s is listed in %s, but you are exempt", source_p->sockhost, dnsbl_name); break; }
sendto_realops_snomask(SNO_REJ, L_NETWIDE, "Listed on DNSBL %s: %s (%s@%s) [%s] [%s]", dnsbl_name, source_p->name, source_p->username, source_p->host, IsIPSpoof(source_p) ? "255.255.255.255" : source_p->sockhost, source_p->info);
sendto_one(source_p, form_str(ERR_YOUREBANNEDCREEP), me.name, source_p->name, reason);
sendto_one_notice(source_p, ":*** Your IP address %s is listed in %s", source_p->sockhost, dnsbl_name); add_reject(source_p, NULL, NULL, NULL, "Banned (listed in a DNSBL)"); exit_client(client_p, source_p, &me, "Banned (listed in a DNSBL)"); reject = true; } break; case 'O': /* OPM */ { char *proxy = source_p->preClient->auth.data; char *port = strrchr(proxy, ':');
if(port == NULL) { /* This shouldn't happen, better tell the ops... */ ierror("authd sent us a malformed OPM string %s", proxy); sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "authd sent us a malformed OPM string %s", proxy); break; }
/* Terminate the proxy type */ *(port++) = '\0';
if(IsExemptKline(source_p) || IsConfExemptProxy(aconf)) { sendto_one_notice(source_p, ":*** Your IP address %s has been detected as an open proxy (type %s, port %s), but you are exempt", source_p->sockhost, proxy, port); break; } sendto_realops_snomask(SNO_REJ, L_NETWIDE, "Open proxy %s/%s: %s (%s@%s) [%s] [%s]", proxy, port, source_p->name, source_p->username, source_p->host, IsIPSpoof(source_p) ? "255.255.255.255" : source_p->sockhost, source_p->info);
sendto_one(source_p, form_str(ERR_YOUREBANNEDCREEP), me.name, source_p->name, reason);
sendto_one_notice(source_p, ":*** Your IP address %s has been detected as an open proxy (type %s, port %s)", source_p->sockhost, proxy, port); add_reject(source_p, NULL, NULL, NULL, "Banned (Open proxy)"); exit_client(client_p, source_p, &me, "Banned (Open proxy)"); reject = true; } break; default: /* Unknown, but handle the case properly */ if(IsExemptKline(source_p)) { sendto_one_notice(source_p, ":*** You were rejected, but you are exempt (reason: %s)", reason); break; } sendto_realops_snomask(SNO_REJ, L_NETWIDE, "Rejected by authentication system (reason %s): %s (%s@%s) [%s] [%s]", reason, source_p->name, source_p->username, source_p->host, IsIPSpoof(source_p) ? "255.255.255.255" : source_p->sockhost, source_p->info);
sendto_one(source_p, form_str(ERR_YOUREBANNEDCREEP), me.name, source_p->name, reason);
sendto_one_notice(source_p, ":*** Rejected by authentication system: %s", reason); add_reject(source_p, NULL, NULL, NULL, "Banned (authentication system)"); exit_client(client_p, source_p, &me, "Banned (authentication system)"); reject = true; break; }
if(reject) ServerStats.is_ref++;
substitution_free(&varlist);
return reject;}
/*** register_local_user** This function is called when both NICK and USER messages** have been accepted for the client, in whatever order. Only** after this, is the USER message propagated.**** NICK's must be propagated at once when received, although** it would be better to delay them too until full info is** available. Doing it is not so simple though, would have** to implement the following:**** (actually it has been implemented already for a while) -orabidoo**** 1) user telnets in and gives only "NICK foobar" and waits** 2) another user far away logs in normally with the nick** "foobar" (quite legal, as this server didn't propagate** it).** 3) now this server gets nick "foobar" from outside, but** has alread the same defined locally. Current server** would just issue "KILL foobar" to clean out dups. But,** this is not fair. It should actually request another** nick from local user or kill him/her... */intregister_local_user(struct Client *client_p, struct Client *source_p){ struct ConfItem *aconf, *xconf; char tmpstr2[BUFSIZE]; char ipaddr[HOSTIPLEN]; char notildeusername[USERLEN + 1]; int status, umodes;
s_assert(NULL != source_p); s_assert(MyConnect(source_p));
if(source_p == NULL) return -1;
if(IsAnyDead(source_p)) return -1;
if(ConfigFileEntry.ping_cookie) { if(!(source_p->flags & FLAGS_PINGSENT) && source_p->localClient->random_ping == 0) { source_p->localClient->random_ping = (uint32_t)(((rand() * rand()) << 1) | 1); sendto_one(source_p, "PING :%08X", (unsigned int) source_p->localClient->random_ping); source_p->flags |= FLAGS_PINGSENT; return -1; } if(!(source_p->flags & FLAGS_PING_COOKIE)) { return -1; } }
/* hasnt finished client cap negotiation */ if(source_p->flags & FLAGS_CLICAP) return -1;
/* Waiting on authd */ if(source_p->preClient->auth.cid) return -1;
/* Set firsttime here so that post_registration_delay works from registration, * rather than initial connection. */ source_p->localClient->firsttime = client_p->localClient->last = rb_current_time();
if (!IsGotId(source_p)) { const char *haystack; int o = 0;
haystack = source_p->username;
for (int i = 0; haystack[i] != '\0'; i++) if (haystack[i] != '[') notildeusername[o++] = haystack[i];
notildeusername[o] = '\0';
rb_strlcpy(source_p->username, "~", sizeof(source_p->username)); rb_strlcat(source_p->username, notildeusername, sizeof(source_p->username)); } else rb_strlcpy(notildeusername, source_p->username, sizeof notildeusername);
/* valid user name check */
if(!valid_username(source_p->username)) { sendto_realops_snomask(SNO_REJ, L_NETWIDE, "Invalid username: %s (%s@%s)", source_p->name, source_p->username, source_p->host);
const char *illegal_name_long_client_message = ConfigFileEntry.illegal_name_long_client_message; const char *illegal_name_short_client_message = ConfigFileEntry.illegal_name_short_client_message;
if (illegal_name_long_client_message == NULL) illegal_name_long_client_message = "Your username is invalid. Please make sure that your username contains " "only alphanumeric characters."; if (illegal_name_short_client_message == NULL) illegal_name_short_client_message = "Invalid username";
ServerStats.is_ref++; sendto_one_notice(source_p, ":*** %s", illegal_name_long_client_message); sprintf(tmpstr2, "%s [%s]", illegal_name_short_client_message, source_p->username); exit_client(client_p, source_p, &me, tmpstr2); return (CLIENT_EXITED); }
/* end of valid user name check */
if((status = check_client(client_p, source_p, notildeusername)) < 0) return (CLIENT_EXITED);
/* Apply nick override */ if(*source_p->preClient->spoofnick) { char note[NAMELEN + 10];
del_from_client_hash(source_p->name, source_p); rb_strlcpy(source_p->name, source_p->preClient->spoofnick, NICKLEN + 1); add_to_client_hash(source_p->name, source_p);
snprintf(note, sizeof(note), "Nick: %s", source_p->name); rb_note(source_p->localClient->F, note); }
if(!valid_hostname(source_p->host)) { const char *illegal_hostname_client_message = ConfigFileEntry.illegal_hostname_client_message;
if (illegal_hostname_client_message == NULL) illegal_hostname_client_message = "You have an illegal character in your hostname.";
sendto_one_notice(source_p, ":*** Notice -- %s", illegal_hostname_client_message);
rb_strlcpy(source_p->host, source_p->sockhost, sizeof(source_p->host)); }
aconf = source_p->localClient->att_conf;
if(aconf == NULL) { const char *not_authorised_client_message = ConfigFileEntry.not_authorised_client_message;
if (not_authorised_client_message == NULL) not_authorised_client_message = "You are not authorised to access this server.";
exit_client(client_p, source_p, &me, not_authorised_client_message); return (CLIENT_EXITED); }
if(IsConfSSLNeeded(aconf) && !IsSecure(source_p)) { const char *ssltls_only_client_message = ConfigFileEntry.ssltls_only_client_message;
if (ssltls_only_client_message == NULL) ssltls_only_client_message = "You need to use SSL/TLS to use this server.";
ServerStats.is_ref++; sendto_one_notice(source_p, ":*** Notice -- %s", ssltls_only_client_message);
exit_client(client_p, source_p, &me, ssltls_only_client_message); return (CLIENT_EXITED); }
if(IsSCTP(source_p) && !IsConfAllowSCTP(aconf)) { const char *sctp_forbidden_client_message = ConfigFileEntry.sctp_forbidden_client_message;
if (sctp_forbidden_client_message == NULL) sctp_forbidden_client_message = "You are not allowed to use SCTP on this server.";
ServerStats.is_ref++; sendto_one_notice(source_p, ":*** Notice -- %s", sctp_forbidden_client_message);
exit_client(client_p, source_p, &me, sctp_forbidden_client_message); return (CLIENT_EXITED); }
if(!IsGotId(source_p)) { if(IsNeedIdentd(aconf)) {
const char *identd_only_client_message = ConfigFileEntry.identd_only_client_message;
if (identd_only_client_message == NULL) identd_only_client_message = "You need to install identd to use this server.";
ServerStats.is_ref++; sendto_one_notice(source_p, ":*** Notice -- %s", identd_only_client_message);
exit_client(client_p, source_p, &me, identd_only_client_message); return (CLIENT_EXITED); }
/* dont replace username if its supposed to be spoofed --fl */ if (IsNoTilde(aconf) && (!IsConfDoSpoofIp(aconf) || !strchr(aconf->info.name, '@'))) { rb_strlcpy(source_p->username, notildeusername, sizeof(source_p->username)); } }
if(IsNeedSasl(aconf) && !*source_p->user->suser) {
const char *sasl_only_client_message = ConfigFileEntry.sasl_only_client_message;
if (sasl_only_client_message == NULL) sasl_only_client_message = "You need to identify via SASL to use this server.";
ServerStats.is_ref++; sendto_one_notice(source_p, ":*** Notice -- %s", sasl_only_client_message);
exit_client(client_p, source_p, &me, sasl_only_client_message); return (CLIENT_EXITED); }
/* password check */ if(!EmptyString(aconf->passwd)) { const char *encr;
if(EmptyString(source_p->localClient->passwd)) encr = ""; else if(IsConfEncrypted(aconf)) encr = rb_crypt(source_p->localClient->passwd, aconf->passwd); else encr = source_p->localClient->passwd;
if(encr == NULL || strcmp(encr, aconf->passwd)) { ServerStats.is_ref++; sendto_one(source_p, form_str(ERR_PASSWDMISMATCH), me.name, source_p->name); exit_client(client_p, source_p, &me, "Bad Password"); return (CLIENT_EXITED); }
/* clear password only if used now, otherwise send it * to services -- jilles */ if(source_p->localClient->passwd) { memset(source_p->localClient->passwd, 0, strlen(source_p->localClient->passwd)); rb_free(source_p->localClient->passwd); source_p->localClient->passwd = NULL; } }
/* report and set flags (kline exempt etc.) as needed in source_p */ report_and_set_user_flags(source_p, aconf);
/* Limit clients */ /* * We want to be able to have servers and F-line clients * connect, so save room for "buffer" connections. * Smaller servers may want to decrease this, and it should * probably be just a percentage of the MAXCLIENTS... * -Taner */ /* Except "F:" clients */ if(rb_dlink_list_length(&lclient_list) >= (unsigned long)GlobalSetOptions.maxclients && !IsConfExemptLimits(aconf)) { sendto_realops_snomask(SNO_FULL, L_NETWIDE, "Too many clients, rejecting %s[%s].", source_p->name, source_p->host);
const char *server_full_client_message = ConfigFileEntry.server_full_client_message;
if (server_full_client_message == NULL) server_full_client_message = "Sorry, server is full - try later";
ServerStats.is_ref++; exit_client(client_p, source_p, &me, server_full_client_message); return (CLIENT_EXITED); }
/* kline exemption extends to xline too */ if(!IsExemptKline(source_p) && (xconf = find_xline(source_p->info, 1)) != NULL) { ServerStats.is_ref++; sendto_realops_snomask(SNO_BANNED, L_NETWIDE, "Rejecting X-Lined user %s [%s] (%s)", get_client_name(source_p, HIDE_IP), show_ip(NULL, source_p) ? source_p->sockhost : "255.255.255.255", xconf->host);
add_reject(source_p, xconf->host, NULL, NULL, NULL); exit_client(client_p, source_p, &me, "Bad user info"); return CLIENT_EXITED; }
/* authd rejection check */ if(authd_check(client_p, source_p)) return CLIENT_EXITED;
/* Store original hostname -- jilles */ rb_strlcpy(source_p->orighost, source_p->host, HOSTLEN + 1);
/* Spoof user@host */ if(*source_p->preClient->spoofuser) rb_strlcpy(source_p->username, source_p->preClient->spoofuser, USERLEN + 1); if(*source_p->preClient->spoofhost) { rb_strlcpy(source_p->host, source_p->preClient->spoofhost, HOSTLEN + 1); if (irccmp(source_p->host, source_p->orighost)) SetDynSpoof(source_p); }
umodes = ConfigFileEntry.default_umodes & ~aconf->umodes_mask; umodes |= aconf->umodes; umodes &= ~ConfigFileEntry.oper_only_umodes; umodes &= ~orphaned_umodes; source_p->umodes |= umodes;
call_hook(h_new_local_user, source_p);
/* If they have died in send_* or were thrown out by the * new_local_user hook don't do anything. */ if(IsAnyDead(source_p)) return CLIENT_EXITED;
/* To avoid inconsistencies, do not abort the registration * starting from this point -- jilles */ rb_inet_ntop_sock((struct sockaddr *)&source_p->localClient->ip, ipaddr, sizeof(ipaddr));
sendto_realops_snomask(SNO_CCONN, L_ALL, "Client connecting: %s (%s@%s) [%s] {%s} <%s> [%s]", source_p->name, source_p->username, source_p->orighost, show_ip(NULL, source_p) ? ipaddr : "255.255.255.255", get_client_class(source_p), *source_p->user->suser ? source_p->user->suser : "*", source_p->info);
sendto_realops_snomask(SNO_CCONNEXT, L_ALL, "CLICONN %s %s %s %s %s %s 0 %s %s", source_p->name, source_p->username, source_p->orighost, show_ip(NULL, source_p) ? ipaddr : "255.255.255.255", get_client_class(source_p), /* mirc can sometimes send ips here */ show_ip(NULL, source_p) ? source_p->localClient->fullcaps : "<hidden> <hidden>", *source_p->user->suser ? source_p->user->suser : "*", source_p->info);
add_to_hostname_hash(source_p->orighost, source_p);
/* Allocate a UID if it was not previously allocated. * If this already occured, it was probably during SASL auth... */ if(!*source_p->id) { rb_strlcpy(source_p->id, generate_uid(), sizeof(source_p->id)); add_to_id_hash(source_p->id, source_p); }
if (IsSecure(source_p)) source_p->umodes |= UMODE_SECURE;
if (source_p->umodes & UMODE_INVISIBLE) Count.invisi++;
s_assert(!IsClient(source_p)); rb_dlinkMoveNode(&source_p->localClient->tnode, &unknown_list, &lclient_list); SetClient(source_p);
source_p->servptr = &me; rb_dlinkAdd(source_p, &source_p->lnode, &source_p->servptr->serv->users);
/* Increment our total user count here */ if(++Count.total > Count.max_tot) Count.max_tot = Count.total;
Count.totalrestartcount++;
s_assert(source_p->localClient != NULL);
if(rb_dlink_list_length(&lclient_list) > (unsigned long)Count.max_loc) { Count.max_loc = rb_dlink_list_length(&lclient_list); if(!(Count.max_loc % 10)) sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "New Max Local Clients: %d", Count.max_loc); }
/* they get a reduced limit */ if(find_tgchange(source_p->sockhost)) source_p->localClient->targets_free = TGCHANGE_INITIAL_LOW; else source_p->localClient->targets_free = TGCHANGE_INITIAL;
monitor_signon(source_p); user_welcome(source_p);
free_pre_client(source_p);
introduce_client(client_p, source_p, source_p->user, source_p->name, 1); return 0;}
/* * introduce_clients * * inputs - * output - * side effects - This common function introduces a client to the rest * of the net, either from a local client connect or * from a remote connect. */voidintroduce_client(struct Client *client_p, struct Client *source_p, struct User *user, const char *nick, int use_euid){ char ubuf[BUFSIZE]; struct Client *identifyservice_p; char *p; hook_data_umode_changed hdata; hook_data_client hdata2;
if(MyClient(source_p)) send_umode(source_p, source_p, 0, ubuf); else send_umode(NULL, source_p, 0, ubuf);
if(!*ubuf) { ubuf[0] = '+'; ubuf[1] = '\0'; }
s_assert(has_id(source_p));
if (use_euid) sendto_server(client_p, NULL, CAP_EUID | CAP_TS6, NOCAPS, ":%s EUID %s %d %ld %s %s %s %s %s %s %s :%s", source_p->servptr->id, nick, source_p->hopcount + 1, (long) source_p->tsinfo, ubuf, source_p->username, source_p->host, IsIPSpoof(source_p) ? "0" : source_p->sockhost, source_p->id, IsDynSpoof(source_p) ? source_p->orighost : "*", EmptyString(source_p->user->suser) ? "*" : source_p->user->suser, source_p->info);
sendto_server(client_p, NULL, CAP_TS6, use_euid ? CAP_EUID : NOCAPS, ":%s UID %s %d %ld %s %s %s %s %s :%s", source_p->servptr->id, nick, source_p->hopcount + 1, (long) source_p->tsinfo, ubuf, source_p->username, source_p->host, IsIPSpoof(source_p) ? "0" : source_p->sockhost, source_p->id, source_p->info);
if(!EmptyString(source_p->certfp)) sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s ENCAP * CERTFP :%s", use_id(source_p), source_p->certfp);
if (IsDynSpoof(source_p)) { sendto_server(client_p, NULL, CAP_TS6, use_euid ? CAP_EUID : NOCAPS, ":%s ENCAP * REALHOST %s", use_id(source_p), source_p->orighost); }
if (!EmptyString(source_p->user->suser)) { sendto_server(client_p, NULL, CAP_TS6, use_euid ? CAP_EUID : NOCAPS, ":%s ENCAP * LOGIN %s", use_id(source_p), source_p->user->suser); }
if(MyConnect(source_p) && source_p->localClient->passwd) { if (!EmptyString(ConfigFileEntry.identifyservice) && !EmptyString(ConfigFileEntry.identifycommand)) { /* use user@server */ p = strchr(ConfigFileEntry.identifyservice, '@'); if (p != NULL) identifyservice_p = find_named_client(p + 1); else identifyservice_p = NULL; if (identifyservice_p != NULL) { if (!EmptyString(source_p->localClient->auth_user)) sendto_one(identifyservice_p, ":%s PRIVMSG %s :%s %s %s", get_id(source_p, identifyservice_p), ConfigFileEntry.identifyservice, ConfigFileEntry.identifycommand, source_p->localClient->auth_user, source_p->localClient->passwd); else sendto_one(identifyservice_p, ":%s PRIVMSG %s :%s %s", get_id(source_p, identifyservice_p), ConfigFileEntry.identifyservice, ConfigFileEntry.identifycommand, source_p->localClient->passwd); } } memset(source_p->localClient->passwd, 0, strlen(source_p->localClient->passwd)); rb_free(source_p->localClient->passwd); source_p->localClient->passwd = NULL; }
/* let modules providing usermodes know that we've got a new user, * why is this here? -- well, some modules need to be able to send out new * information about a client, so this was the best place to do it * --nenolod */ hdata.client = source_p; hdata.oldumodes = 0; hdata.oldsnomask = 0; call_hook(h_umode_changed, &hdata);
/* On the other hand, some modules need to know when a client is * being introduced, period. * --gxti */ hdata2.client = client_p; hdata2.target = source_p; call_hook(h_introduce_client, &hdata2);}
/* * valid_hostname - check hostname for validity * * Inputs - pointer to user * Output - true if valid, false if not * Side effects - NONE * * NOTE: this doesn't allow a hostname to begin with a dot and * will not allow more dots than chars. */boolvalid_hostname(const char *hostname){ const char *p = hostname, *last_slash = 0; int found_sep = 0;
s_assert(NULL != p);
if(hostname == NULL) return false;
if(!strcmp(hostname, "localhost")) return true;
if('.' == *p || ':' == *p || '/' == *p) return false;
while (*p) { if(!IsHostChar(*p)) return false; if(*p == '.' || *p == ':') found_sep++; else if(*p == '/') { found_sep++; last_slash = p; } p++; }
if(found_sep == 0) return false;
if(last_slash && IsDigit(last_slash[1])) return false;
return true;}
/* * valid_username - check username for validity * * Inputs - pointer to user * Output - true if valid, false if not * Side effects - NONE * * Absolutely always reject any '*' '!' '?' '@' in an user name * reject any odd control characters names. * Allow '.' in username to allow for "first.last" * style of username */boolvalid_username(const char *username){ int dots = 0; const char *p = username;
s_assert(NULL != p);
if(username == NULL) return false;
if('~' == *p) ++p;
/* reject usernames that don't start with an alphanum * i.e. reject jokers who have '-@somehost' or '.@somehost' * or "-hi-@somehost", "h-----@somehost" would still be accepted. */ if(!IsAlNum(*p)) return false;
while (*++p) { if((*p == '.') && ConfigFileEntry.dots_in_ident) { dots++; if(dots > ConfigFileEntry.dots_in_ident) return false; if(!IsUserChar(p[1])) return false; } else if(!IsUserChar(*p)) return false; } return true;}
/* report_and_set_user_flags * * Inputs - pointer to source_p * - pointer to aconf for this user * Output - NONE * Side effects - * Report to user any special flags they are getting, and set them. */
static voidreport_and_set_user_flags(struct Client *source_p, struct ConfItem *aconf){ /* If this user is being spoofed, tell them so */ if(IsConfDoSpoofIp(aconf)) { sendto_one_notice(source_p, ":*** Spoofing your IP"); }
/* If this user is in the exception class, Set it "E lined" */ if(IsConfExemptKline(aconf)) { SetExemptKline(source_p); sendto_one_notice(source_p, ":*** You are exempt from K/X lines"); }
if(IsConfExemptDNSBL(aconf)) /* kline exempt implies this, don't send both */ if(!IsConfExemptKline(aconf)) sendto_one_notice(source_p, ":*** You are exempt from DNSBL listings");
/* If this user is exempt from user limits set it F lined" */ if(IsConfExemptLimits(aconf)) { sendto_one_notice(source_p, ":*** You are exempt from user limits"); }
if(IsConfExemptFlood(aconf)) { SetExemptFlood(source_p); sendto_one_notice(source_p, ":*** You are exempt from flood limits"); }
if(IsConfExemptSpambot(aconf)) { SetExemptSpambot(source_p); sendto_one_notice(source_p, ":*** You are exempt from spambot checks"); }
if(IsConfExemptJupe(aconf)) { SetExemptJupe(source_p); sendto_one_notice(source_p, ":*** You are exempt from juped channel warnings"); }
if(IsConfExemptResv(aconf)) { SetExemptResv(source_p); sendto_one_notice(source_p, ":*** You are exempt from resvs"); }
if(IsConfExemptShide(aconf)) { SetExemptShide(source_p); sendto_one_notice(source_p, ":*** You are exempt from serverhiding"); }
if(IsConfExtendChans(aconf)) { SetExtendChans(source_p); sendto_one_notice(source_p, ":*** You are exempt from normal channel limits"); }}
voidreport_priv_change(struct Client *client, struct PrivilegeSet *old, struct PrivilegeSet *new){ struct privset_diff diff = privilegeset_diff(old, new);
hook_data_priv_change hdata = { .client = client, .new = new, .old = old, .unchanged = diff.unchanged, .added = diff.added, .removed = diff.removed, }; call_hook(h_priv_change, &hdata);}
static voidshow_other_user_mode(struct Client *source_p, struct Client *target_p){ int i; char buf[BUFSIZE]; char *m;
m = buf; *m++ = '+';
for (i = 0; i < 128; i++) /* >= 127 is extended ascii */ if (target_p->umodes & user_modes[i]) *m++ = (char) i; *m = '\0';
if (MyConnect(target_p) && target_p->snomask != 0) sendto_one_notice(source_p, ":Modes for %s are %s %s", target_p->name, buf, construct_snobuf(target_p->snomask)); else sendto_one_notice(source_p, ":Modes for %s are %s", target_p->name, buf);}
/* * user_mode - set get current users mode * * m_umode() added 15/10/91 By Darren Reed. * parv[1] - username to change mode for * parv[2] - modes to change */intuser_mode(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]){ int flag; int i; char *m; const char *pm; struct Client *target_p; int what, setflags; bool badflag = false; /* Only send one bad flag notice */ bool showsnomask = false; unsigned int setsnomask; char buf[BUFSIZE]; hook_data_umode_changed hdata;
what = MODE_ADD;
if(parc < 2) { sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "MODE"); return 0; }
if((target_p = MyClient(source_p) ? find_named_person(parv[1]) : find_person(parv[1])) == NULL) { if(MyConnect(source_p)) sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), parv[1]); return 0; }
/* Dont know why these were commented out.. * put them back using new sendto() funcs */
if(IsServer(source_p)) { sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "*** Mode for User %s from %s", parv[1], source_p->name); return 0; }
if(source_p != target_p) { if (HasPrivilege(source_p, "auspex:umodes") && parc < 3) show_other_user_mode(source_p, target_p); else sendto_one(source_p, form_str(ERR_USERSDONTMATCH), me.name, source_p->name); return 0; }
if(parc < 3) { m = buf; *m++ = '+';
for (i = 0; i < 128; i++) /* >= 127 is extended ascii */ if (source_p->umodes & user_modes[i]) *m++ = (char) i;
*m = '\0'; sendto_one_numeric(source_p, RPL_UMODEIS, form_str(RPL_UMODEIS), buf);
if (source_p->snomask != 0) sendto_one_numeric(source_p, RPL_SNOMASK, form_str(RPL_SNOMASK), construct_snobuf(source_p->snomask));
return 0; }
/* find flags already set for user */ setflags = source_p->umodes; setsnomask = source_p->snomask;
/* * parse mode change string(s) */ for (pm = parv[2]; *pm; pm++) switch (*pm) { case '+': what = MODE_ADD; break; case '-': what = MODE_DEL; break;
case 'o': if(what == MODE_ADD) { if(IsServer(client_p) && !IsOper(source_p)) { ++Count.oper; SetOper(source_p); rb_dlinkAddAlloc(source_p, &oper_list); } } else { /* Only decrement the oper counts if an oper to begin with * found by Pat Szuta, Perly , perly@xnet.com */
if(!IsOper(source_p)) break;
ClearOper(source_p);
Count.oper--;
if(MyConnect(source_p)) { source_p->umodes &= ~ConfigFileEntry.oper_only_umodes; rb_dlinkFindDestroy(source_p, &local_oper_list); }
if(source_p->user->opername != NULL) { rb_free(source_p->user->opername); source_p->user->opername = NULL; }
if(source_p->user->privset != NULL) { report_priv_change(source_p, source_p->user->privset, NULL);
privilegeset_unref(source_p->user->privset); source_p->user->privset = NULL; }
rb_dlinkFindDestroy(source_p, &oper_list); } break;
/* we may not get these, * but they shouldnt be in default */
/* can only be set on burst */ case 'S': case 'Z': case ' ': case '\n': case '\r': case '\t': break;
case 's': if (MyConnect(source_p)) { if((ConfigFileEntry.oper_only_umodes & UMODE_SERVNOTICE) && (!IsOper(source_p) || !HasPrivilege(source_p, "usermode:servnotice"))) { if (what == MODE_ADD || source_p->umodes & UMODE_SERVNOTICE) badflag = true; continue; } showsnomask = true; if(what == MODE_ADD) { if (parc > 3) source_p->snomask = parse_snobuf_to_mask(source_p->snomask, parv[3]); else source_p->snomask |= SNO_GENERAL; } else source_p->snomask = 0; if (source_p->snomask != 0) source_p->umodes |= UMODE_SERVNOTICE; else source_p->umodes &= ~UMODE_SERVNOTICE; break; } /* FALLTHROUGH */ default: if (MyConnect(source_p) && *pm == 'Q' && !ConfigChannel.use_forward) { badflag = true; break; }
if((flag = user_modes[(unsigned char) *pm])) { if(MyConnect(source_p) && ((!IsOper(source_p) && (ConfigFileEntry.oper_only_umodes & flag)) || (orphaned_umodes & flag))) { if (what == MODE_ADD || source_p->umodes & flag) badflag = true; } else { if(what == MODE_ADD) source_p->umodes |= flag; else source_p->umodes &= ~flag; } } else { if(MyConnect(source_p)) badflag = true; } break; }
if(badflag) sendto_one(source_p, form_str(ERR_UMODEUNKNOWNFLAG), me.name, source_p->name);
if(MyClient(source_p)) { if ((ConfigFileEntry.oper_only_umodes & UMODE_SERVNOTICE) && !HasPrivilege(source_p, "usermode:servnotice")) source_p->umodes &= ~UMODE_SERVNOTICE; if (!(source_p->umodes & UMODE_SERVNOTICE) && source_p->snomask != 0) { source_p->snomask = 0; showsnomask = true; } }
if(MyClient(source_p) && (source_p->snomask & SNO_NCHANGE) && !IsOperN(source_p)) { sendto_one_notice(source_p, ":*** You need oper and nick_changes flag for +s +n"); source_p->snomask &= ~SNO_NCHANGE; /* only tcm's really need this */ }
if(MyClient(source_p) && (source_p->umodes & UMODE_OPERWALL) && !IsOperOperwall(source_p)) { sendto_one_notice(source_p, ":*** You need oper and operwall flag for +z"); source_p->umodes &= ~UMODE_OPERWALL; }
if(MyConnect(source_p) && (source_p->umodes & UMODE_ADMIN) && (!IsOperAdmin(source_p) || IsOperHiddenAdmin(source_p))) { sendto_one_notice(source_p, ":*** You need oper and admin flag for +a"); source_p->umodes &= ~UMODE_ADMIN; }
/* let modules providing usermodes know that we've changed our usermode --nenolod */ hdata.client = source_p; hdata.oldumodes = setflags; hdata.oldsnomask = setsnomask; call_hook(h_umode_changed, &hdata);
if(MyClient(source_p)) source_p->handler = IsOper(source_p) ? OPER_HANDLER : CLIENT_HANDLER;
if(!(setflags & UMODE_INVISIBLE) && IsInvisible(source_p)) ++Count.invisi; if((setflags & UMODE_INVISIBLE) && !IsInvisible(source_p)) --Count.invisi; /* * compare new flags with old flags and send string which * will cause servers to update correctly. */ send_umode_out(client_p, source_p, setflags); if (showsnomask && MyConnect(source_p)) sendto_one_numeric(source_p, RPL_SNOMASK, form_str(RPL_SNOMASK), construct_snobuf(source_p->snomask));
return (0);}
/* * send the MODE string for user (user) to connection client_p * -avalon */voidsend_umode(struct Client *client_p, struct Client *source_p, int old, char *umode_buf){ int i; int flag; char *m; int what = 0;
/* * build a string in umode_buf to represent the change in the user's * mode between the new (source_p->flag) and 'old'. */ m = umode_buf; *m = '\0';
for (i = 0; i < 128; i++) { flag = user_modes[i];
if((flag & old) && !(source_p->umodes & flag)) { if(what == MODE_DEL) *m++ = (char) i; else { what = MODE_DEL; *m++ = '-'; *m++ = (char) i; } } else if(!(flag & old) && (source_p->umodes & flag)) { if(what == MODE_ADD) *m++ = (char) i; else { what = MODE_ADD; *m++ = '+'; *m++ = (char) i; } } } *m = '\0';
if(*umode_buf && client_p) sendto_one(client_p, ":%s MODE %s :%s", source_p->name, source_p->name, umode_buf);}
/* * send_umode_out * * inputs - * output - NONE * side effects - */voidsend_umode_out(struct Client *client_p, struct Client *source_p, int old){ struct Client *target_p; char buf[BUFSIZE]; rb_dlink_node *ptr;
send_umode(NULL, source_p, old, buf);
RB_DLINK_FOREACH(ptr, serv_list.head) { target_p = ptr->data;
if((target_p != client_p) && (target_p != source_p) && (*buf)) { sendto_one(target_p, ":%s MODE %s :%s", get_id(source_p, target_p), get_id(source_p, target_p), buf); } }
if(client_p && MyClient(client_p)) send_umode(client_p, source_p, old, buf);}
/* * user_welcome * * inputs - client pointer to client to welcome * output - NONE * side effects - */voiduser_welcome(struct Client *source_p){ sendto_one_numeric(source_p, RPL_WELCOME, form_str(RPL_WELCOME), ServerInfo.network_name, source_p->name); sendto_one_numeric(source_p, RPL_YOURHOST, form_str(RPL_YOURHOST), get_listener_name(source_p->localClient->listener), ircd_version); sendto_one_numeric(source_p, RPL_CREATED, form_str(RPL_CREATED), creation); sendto_one_numeric(source_p, RPL_MYINFO, form_str(RPL_MYINFO), me.name, ircd_version, umodebuf, cflagsmyinfo);
show_isupport(source_p);
call_hook(h_user_welcome, source_p); show_lusers(source_p);
if(ConfigFileEntry.short_motd) { sendto_one_notice(source_p, ":*** Notice -- motd was last changed at %s", user_motd_changed); sendto_one_notice(source_p, ":*** Notice -- Please read the motd if you haven't read it");
sendto_one(source_p, form_str(RPL_MOTDSTART), me.name, source_p->name, me.name);
sendto_one(source_p, form_str(RPL_MOTD), me.name, source_p->name, "*** This is the short motd ***");
sendto_one(source_p, form_str(RPL_ENDOFMOTD), me.name, source_p->name); } else send_user_motd(source_p);}
/* oper_up() * * inputs - pointer to given client to oper * - pointer to ConfItem to use * output - none * side effects - opers up source_p using aconf for reference */voidoper_up(struct Client *source_p, struct oper_conf *oper_p){ unsigned int old = source_p->umodes, oldsnomask = source_p->snomask; hook_data_umode_changed hdata;
SetOper(source_p);
if(oper_p->umodes) source_p->umodes |= oper_p->umodes; else if(ConfigFileEntry.oper_umodes) source_p->umodes |= ConfigFileEntry.oper_umodes; else source_p->umodes |= DEFAULT_OPER_UMODES;
if (oper_p->snomask) { source_p->snomask |= oper_p->snomask; source_p->umodes |= UMODE_SERVNOTICE; } else if (source_p->umodes & UMODE_SERVNOTICE) { /* Only apply these if +s is already set -- jilles */ if (ConfigFileEntry.oper_snomask) source_p->snomask |= ConfigFileEntry.oper_snomask; else source_p->snomask |= DEFAULT_OPER_SNOMASK; }
Count.oper++;
SetExtendChans(source_p); SetExemptKline(source_p);
source_p->user->opername = rb_strdup(oper_p->name); source_p->user->privset = privilegeset_ref(oper_p->privset);
report_priv_change(source_p, NULL, source_p->user->privset);
rb_dlinkAddAlloc(source_p, &local_oper_list); rb_dlinkAddAlloc(source_p, &oper_list);
if(IsOperAdmin(source_p) && !IsOperHiddenAdmin(source_p)) source_p->umodes |= UMODE_ADMIN; if(!IsOperN(source_p)) source_p->snomask &= ~SNO_NCHANGE; if(!IsOperOperwall(source_p)) source_p->umodes &= ~UMODE_OPERWALL; if((ConfigFileEntry.oper_only_umodes & UMODE_SERVNOTICE) && !HasPrivilege(source_p, "usermode:servnotice")) { source_p->umodes &= ~UMODE_SERVNOTICE; source_p->snomask = 0; } hdata.client = source_p; hdata.oldumodes = old; hdata.oldsnomask = oldsnomask; call_hook(h_umode_changed, &hdata);
source_p->handler = IsOper(source_p) ? OPER_HANDLER : CLIENT_HANDLER;
sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s (%s!%s@%s) is now an operator", oper_p->name, source_p->name, source_p->username, source_p->host); sendto_server(NULL, NULL, CAP_TS6, NOCAPS, ":%s OPER %s %s", use_id(source_p), oper_p->name, oper_p->privset->name); if(!(old & UMODE_INVISIBLE) && IsInvisible(source_p)) ++Count.invisi; if((old & UMODE_INVISIBLE) && !IsInvisible(source_p)) --Count.invisi; send_umode_out(source_p, source_p, old); sendto_one_numeric(source_p, RPL_SNOMASK, form_str(RPL_SNOMASK), construct_snobuf(source_p->snomask)); sendto_one(source_p, form_str(RPL_YOUREOPER), me.name, source_p->name); sendto_one_notice(source_p, ":*** Oper privilege set is %s", oper_p->privset->name); send_multiline_init(source_p, " ", ":%s NOTICE %s :*** Oper privs are ", me.name, source_p->name); for (const char *const *s = privilegeset_privs(oper_p->privset); *s != NULL; s++) send_multiline_item(source_p, "%s", *s); send_multiline_fini(source_p, NULL); send_oper_motd(source_p);}
/* * find_umode_slot * * inputs - NONE * outputs - an available umode bitmask or * 0 if no umodes are available * side effects - NONE */unsigned intfind_umode_slot(void){ unsigned int all_umodes = 0, my_umode = 0, i;
for (i = 0; i < 128; i++) all_umodes |= user_modes[i];
for (my_umode = 1; my_umode && (all_umodes & my_umode); my_umode <<= 1);
return my_umode;}
voidconstruct_umodebuf(void){ int i; char *ptr = umodebuf; static int prev_user_modes[128];
*ptr = '\0';
for (i = 0; i < 128; i++) { if (prev_user_modes[i] != 0 && prev_user_modes[i] != user_modes[i]) { if (user_modes[i] == 0) { orphaned_umodes |= prev_user_modes[i]; sendto_realops_snomask(SNO_DEBUG, L_NETWIDE, "Umode +%c is now orphaned", i); } else { orphaned_umodes &= ~prev_user_modes[i]; sendto_realops_snomask(SNO_DEBUG, L_NETWIDE, "Orphaned umode +%c is picked up by module", i); } user_modes[i] = prev_user_modes[i]; } else prev_user_modes[i] = user_modes[i]; if (user_modes[i]) *ptr++ = (char) i; }
*ptr++ = '\0';}
voidchange_nick_user_host(struct Client *target_p, const char *nick, const char *user, const char *host, int newts, const char *format, ...){ rb_dlink_node *ptr; struct Channel *chptr; struct membership *mscptr; int changed = irccmp(target_p->name, nick); int changed_case = strcmp(target_p->name, nick); int do_qjm = strcmp(target_p->username, user) || (strcmp(target_p->host, host) && ConfigChannel.cycle_host_change); char mode[10], modeval[NICKLEN * 2 + 2], reason[256], *mptr; va_list ap;
modeval[0] = '\0';
if(changed) { target_p->tsinfo = newts; monitor_signoff(target_p); } invalidate_bancache_user(target_p);
if(do_qjm) { va_start(ap, format); vsnprintf(reason, sizeof reason, format, ap); va_end(ap);
sendto_common_channels_local_butone(target_p, NOCAPS, CLICAP_CHGHOST, ":%s!%s@%s QUIT :%s", target_p->name, target_p->username, target_p->host, reason);
RB_DLINK_FOREACH(ptr, target_p->user->channel.head) { mscptr = ptr->data; chptr = mscptr->chptr; mptr = mode;
if(is_chanop(mscptr)) { *mptr++ = 'o'; strcat(modeval, nick); strcat(modeval, " "); }
if(is_voiced(mscptr)) { *mptr++ = 'v'; strcat(modeval, nick); }
*mptr = '\0';
sendto_channel_local_with_capability_butone(target_p, ALL_MEMBERS, NOCAPS, CLICAP_EXTENDED_JOIN | CLICAP_CHGHOST, chptr, ":%s!%s@%s JOIN %s", nick, user, host, chptr->chname); sendto_channel_local_with_capability_butone(target_p, ALL_MEMBERS, CLICAP_EXTENDED_JOIN, CLICAP_CHGHOST, chptr, ":%s!%s@%s JOIN %s %s :%s", nick, user, host, chptr->chname, EmptyString(target_p->user->suser) ? "*" : target_p->user->suser, target_p->info);
if(*mode) sendto_channel_local_with_capability_butone(target_p, ALL_MEMBERS, NOCAPS, CLICAP_CHGHOST, chptr, ":%s MODE %s +%s %s", target_p->servptr->name, chptr->chname, mode, modeval);
*modeval = '\0'; }
/* Resend away message to away-notify enabled clients. */ if (target_p->user->away) sendto_common_channels_local_butone(target_p, CLICAP_AWAY_NOTIFY, CLICAP_CHGHOST, ":%s!%s@%s AWAY :%s", nick, user, host, target_p->user->away);
sendto_common_channels_local_butone(target_p, CLICAP_CHGHOST, NOCAPS, ":%s!%s@%s CHGHOST %s %s", target_p->name, target_p->username, target_p->host, user, host);
if(MyClient(target_p) && changed_case) sendto_one(target_p, ":%s!%s@%s NICK %s", target_p->name, user, host, nick);
/* TODO: send some snotes to SNO_NCHANGE/SNO_CCONN/SNO_CCONNEXT? */ } else if(changed_case) { sendto_common_channels_local(target_p, NOCAPS, NOCAPS, ":%s!%s@%s NICK :%s", target_p->name, user, host, nick);
if(MyConnect(target_p)) sendto_realops_snomask(SNO_NCHANGE, L_ALL, "Nick change: From %s to %s [%s@%s]", target_p->name, nick, target_p->username, target_p->host); }
if (user != target_p->username) rb_strlcpy(target_p->username, user, sizeof target_p->username);
rb_strlcpy(target_p->host, host, sizeof target_p->host);
if (changed) whowas_add_history(target_p, 1);
del_from_client_hash(target_p->name, target_p); rb_strlcpy(target_p->name, nick, NICKLEN); add_to_client_hash(target_p->name, target_p);
if(changed) { monitor_signon(target_p); del_all_accepts(target_p, false); }}
boolhas_common_channel(struct Client *source_p, struct Client *target_p){ rb_dlink_node *ps, *pt; struct membership *ms, *mt; struct Channel *chptr;
ITER_COMM_CHANNELS(ps, pt, source_p->user->channel.head, target_p->user->channel.head, ms, mt, chptr) { if (ms != NULL && mt != NULL) return true; }
return false;}