BarryServer : Git

All the code for all my projects
// BarryServer : Git / IRCWebHooks / blob / 15ed2e4901d1b6a3c4906bb30f27cf249e48941d / src / irc.c

// Related

IRCWebHooks

Barry Making admin auths optional 46d7b3c (3 years, 3 months ago)
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <netdb.h>
#include <string.h>

#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>

#include "config.h"
#include "list.h"
#include "irc.h"

SSL_CTX *ctx;
SSL *ssl;
int conn;
char sbuf[512];
struct Node *head = NULL;
struct Node *current = NULL;

/* Auth a user */
int
auth(char *ident, char *vhost)
{
	char *pt;

#ifdef ADMIN_IDENT
	char *identlist = strdup(ADMIN_IDENT);
	pt = strtok(identlist,",");
	while (pt != NULL) {
		if (!strncmp(ident, pt, strlen(pt))) return 1;
		pt = strtok(NULL, ",");
	}
#endif

#ifdef ADMIN_VHOST
	char *vhostlist = strdup(ADMIN_VHOST);
	pt = strtok(vhostlist,",");
	while (pt != NULL) {
		if (!strncmp(vhost, pt, strlen(pt))) return 1;
		pt = strtok(NULL, ",");
	}
#endif

	return 0;
}

/* Send data to server */
void
raw(char *fmt, ...)
{
	va_list ap;
	va_start(ap, fmt);
	vsnprintf(sbuf, 512, fmt, ap);
	va_end(ap);
#ifdef VERBOSE
	printf("<< %s", sbuf);
#endif
#ifdef SSL_IRC
	SSL_write(ssl, sbuf, strlen(sbuf));
#else
	write(conn, sbuf, strlen(sbuf));
#endif
}

/* Bot code */
void
bot(void)
{
#ifdef SSL_IRC
	BIO *certbio = NULL, *outbio = NULL;
	X509 *cert = NULL;
	X509_NAME *certname = NULL;
	const SSL_METHOD *method;
#endif

	char *user, *ident, *vhost, *command, *where, *message, *sep, *target;
	int i, j, l, sl, o = -1, start, wordcount;
	char buf[513];
	struct addrinfo hints, *res;

	/* Connect to IRC */
	printf("Connecting to IRC...\n");
	memset(&hints, 0, sizeof(hints));
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_STREAM;
	getaddrinfo(HOST, PORT, &hints, &res);
	conn = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
	connect(conn, res->ai_addr, res->ai_addrlen);

#ifdef SSL_IRC
	/* SSL connection */
	{
		OpenSSL_add_all_algorithms();
		ERR_load_BIO_strings();
		ERR_load_crypto_strings();
		SSL_load_error_strings();
		certbio = BIO_new(BIO_s_file());
		outbio = BIO_new_fp(stdout, BIO_NOCLOSE);
		if (SSL_library_init() < 0) {
			BIO_printf(outbio, "Could not initialise the OpenSSL library!\n");
			exit(1);
		}
		method = SSLv23_client_method();
		if ((ctx = SSL_CTX_new(method)) == NULL) {
			BIO_printf(outbio, "Unable to create a new SSL context!\n");
			exit(1);
		}
		SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
		ssl = SSL_new(ctx);
		SSL_set_fd(ssl, conn);
		if (SSL_connect(ssl) != 1) {
			BIO_printf(outbio, "Error: Could not SSL connect!\n");
			exit(1);
		}
		cert = SSL_get_peer_certificate(ssl);
		if (cert == NULL) {
			BIO_printf(outbio, "Error: Could not get certificate!\n");
			exit(1);
		}
		certname = X509_NAME_new();
		certname = X509_get_subject_name(cert);
	}
#endif

	/* IRC user */
	raw("USER %s 0 0 :%s\r\n", NICK, NICK);
	raw("NICK %s\r\n", NICK);
	printf("Joined IRC!\n");

	/* Add initial channel to list */
	char *chanlist = strdup(CHAN);
	char *pt;
	pt = strtok(chanlist,",");
	while (pt != NULL) {
		insert_first(pt);
		pt = strtok(NULL, ",");
	}

	/* IRC messages */
#ifdef SSL_IRC
	while (sl = SSL_read(ssl, sbuf, 512))
#else
	while (sl = read(conn, sbuf, 512))
#endif
		for (i = 0; i < sl; i++) {
			o++;
			buf[o] = sbuf[i];
			if ((i > 0 && sbuf[i] == '\n' && sbuf[i-1] == '\r') || o == 512) {
				buf[o + 1] = '\0';
				l = o;
				o = -1;

#ifdef VERBOSE
				printf(">> %s", buf);
#endif

				/* Deal with PINGs */
				if (!strncmp(buf, "PING", 4)) {
					buf[1] = 'O';
					raw(buf);
				/* Messages */
				} else if (buf[0] == ':') {
					wordcount = 0;
					user = command = where = message = NULL;
					/* Separate words */
					for (j = 1; j < l; j++) {
						if (buf[j] == ' ') {
							buf[j] = '\0';
							wordcount++;
							switch (wordcount) {
							case 1:
								user = buf + 1;
								break;
							case 2:
								command = buf + start;
								break;
							case 3:
								where = buf + start;
								break;
							}
							if (j == l - 1)
								continue;
							start = j + 1;
						} else if (buf[j] == ':' && wordcount == 3) {
							if (j < l - 1)
								message = buf + j + 1;
							break;
						}
					}

					if (wordcount < 2)

					/* Join a channel */
					sleep(1);
					if (!strncmp(command, "001", 3)) {
#ifdef PASS
						raw("PRIVMSG NickServ :IDENTIFY %s\r\n", PASS);
						sleep(1);
						raw("PRIVMSG HostServ :ON\r\n", PASS);
						sleep(1);
#endif
						raw("JOIN %s\r\n", CHAN);
						printf("Identified for nick, and joined channel!\n");
					/* Incoming messages */
					} else if (!strncmp(command, "PRIVMSG", 7)
					|| !strncmp(command, "NOTICE", 6)) {
						if (where == NULL || message == NULL)
							continue;
						if ((sep = strchr(user, '!')) != NULL) {
							user[sep - user] = '\0';
							ident = sep + 1;
							if ((sep = strchr(ident, '@')) != NULL) {
								ident[sep - ident] = '\0';
								vhost = sep + 1;
							}
						}
						if (where[0] == '#' || where[0] == '&' || where[0] == '+' || where[0] == '!')
							target = where;
						else
							target = user;

						if (target == user) {
							if (!strncmp(message, "JOIN ", 5) && auth(ident,vhost)) {
								raw("%s\r\n", message);
								char *p = message+5;
								while (*p++) if (*p == '\n' || *p == '\r' || *p == ' ') *p = '\0';
								insert_first(message+5);
								raw("PRIVMSG %s :Joined %s\r\n", target, message+5);
							} else if (!strncmp(message, "JOIN", 4) && auth(ident, vhost)) {
								raw("PRIVMSG %s :%s\r\n", target, "Usage: JOIN #<channel name>");
							}
							if (!strncmp(message, "LEAVE ", 6) && auth(ident, vhost)) {
								raw("PART %s\r\n", message+6);
								char *p = message+5;
								while (*p++) if (*p == '\n' || *p == '\r' || *p == ' ') *p = '\0';
								delete(message+6);
								raw("PRIVMSG %s :Left %s\r\n", target, message+6);
							} else if (!strncmp(message, "LEAVE", 5) && auth(ident, vhost)) {
								raw("PRIVMSG %s :%s\r\n", target, "Usage: LEAVE #<channel name>");
							}
							if (!strncmp(message, "HELP", 4) && auth(ident, vhost)) {
								raw("PRIVMSG %s :%s\r\n", target, "IRC Web Hook Bot (https://barryserver.net/)");
								raw("PRIVMSG %s :%s\r\n", target, "Commands:");
								raw("PRIVMSG %s :%s\r\n", target, "  JOIN #<channel>");
								raw("PRIVMSG %s :%s\r\n", target, "    Joins the specified channel");
								raw("PRIVMSG %s :%s\r\n", target, "  LEAVE #<channel>");
								raw("PRIVMSG %s :%s\r\n", target, "    Parts the specified channel");
								raw("PRIVMSG %s :%s\r\n", target, "  HELP");
								raw("PRIVMSG %s :%s\r\n", target, "    Shows this message");
							}
						}

#ifdef VERBOSE
						printf(
							"[from: %s] [reply-with: %s] [where: %s] [reply-to: %s] %s",
							user, command, where, target, message
						);
#endif
					}
				}
			}
		}

#ifdef SSL_IRC
	SSL_free(ssl);
	X509_free(cert);
	SSL_CTX_free(ctx);
#endif
	close(conn);
}