Пример #1
0
/**
 * 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);
}
Пример #2
0
/**
 * 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);
}
Пример #3
0
/**
 * 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;
}
Пример #4
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);
}
Пример #5
0
/**
 * 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;
}
Пример #6
0
/**
 * 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);
}
Пример #7
0
/**
 * 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);
}
Пример #8
0
void
nsTString_CharT::StripChars( const char* aSet )
{
  if (!EnsureMutable())
    AllocFailed(mLength);

  mLength = nsBufferRoutines<CharT>::strip_chars(mData, mLength, aSet);
}
Пример #9
0
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()));
  }
}
Пример #10
0
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;
  }
}
Пример #11
0
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;
}
Пример #12
0
/**
 * 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
}
Пример #13
0
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;
  }
}
Пример #14
0
/**
 * 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;
}
Пример #15
0
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;
}
Пример #16
0
/**
 * 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;
}
Пример #17
0
/**
 * 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);
	}
}
Пример #18
0
/**
 * 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;
}
Пример #19
0
/**
 * 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;
}
Пример #20
0
/**
 * 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;
	}
}
Пример #21
0
/**
 * 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);
	}
}
Пример #22
0
/**
 * 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;
}
Пример #23
0
/**
 * 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;
}
Пример #24
0
/**
 * 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");
}