IRCWebHooks
Barry Making admin auths optional 46d7b3c (4 years, 1 month 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);
}