/** * AddCommand * * Adds a command to a list of commands. * * @param Commands the list of commands * @param Name the name of the command * @param Category the category of the command (e.g. "Admin" or "User") * @param Description a short description of the command * @param HelpText the associated help text (can contain embedded \\n characters */ void AddCommand(commandlist_t *Commands, const char *Name, const char *Category, const char *Description, const char *HelpText) { command_t *Command; if (Commands == NULL) { return; } if (*Commands == NULL) { *Commands = new CHashtable<command_t *, false>(); if (AllocFailed(*Commands)) { return; } (*Commands)->RegisterValueDestructor(DestroyCommandT); } Command = (command_t *)malloc(sizeof(command_t)); if (AllocFailed(Command)) { return; } Command->Category = strdup(Category); Command->Description = strdup(Description); Command->HelpText = HelpText ? strdup(HelpText) : NULL; (*Commands)->Add(Name, Command); }
/** * UpdateHostHelper * * Updates the host for a user. * * @param Host the host (nick!ident\@host) */ void CIRCConnection::UpdateHostHelper(const char *Host) { const char *NickEnd; size_t Offset; char *Copy; if (GetOwner() != NULL && GetOwner()->GetLeanMode() > 0 && m_Site != NULL) { return; } NickEnd = strchr(Host, '!'); if (NickEnd == NULL) { return; } Offset = NickEnd - Host; Copy = strdup(Host); if (AllocFailed(Copy)) { return; } const char *Nick = Copy; char *Site = Copy + Offset; *Site = '\0'; Site++; if (m_CurrentNick && strcasecmp(Nick, m_CurrentNick) == 0) { free(m_Site); m_Site = strdup(Site); if (AllocFailed(m_Site)) {} } if (GetOwner()->GetLeanMode() > 0) { free(Copy); return; } int i = 0; while (hash_t<CChannel *> *Chan = m_Channels->Iterate(i++)) { if (!Chan->Value || !Chan->Value->HasNames()) { continue; } CNick *NickObj = Chan->Value->GetNames()->Get(Nick); if (NickObj && NickObj->GetSite() == NULL) { NickObj->SetSite(Site); } } free(Copy); }
/** * CChannel * * Constructs a new channel object. * * @param Name the name of the channel * @param Owner the owner of the channel object */ CChannel::CChannel(const char *Name, CIRCConnection *Owner) { SetOwner(Owner); m_Name = strdup(Name); if (AllocFailed(m_Name)) {} m_Timestamp = g_CurrentTime; m_Creation = 0; m_Topic = NULL; m_TopicNick = NULL; m_TopicStamp = 0; m_HasTopic = 0; m_Nicks.RegisterValueDestructor(DestroyObject<CNick>); m_HasNames = false; m_ModesValid = false; m_KeepNicklist = true; m_HasBans = false; m_TempModes = NULL; m_Banlist = new CBanlist(this); m_BacklogCount = 0; }
/** * UpdateChannelConfig * * Updates the list of channels in the user's config file. */ void CIRCConnection::UpdateChannelConfig(void) { size_t Size; char *Out = NULL; int a = 0; while (hash_t<CChannel *> *Chan = m_Channels->Iterate(a++)) { bool WasNull = (Out == NULL); Size = (Out ? strlen(Out) : 0) + strlen(Chan->Name) + 2; Out = (char *)realloc(Out, Size); if (AllocFailed(Out)) { return; } if (!WasNull) { strmcat(Out, ",", Size); } else { Out[0] = '\0'; } strmcat(Out, Chan->Name, Size); } /* m_Owner can be NULL if the last channel was not created successfully */ if (GetOwner() != NULL) { GetOwner()->SetConfigChannels(Out); } free(Out); }
/** * ArgTokenize * * Tokenizes a string (i.e. splits it into arguments). ArgFree must * eventually be called on the returned string. * * @param Data the string */ const char *ArgTokenize(const char *Data) { char *Copy; size_t LengthData, Size; if (Data == NULL) { return NULL; } LengthData = strlen(Data); Size = LengthData + 2; Copy = (char *)malloc(Size); if (AllocFailed(Copy)) { return NULL; } strmcpy(Copy, Data, Size); Copy[LengthData + 1] = '\0'; for (unsigned int i = 0; i < LengthData; i++) { if (Copy[i] == ' ' && Copy[i + 1] != ' ' && Copy[i + 1] != '\0') { Copy[i] = '\0'; if (i > 0 && Copy[i + 1] == ':') { break; } } } return Copy; }
/** * LogUser * * Logs something in the bouncer's main log and also sends it to a specific user. * * @param User the user * @param Format a format string * @param ... additional parameters which are used by the format string */ void CCore::LogUser(CUser *User, const char *Format, ...) { char *Out; int Ret; va_list marker; bool DoneUser = false; va_start(marker, Format); Ret = vasprintf(&Out, Format, marker); va_end(marker); if (AllocFailed(Out)) { return; } m_Log->WriteLine("%s", Out); for (int i = 0; i < m_AdminUsers.GetLength(); i++) { CUser *ThisUser = m_AdminUsers[i]; if (ThisUser->GetSystemNotices() && ThisUser->GetClientConnectionMultiplexer()) { ThisUser->GetClientConnectionMultiplexer()->Privmsg(Out); if (ThisUser == User) { DoneUser = true; } } } if (!DoneUser && User->GetClientConnectionMultiplexer() != NULL) { User->GetClientConnectionMultiplexer()->Privmsg(Out); } free(Out); }
/** * Log * * Logs something in the bouncer's main log. * * @param Format a format string * @param ... additional parameters which are used by the format string */ void CCore::Log(const char *Format, ...) { char *Out; int Ret; va_list marker; va_start(marker, Format); Ret = vasprintf(&Out, Format, marker); va_end(marker); if (AllocFailed(Out)) { return; } if (m_Log == NULL) { fprintf(stderr, "%s\n", Out); } else { m_Log->WriteLine("%s", Out); } for (int i = 0; i < m_AdminUsers.GetLength(); i++) { CUser *User = m_AdminUsers.Get(i); if (User->GetSystemNotices() && User->GetClientConnectionMultiplexer() != NULL) { User->GetClientConnectionMultiplexer()->Privmsg(Out); } } free(Out); }
void nsTString_CharT::StripChars( const char* aSet ) { if (!EnsureMutable()) AllocFailed(mLength); mLength = nsBufferRoutines<CharT>::strip_chars(mData, mLength, aSet); }
void nsTString_CharT::ReplaceSubstring(const self_type& aTarget, const self_type& aNewValue) { if (!ReplaceSubstring(aTarget, aNewValue, mozilla::fallible)) { // Note that this may wildly underestimate the allocation that failed, as // we could have been replacing multiple copies of aTarget. AllocFailed(mLength + (aNewValue.Length() - aTarget.Length())); } }
void nsTString_CharT::ReplaceChar( char_type aOldChar, char_type aNewChar ) { if (!EnsureMutable()) // XXX do this lazily? AllocFailed(mLength); for (uint32_t i=0; i<mLength; ++i) { if (mData[i] == aOldChar) mData[i] = aNewChar; } }
bool nsTString_CharT::SetCharAt( char16_t aChar, uint32_t aIndex ) { if (aIndex >= mLength) return false; if (!EnsureMutable()) AllocFailed(mLength); mData[aIndex] = CharT(aChar); return true; }
/** * CLog * * Constructs a log object. * * @param Filename the filename of the log, can be NULL to indicate that * any log messages should be discarded * @param KeepOpen whether to keep the file open */ CLog::CLog(const char *Filename, bool KeepOpen) { if (Filename != NULL) { m_Filename = strdup(Filename); if (AllocFailed(m_Filename)) {} } else { m_Filename = NULL; } m_KeepOpen = KeepOpen; m_File = NULL; #ifndef _WIN32 m_Inode = 0; m_Dev = 0; #endif }
void nsTString_CharT::ReplaceChar( const char* aSet, char_type aNewChar ) { if (!EnsureMutable()) // XXX do this lazily? AllocFailed(mLength); char_type* data = mData; uint32_t lenRemaining = mLength; while (lenRemaining) { int32_t i = ::FindCharInSet(data, lenRemaining, aSet); if (i == kNotFound) break; data[i++] = aNewChar; data += i; lenRemaining -= i; } }
/** * SaltFromHash * * Returns the salt value for a hash (or NULL if there is none). * * @param Hash the hash value */ const char *SaltFromHash(const char *Hash) { static char *Salt = NULL; const char *HashSign; HashSign = strchr(Hash, '$'); if (HashSign == NULL) { return NULL; } free(Salt); Salt = (char *)malloc(HashSign - Hash + 1); if (AllocFailed(Salt)) { g_Bouncer->Fatal(); } strmcpy(Salt, Hash, HashSign - Hash + 1); return Salt; }
const char *sbncBuildPath(const char *Filename, const char *RelativeTo) { static char *Path = NULL; size_t Len; if (sbncIsAbsolutePath(Filename)) { return Filename; } if (RelativeTo == NULL) { char Cwd[MAXPATHLEN]; if (getcwd(Cwd, sizeof(Cwd)) == NULL) { perror("getcwd() failed"); exit(EXIT_FAILURE); } RelativeTo = Cwd; } free(Path); asprintf(&Path, "%s/%s", RelativeTo, Filename); if (AllocFailed(Path)) { return NULL; } #ifdef _WIN32 for (unsigned int i = 0; Path[i] != '\0'; i++) { if (Path[i] == '/') { Path[i] = '\\'; } } #endif return Path; }
/** * AddChannel * * Adds a channel for this IRC connection. This does not actually * send a JOIN command to the IRC server. * * @param Channel the channel's name */ CChannel *CIRCConnection::AddChannel(const char *Channel) { CChannel *ChannelObj; bool LimitExceeded = false; if (g_Bouncer->GetResourceLimit("channels") < m_Channels->GetLength()) { LimitExceeded = true; ChannelObj = NULL; } else { ChannelObj = new CChannel(Channel, this); } if (AllocFailed(ChannelObj)) { GetUser()->Log("Out of memory. Removing channel (%s).", Channel); WriteLine("PART %s", Channel); return NULL; } m_Channels->Add(Channel, ChannelObj); UpdateChannelConfig(); return ChannelObj; }
/** * WriteUnformattedLine * * Writes a new log entry. * * @param Line the log entry */ void CLog::WriteUnformattedLine(const char *Line) { char *Out = NULL, *dupLine; size_t StringLength; unsigned int a; tm Now; char strNow[100]; FILE *LogFile; #ifndef _WIN32 struct stat StatBuf; #endif int rc; if (Line == NULL) { return; } LogFile = m_File; #ifndef _WIN32 if (m_Filename != NULL) { rc = lstat(m_Filename, &StatBuf); if (m_File != NULL && (rc < 0 || StatBuf.st_ino != m_Inode || StatBuf.st_dev != m_Dev)) { fclose(m_File); m_File = NULL; } if (rc == 0) { m_Inode = StatBuf.st_ino; m_Dev = StatBuf.st_dev; } } #endif if (m_Filename == NULL || (m_File == NULL && (LogFile = fopen(m_Filename, "a")) == NULL)) { return; } SetPermissions(m_Filename, S_IRUSR | S_IWUSR); Now = *localtime(&g_CurrentTime); #ifdef _WIN32 strftime(strNow, sizeof(strNow), "%#c" , &Now); #else strftime(strNow, sizeof(strNow), "%a %B %d %Y %H:%M:%S" , &Now); #endif dupLine = strdup(Line); if (AllocFailed(dupLine)) { return; } StringLength = strlen(dupLine); a = 0; for (unsigned int i = 0; i <= StringLength; i++) { if (dupLine[i] == '\r' || dupLine[i] == '\n') { continue; } dupLine[a] = dupLine[i]; a++; } rc = asprintf(&Out, "[%s]: %s\n", strNow, dupLine); free(dupLine); if (rc < 0) { perror("asprintf() failed"); return; } fputs(Out, LogFile); printf("%s", Out); free(Out); if (!m_KeepOpen) { fclose(LogFile); } else { m_File = LogFile; fflush(m_File); } }
/** * SocketAndConnect * * Creates a socket and connects to the specified host/port. You should use * SocketAndConnectResolved instead wherever possible as this function uses * blocking DNS requests. * * @param Host the host * @param Port the port * @param BindIp the ip address/hostname which should be used for binding the socket */ SOCKET SocketAndConnect(const char *Host, unsigned int Port, const char *BindIp) { unsigned long lTrue = 1; sockaddr_in sin, sloc; SOCKET Socket; hostent *hent; unsigned long addr; int code; if (Host == NULL || Port == 0) { return INVALID_SOCKET; } Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (Socket == INVALID_SOCKET) { return INVALID_SOCKET; } ioctlsocket(Socket, FIONBIO, &lTrue); if (BindIp && *BindIp) { sloc.sin_family = AF_INET; sloc.sin_port = 0; hent = gethostbyname(BindIp); if (hent) { in_addr *peer = (in_addr *)hent->h_addr_list[0]; sloc.sin_addr.s_addr = peer->s_addr; } else { addr = inet_addr(BindIp); sloc.sin_addr.s_addr = addr; } bind(Socket, (sockaddr *)&sloc, sizeof(sloc)); } sin.sin_family = AF_INET; sin.sin_port = htons(Port); hent = gethostbyname(Host); if (hent) { in_addr *peer = (in_addr *)hent->h_addr_list[0]; sin.sin_addr.s_addr = peer->s_addr; } else { addr = inet_addr(Host); sin.sin_addr.s_addr = addr; } code = connect(Socket, (const sockaddr *)&sin, sizeof(sin)); #ifdef _WIN32 if (code != 0 && errno != WSAEWOULDBLOCK) { #else if (code != 0 && errno != EINPROGRESS) { #endif closesocket(Socket); return INVALID_SOCKET; } return Socket; } /** * SocketAndConnectResolved * * Creates a socket and connects to the specified host/port. * * @param Host the host's ip address * @param BindIp the ip address which should be used for binding the socket */ SOCKET SocketAndConnectResolved(const sockaddr *Host, const sockaddr *BindIp) { unsigned long lTrue = 1; int Code, Size; SOCKET Socket = socket(Host->sa_family, SOCK_STREAM, IPPROTO_TCP); if (Socket == INVALID_SOCKET) { return INVALID_SOCKET; } ioctlsocket(Socket, FIONBIO, &lTrue); if (BindIp != NULL) { bind(Socket, (sockaddr *)BindIp, SOCKADDR_LEN(BindIp->sa_family)); } Size = SOCKADDR_LEN(Host->sa_family); Code = connect(Socket, Host, Size); #ifdef _WIN32 if (Code != 0 && WSAGetLastError() != WSAEWOULDBLOCK) { #else if (Code != 0 && errno != EINPROGRESS) { #endif closesocket(Socket); return INVALID_SOCKET; } return Socket; } /** * NickFromHostname * * Given a complete hostmask (nick!ident\@host) this function returns a copy * of the nickname. The result must be passed to free() when it is no longer used. * * @param Hostmask the hostmask */ char *NickFromHostmask(const char *Hostmask) { char *Copy; const char *ExclamationMark; ExclamationMark = strchr(Hostmask, '!'); if (ExclamationMark == NULL) { return NULL; } Copy = strdup(Hostmask); if (AllocFailed(Copy)) { return NULL; } Copy[ExclamationMark - Hostmask] = '\0'; return Copy; }
/** * CIRCConnection * * Constructs a new IRC connection object. * * @param Host the server's host name * @param Port the server's port * @param Owner the owner of the IRC connection * @param BindIp bind address (or NULL) * @param SSL whether to use SSL * @param Family socket family (either AF_INET or AF_INET6) */ CIRCConnection::CIRCConnection(const char *Host, unsigned int Port, CUser *Owner, const char *BindIp, bool SSL, int Family) : CConnection(Host, Port, BindIp, SSL, Family) { const char *Ident; SetRole(Role_Client); SetOwner(Owner); g_LastReconnect = g_CurrentTime; m_LastResponse = g_LastReconnect; m_State = State_Connecting; m_CurrentNick = NULL; m_Server = NULL; m_ServerVersion = NULL; m_ServerFeat = NULL; m_Site = NULL; m_Usermodes = NULL; m_EatPong = false; m_QueueHigh = new CQueue(); if (AllocFailed(m_QueueHigh)) { g_Bouncer->Fatal(); } m_QueueMiddle = new CQueue(); if (AllocFailed(m_QueueMiddle)) { g_Bouncer->Fatal(); } m_QueueLow = new CQueue(); if (AllocFailed(m_QueueLow)) { g_Bouncer->Fatal(); } m_FloodControl = new CFloodControl(); if (AllocFailed(m_FloodControl)) { g_Bouncer->Fatal(); } if (Host != NULL) { const char *Password = Owner->GetServerPassword(); if (Password != NULL) { WriteLine("PASS :%s", Password); } WriteLine("NICK %s", Owner->GetNick()); if (Owner->GetIdent() != NULL) { Ident = Owner->GetIdent(); } else { Ident = Owner->GetUsername(); } WriteLine("USER %s \"\" \"fnords\" :%s", Ident, Owner->GetRealname()); } m_Channels = new CHashtable<CChannel *, false>(); if (AllocFailed(m_Channels)) { g_Bouncer->Fatal(); } m_Channels->RegisterValueDestructor(DestroyObject<CChannel>); m_ISupport = new CHashtable<char *, false>(); if (AllocFailed(m_ISupport)) { g_Bouncer->Fatal(); } m_ISupport->RegisterValueDestructor(FreeString); m_ISupport->Add("CHANMODES", strdup("bIe,k,l")); m_ISupport->Add("CHANTYPES", strdup("#&+")); m_ISupport->Add("PREFIX", strdup("(ov)@+")); m_ISupport->Add("NAMESX", strdup("")); m_FloodControl->AttachInputQueue(m_QueueHigh, 0); m_FloodControl->AttachInputQueue(m_QueueMiddle, 1); m_FloodControl->AttachInputQueue(m_QueueLow, 2); m_PingTimer = g_Bouncer->CreateTimer(180, true, IRCPingTimer, this); m_DelayJoinTimer = NULL; m_NickCatchTimer = NULL; }
/** * ParseLineArgV * * Parses and processes a line which was sent by the server. * * @param argc number of tokens * @param argv the tokens */ bool CIRCConnection::ParseLineArgV(int argc, const char **argv) { CChannel *Channel; CClientConnection *Client; m_LastResponse = g_CurrentTime; if (argc < 2) { return true; } const char *Reply = argv[0]; const char *Raw = argv[1]; char *Nick = ::NickFromHostmask(Reply); int iRaw = atoi(Raw); bool b_Me = false; if (m_CurrentNick != NULL && Nick != NULL && strcasecmp(Nick, m_CurrentNick) == 0) { b_Me = true; } free(Nick); Client = GetOwner()->GetClientConnectionMultiplexer(); // HASH values CHashCompare hashRaw(argv[1]); static CHashCompare hashPrivmsg("PRIVMSG"); static CHashCompare hashNotice("NOTICE"); static CHashCompare hashJoin("JOIN"); static CHashCompare hashPart("PART"); static CHashCompare hashKick("KICK"); static CHashCompare hashNick("NICK"); static CHashCompare hashQuit("QUIT"); static CHashCompare hashMode("MODE"); static CHashCompare hashTopic("TOPIC"); static CHashCompare hashPong("PONG"); // END of HASH values if (argc > 3 && iRaw == 433) { bool ReturnValue = ModuleEvent(argc, argv); if (ReturnValue) { if (GetCurrentNick() == NULL) { WriteLine("NICK :%s_", argv[3]); } if (m_NickCatchTimer == NULL) { m_NickCatchTimer = new CTimer(30, false, NickCatchTimer, this); } } return ReturnValue; } else if (argc > 3 && hashRaw == hashPrivmsg && Client == NULL) { const char *Host; const char *Dest = argv[2]; char *Nick = ::NickFromHostmask(Reply); Channel = GetChannel(Dest); if (Channel != NULL) { CNick *User = Channel->GetNames()->Get(Nick); if (User != NULL) { User->SetIdleSince(g_CurrentTime); } Channel->AddBacklogLine(argv[0], argv[3]); } if (!ModuleEvent(argc, argv)) { free(Nick); return false; } /* don't log ctcp requests */ if (argv[3][0] != '\1' && argv[3][strlen(argv[3]) - 1] != '\1' && Dest != NULL && Nick != NULL && m_CurrentNick != NULL && strcasecmp(Dest, m_CurrentNick) == 0 && strcasecmp(Nick, m_CurrentNick) != 0) { char *Dup; char *Delim; Dup = strdup(Reply); if (AllocFailed(Dup)) { free(Nick); return true; } Delim = strchr(Dup, '!'); if (Delim != NULL) { *Delim = '\0'; Host = Delim + 1; } GetOwner()->Log("%s (%s): %s", Dup, Delim ? Host : "<unknown host>", argv[3]); free(Dup); } free(Nick); UpdateHostHelper(Reply); return true; } else if (argc > 3 && hashRaw == hashPrivmsg && Client != NULL) { Channel = GetChannel(argv[2]); if (Channel != NULL) { Channel->AddBacklogLine(argv[0], argv[3]); } } else if (argc > 3 && hashRaw == hashNotice && Client == NULL) { const char *Dest = argv[2]; char *Nick; if (!ModuleEvent(argc, argv)) { return false; } Nick = ::NickFromHostmask(Reply); /* don't log ctcp replies */ if (argv[3][0] != '\1' && argv[3][strlen(argv[3]) - 1] != '\1' && Dest != NULL && Nick != NULL && m_CurrentNick != NULL && strcasecmp(Dest, m_CurrentNick) == 0 && strcasecmp(Nick, m_CurrentNick) != 0) { GetOwner()->Log("%s (notice): %s", Reply, argv[3]); } free(Nick); return true; } else if (argc > 2 && hashRaw == hashJoin) { if (b_Me) { AddChannel(argv[2]); /* GetOwner() can be NULL if AddChannel failed */ if (GetOwner() != NULL && Client == NULL) { WriteLine("MODE %s", argv[2]); } } Channel = GetChannel(argv[2]); if (Channel != NULL) { Nick = NickFromHostmask(Reply); if (AllocFailed(Nick)) { return false; } Channel->AddUser(Nick, '\0'); free(Nick); } UpdateHostHelper(Reply); } else if (argc > 2 && hashRaw == hashPart) { bool bRet = ModuleEvent(argc, argv); if (b_Me) { RemoveChannel(argv[2]); } else { Channel = GetChannel(argv[2]); if (Channel != NULL) { Nick = ::NickFromHostmask(Reply); if (AllocFailed(Nick)) { return false; } Channel->RemoveUser(Nick); free(Nick); } } UpdateHostHelper(Reply); return bRet; } else if (argc > 3 && hashRaw == hashKick) { bool bRet = ModuleEvent(argc, argv); if (m_CurrentNick != NULL && strcasecmp(argv[3], m_CurrentNick) == 0) { RemoveChannel(argv[2]); if (Client == NULL) { char *Dup = strdup(Reply); if (AllocFailed(Dup)) { return bRet; } char *Delim = strchr(Dup, '!'); const char *Host = NULL; if (Delim) { *Delim = '\0'; Host = Delim + 1; } GetOwner()->Log("%s (%s) kicked you from %s (%s)", Dup, Delim ? Host : "<unknown host>", argv[2], argc > 4 ? argv[4] : ""); free(Dup); } } else { Channel = GetChannel(argv[2]); if (Channel != NULL) { Channel->RemoveUser(argv[3]); } } UpdateHostHelper(Reply); return bRet; } else if (argc > 2 && iRaw == 1) { if (Client != NULL) { if (strcmp(Client->GetNick(), argv[2]) != 0) { Client->WriteLine(":%s!%s NICK :%s", Client->GetNick(), m_Site ? m_Site : "*****@*****.**", argv[2]); } } free(m_CurrentNick); m_CurrentNick = strdup(argv[2]); free(m_Server); m_Server = strdup(Reply); } else if (argc > 2 && hashRaw == hashNick) { if (b_Me) { free(m_CurrentNick); m_CurrentNick = strdup(argv[2]); } Nick = NickFromHostmask(argv[0]); int i = 0; if (!b_Me && GetOwner()->GetClientConnectionMultiplexer() == NULL) { const char *AwayNick = GetOwner()->GetAwayNick(); if (AwayNick != NULL && strcasecmp(AwayNick, Nick) == 0) { WriteLine("NICK %s", AwayNick); } } while (hash_t<CChannel *> *ChannelHash = m_Channels->Iterate(i++)) { ChannelHash->Value->RenameUser(Nick, argv[2]); } free(Nick); } else if (argc > 1 && hashRaw == hashQuit) { bool bRet = ModuleEvent(argc, argv); Nick = NickFromHostmask(argv[0]); int i = 0; while (hash_t<CChannel *> *ChannelHash = m_Channels->Iterate(i++)) { ChannelHash->Value->RemoveUser(Nick); } free(Nick); return bRet; } else if (argc > 1 && (iRaw == 422 || iRaw == 376)) { int DelayJoin = GetOwner()->GetDelayJoin(); if (m_State != State_Connected) { const CVector<CModule *> *Modules = g_Bouncer->GetModules(); for (int i = 0; i < Modules->GetLength(); i++) { (*Modules)[i]->ServerLogon(GetOwner()->GetUsername()); } const char *ClientNick; if (Client != NULL) { ClientNick = Client->GetNick(); if (strcmp(m_CurrentNick, ClientNick) != 0) { Client->ChangeNick(m_CurrentNick); } } GetOwner()->Log("You were successfully connected to an IRC server."); g_Bouncer->Log("User %s connected to an IRC server.", GetOwner()->GetUsername()); } if (DelayJoin == 1) { m_DelayJoinTimer = g_Bouncer->CreateTimer(5, false, DelayJoinTimer, this); } else if (DelayJoin == 0) { JoinChannels(); } if (Client == NULL) { bool AppendTS = (GetOwner()->GetConfig()->ReadInteger("user.ts") != 0); const char *AwayReason = GetOwner()->GetAwayText(); if (AwayReason != NULL) { WriteLine(AppendTS ? "AWAY :%s (Away since the dawn of time)" : "AWAY :%s", AwayReason); } } const char *AutoModes = GetOwner()->GetAutoModes(); const char *DropModes = GetOwner()->GetDropModes(); if (AutoModes != NULL) { WriteLine("MODE %s +%s", GetCurrentNick(), AutoModes); } if (DropModes != NULL && Client == NULL) { WriteLine("MODE %s -%s", GetCurrentNick(), DropModes); } m_State = State_Connected; } else if (argc > 1 && strcasecmp(Reply, "ERROR") == 0) { if (strstr(Raw, "throttle") != NULL) { GetOwner()->ScheduleReconnect(120); } else { GetOwner()->ScheduleReconnect(5); } if (GetCurrentNick() != NULL && GetSite() != NULL) { g_Bouncer->LogUser(GetUser(), "Error received for user %s [%s!%s]: %s", GetOwner()->GetUsername(), GetCurrentNick(), GetSite(), argv[1]); } else { g_Bouncer->LogUser(GetUser(), "Error received for user %s: %s", GetOwner()->GetUsername(), argv[1]); } } else if (argc > 3 && iRaw == 465) { if (GetCurrentNick() != NULL && GetSite() != NULL) { g_Bouncer->LogUser(GetUser(), "G/K-line reason for user %s [%s!%s]: %s", GetOwner()->GetUsername(), GetCurrentNick(), GetSite(), argv[3]); } else { g_Bouncer->LogUser(GetUser(), "G/K-line reason for user %s: %s", GetOwner()->GetUsername(), argv[3]); } } else if (argc > 5 && iRaw == 351) { free(m_ServerVersion); m_ServerVersion = strdup(argv[3]); free(m_ServerFeat); m_ServerFeat = strdup(argv[5]); } else if (argc > 3 && iRaw == 5) { for (int i = 3; i < argc - 1; i++) { char *Dup = strdup(argv[i]); if (AllocFailed(Dup)) { return false; } char *Eq = strchr(Dup, '='); if (strcasecmp(Dup, "NAMESX") == 0) { WriteLine("PROTOCTL NAMESX"); } char *Value; if (Eq) { *Eq = '\0'; Value = strdup(++Eq); } else { Value = strdup(""); } m_ISupport->Add(Dup, Value); free(Dup); } } else if (argc > 4 && iRaw == 324) { Channel = GetChannel(argv[3]); if (Channel != NULL) { Channel->ClearModes(); Channel->ParseModeChange(argv[0], argv[4], argc - 5, &argv[5]); Channel->SetModesValid(true); } } else if (argc > 3 && hashRaw == hashMode) { Channel = GetChannel(argv[2]); if (Channel != NULL) { Channel->ParseModeChange(argv[0], argv[3], argc - 4, &argv[4]); } else if (strcmp(m_CurrentNick, argv[2]) == 0) { bool Flip = true, WasNull; const char *Modes = argv[3]; size_t Length = strlen(Modes) + 1; if (m_Usermodes != NULL) { Length += strlen(m_Usermodes); } WasNull = (m_Usermodes != NULL) ? false : true; m_Usermodes = (char *)realloc(m_Usermodes, Length); if (AllocFailed(m_Usermodes)) { return false; } if (WasNull) { m_Usermodes[0] = '\0'; } while (*Modes != '\0') { if (*Modes == '+') { Flip = true; } else if (*Modes == '-') { Flip = false; } else { if (Flip) { size_t Position = strlen(m_Usermodes); m_Usermodes[Position] = *Modes; m_Usermodes[Position + 1] = '\0'; } else { char *CurrentModes = m_Usermodes; size_t a = 0; while (*CurrentModes != '\0') { *CurrentModes = m_Usermodes[a]; if (*CurrentModes != *Modes) { CurrentModes++; } a++; } } } Modes++; } } UpdateHostHelper(Reply); } else if (argc > 4 && iRaw == 329) { Channel = GetChannel(argv[3]); if (Channel != NULL) { Channel->SetCreationTime(atoi(argv[4])); } } else if (argc > 4 && iRaw == 332) { Channel = GetChannel(argv[3]); if (Channel != NULL) { Channel->SetTopic(argv[4]); } } else if (argc > 5 && iRaw == 333) { Channel = GetChannel(argv[3]); if (Channel != NULL) { Channel->SetTopicNick(argv[4]); Channel->SetTopicStamp(atoi(argv[5])); } } else if (argc > 3 && iRaw == 331) { Channel = GetChannel(argv[3]); if (Channel != NULL) { Channel->SetNoTopic(); } } else if (argc > 3 && hashRaw == hashTopic) { Channel = GetChannel(argv[2]); if (Channel != NULL) { Channel->SetTopic(argv[3]); Channel->SetTopicStamp(g_CurrentTime); Channel->SetTopicNick(argv[0]); } UpdateHostHelper(Reply); } else if (argc > 5 && iRaw == 353) { Channel = GetChannel(argv[4]); if (Channel != NULL) { const char *nicks; const char **nickv; nicks = ArgTokenize(argv[5]); if (AllocFailed(nicks)) { return false; } nickv = ArgToArray(nicks); if (AllocFailed(nickv)) { ArgFree(nicks); return false; } int nickc = ArgCount(nicks); for (int i = 0; i < nickc; i++) { char *Nick = strdup(nickv[i]); char *BaseNick = Nick; if (AllocFailed(Nick)) { ArgFree(nicks); return false; } StrTrim(Nick, ' '); while (IsNickPrefix(*Nick)) { Nick++; } char *Modes = NULL; if (BaseNick != Nick) { Modes = (char *)malloc(Nick - BaseNick + 1); if (!AllocFailed(Modes)) { strmcpy(Modes, BaseNick, Nick - BaseNick + 1); } } Channel->AddUser(Nick, Modes); free(BaseNick); free(Modes); } ArgFreeArray(nickv); ArgFree(nicks); } } else if (argc > 3 && iRaw == 366) { Channel = GetChannel(argv[3]); if (Channel != NULL) { Channel->SetHasNames(); } } else if (argc > 9 && iRaw == 352) { const char *Ident = argv[4]; const char *Host = argv[5]; const char *Server = argv[6]; const char *Nick = argv[7]; const char *Realname = argv[9]; char *Mask; int rc = asprintf(&Mask, "%s!%s@%s", Nick, Ident, Host); if (!RcFailed(rc)) { UpdateHostHelper(Mask); UpdateWhoHelper(Nick, Realname, Server); free(Mask); } } else if (argc > 6 && iRaw == 367) { Channel = GetChannel(argv[3]); if (Channel != NULL) { Channel->GetBanlist()->SetBan(argv[4], argv[5], atoi(argv[6])); } } else if (argc > 3 && iRaw == 368) { Channel = GetChannel(argv[3]); if (Channel != NULL) { Channel->SetHasBans(); } } else if (argc > 3 && iRaw == 396) { free(m_Site); m_Site = strdup(argv[3]); if (AllocFailed(m_Site)) {} } else if (argc > 3 && hashRaw == hashPong && m_Server != NULL && strcasecmp(argv[2], m_Server) == 0 && m_EatPong) { m_EatPong = false; return false; } else if (argc > 3 && iRaw == 421) { m_FloodControl->Unplug(); return false; } if (GetOwner() != NULL) { return ModuleEvent(argc, argv); } else { return true; } }
/** * JoinChannels * * Joins the channels which the user should be in (according to * the configuration file). */ void CIRCConnection::JoinChannels(void) { size_t Size; const char *Channels; if (m_DelayJoinTimer) { m_DelayJoinTimer->Destroy(); m_DelayJoinTimer = NULL; } Channels = GetOwner()->GetConfigChannels(); if (Channels != NULL && Channels[0] != '\0') { char *DupChannels, *newChanList, *Channel, *ChanList = NULL; CKeyring *Keyring; DupChannels = strdup(Channels); if (AllocFailed(DupChannels)) { return; } Channel = strtok(DupChannels, ","); Keyring = GetOwner()->GetKeyring(); while (Channel != NULL && Channel[0] != '\0') { const char *Key = Keyring->GetKey(Channel); if (Key != NULL) { WriteLine("JOIN %s %s", Channel, Key); } else { if (ChanList == NULL || strlen(ChanList) > 400) { if (ChanList != NULL) { WriteLine("JOIN %s", ChanList); free(ChanList); } Size = strlen(Channel) + 1; ChanList = (char *)malloc(Size); if (AllocFailed(ChanList)) { free(DupChannels); return; } strmcpy(ChanList, Channel, Size); } else { Size = strlen(ChanList) + 1 + strlen(Channel) + 2; newChanList = (char *)realloc(ChanList, Size); if (AllocFailed(newChanList)) { continue; } ChanList = newChanList; strmcat(ChanList, ",", Size); strmcat(ChanList, Channel, Size); } } Channel = strtok(NULL, ","); } if (ChanList != NULL) { WriteLine("JOIN %s", ChanList); free(ChanList); } free(DupChannels); } }
/** * UtilSaltedMd5 * * Computes the MD5 hash of a given string and returns * a string representation of the hash. * * @param String the string which should be hashed * @param Salt the salt value * @param BrokenAlgo whether to use the broken algorithm */ const char *UtilMd5(const char *String, const char *Salt, bool BrokenAlgo) { #ifdef HAVE_LIBSSL MD5_CTX context; #else /* HAVE_LIBSSL */ sMD5_CTX context; #endif /* HAVE_LIBSSL */ broken_sMD5_CTX broken_context; unsigned char digest[16]; char *StringAndSalt, *StringPtr; static char *SaltAndResult = NULL; int rc; free(SaltAndResult); if (Salt != NULL) { rc = asprintf(&StringAndSalt, "%s%s", String, Salt); } else { rc = asprintf(&StringAndSalt, "%s", String); } if (RcFailed(rc)) { g_Bouncer->Fatal(); } if (!BrokenAlgo) { #ifdef HAVE_LIBSSL MD5_Init(&context); MD5_Update(&context, (unsigned char *)StringAndSalt, strlen(StringAndSalt)); MD5_Final(digest, &context); #else /* HAVE_LIBSSL */ MD5Init(&context); MD5Update(&context, (unsigned char *)StringAndSalt, strlen(StringAndSalt)); MD5Final(digest, &context); #endif /* HAVE_LIBSSL */ } else { broken_MD5Init(&broken_context); broken_MD5Update(&broken_context, (unsigned char *)StringAndSalt, strlen(StringAndSalt)); broken_MD5Final(digest, &broken_context); } free(StringAndSalt); if (Salt != NULL) { SaltAndResult = (char *)malloc(strlen(Salt) + 50); if (AllocFailed(SaltAndResult)) { g_Bouncer->Fatal(); } strmcpy(SaltAndResult, Salt, strlen(Salt) + 50); strmcat(SaltAndResult, "$", strlen(Salt) + 50); StringPtr = SaltAndResult + strlen(SaltAndResult); } else { StringPtr = SaltAndResult = (char *)malloc(50); if (AllocFailed(SaltAndResult)) { g_Bouncer->Fatal(); } } for (int i = 0; i < 16; i++) { /* TODO: don't use sprintf */ sprintf(StringPtr + i * 2, "%02x", digest[i]); } return SaltAndResult; }
/** * SetIdent * * Sets the default ident for the bouncer. * * @param Ident the ident */ void CIdentSupport::SetIdent(const char *Ident) { char *NewIdent; #ifndef _WIN32 passwd *pwd; uid_t uid; char *FilenameTemp, *Filename; int rc; uid = getuid(); pwd = getpwuid(uid); if (pwd == NULL) { g_Bouncer->Log("Could not figure out the UNIX username. Not setting ident."); return; } rc = asprintf(&Filename, "%s/.oidentd.conf", pwd->pw_dir); if (RcFailed(rc)) { return; } rc = asprintf(&FilenameTemp, "%s.tmp", Filename); if (RcFailed(rc)) { free(Filename); return; } FILE *identConfig = fopen(FilenameTemp, "w"); SetPermissions(FilenameTemp, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (identConfig != NULL) { char *Buf = (char *)malloc(strlen(Ident) + 50); snprintf(Buf, strlen(Ident) + 50, "global { reply \"%s\" }", Ident); fputs(Buf, identConfig); free(Buf); fclose(identConfig); } rc = rename(FilenameTemp, Filename); free(Filename); free(FilenameTemp); if (RcFailed(rc)) {} #endif NewIdent = strdup(Ident); if (AllocFailed(NewIdent)) { return; } free(m_Ident); m_Ident = NewIdent; }
/** * CCore * * Creates a new shroudBNC application object. * * @param Config the main config object * @param argc argument counts * @param argv program arguments */ CCore::CCore(CConfig *Config, int argc, char **argv) { int i; m_Log = NULL; m_PidFile = NULL; WritePidFile(); m_Config = Config; m_SSLContext = NULL; m_SSLClientContext = NULL; m_Status = Status_Running; CacheInitialize(m_ConfigCache, Config, "system."); char *SourcePath = strdup(BuildPathLog("sbnc.log")); rename(SourcePath, BuildPathLog("sbnc.log.old")); free(SourcePath); m_PollFds.Preallocate(SFD_SETSIZE); m_Log = new CLog("sbnc.log", true); if (m_Log == NULL) { printf("Log system could not be initialized. Shutting down."); exit(EXIT_FAILURE); } m_Log->Clear(); Log("Log system initialized."); g_Bouncer = this; m_Config = Config; m_Args.SetList(argv, argc); m_Ident = new CIdentSupport(); m_Config = new CConfig("sbnc.conf", NULL); CacheInitialize(m_ConfigCache, m_Config, "system."); const char *Users; CUser *User; if ((Users = m_Config->ReadString("system.users")) == NULL) { if (!MakeConfig()) { Log("Configuration file could not be created."); Fatal(); } printf("Configuration has been successfully saved. Please restart shroudBNC now.\n"); exit(EXIT_SUCCESS); } const char *Args; int Count; Args = ArgTokenize(Users); if (AllocFailed(Args)) { Fatal(); } Count = ArgCount(Args); for (i = 0; i < Count; i++) { const char *Name = ArgGet(Args, i + 1); User = new CUser(Name); if (AllocFailed(User)) { Fatal(); } m_Users.Add(Name, User); } ArgFree(Args); m_Listener = NULL; m_ListenerV6 = NULL; m_SSLListener = NULL; m_SSLListenerV6 = NULL; time(&m_Startup); m_LoadingModules = false; m_LoadingListeners = false; InitializeSocket(); m_Capabilities = new CVector<const char *>(); m_Capabilities->Insert("multi-prefix"); m_Capabilities->Insert("znc.in/server-time-iso"); }