diff options
| -rw-r--r-- | Makefile | 1 | ||||
| -rw-r--r-- | config.c | 73 | ||||
| -rw-r--r-- | config.h | 15 | ||||
| -rw-r--r-- | config.irc | 2 | ||||
| -rw-r--r-- | handle.c | 64 | ||||
| -rw-r--r-- | ircd.h | 6 | ||||
| -rw-r--r-- | main.c | 15 | ||||
| -rw-r--r-- | reply.c | 40 |
8 files changed, 205 insertions, 11 deletions
diff --git a/Makefile b/Makefile index e70390f..b9d6948 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,7 @@ NAME ?= ircd CFLAGS += -Wall -Wextra OBJS += channel.o +OBJS += config.o OBJS += handle.o OBJS += loop.o OBJS += main.o diff --git a/config.c b/config.c new file mode 100644 index 0000000..9d945eb --- /dev/null +++ b/config.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2026 Nakidai Perumenei <nakidai at disroot dot org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ircd.h" + +#include <string.h> + +#include <err.h> +#include <fcntl.h> +#include <poll.h> +#include <unistd.h> + +#include <sys/socket.h> +#include <sys/types.h> + +char creation[CREATION_MAX] = CREATION_DATE; +char info[INFO_MAX] = INFO; + +int +readcfg(const char *path) +{ + struct Peer peer; + ssize_t recvd; + int fd, ret; + + fd = open(path, O_RDONLY); + ensure(fd != -1, warn("open(%s)", path), 0); + + peer = (struct Peer){ + .fd = STDERR_FILENO, + .type = CONFIG, + }; + strlcpy(peer.nick, path, sizeof(peer.nick)); + + for (ret = 0;;) + { + recvd = read( + fd, + peer.buf + peer.recvd, + sizeof(peer.buf) - peer.recvd + ); + peer.recvd += recvd; + if (recvd == -1) + { + warn("read(%s)", path); + ++ret; + goto end; + } else if (!recvd) + { + goto end; + } else if (handle(&peer)) + { + ++ret; + goto end; + } + } +end: + close(fd); + return ret; +} diff --git a/config.h b/config.h index 394ac70..dce385b 100644 --- a/config.h +++ b/config.h @@ -15,19 +15,22 @@ */ #define CREATION_DATE "Thu Jan 1 1970 at 00:00:00 UTC" +#define INFO "The best IRC server ever \\o/" #define IRCD_VERSION "0.1.0" -#define PARAM_MAX 15 +#define INFO_MAX 64 +#define CREATION_MAX 64 +#define PARAM_MAX 15 #define MESSAGE_MAX 512 -#define PEERS_MAX 512 -#define CHANNELS_MAX 512 +#define PEERS_MAX 100 +#define CHANNELS_MAX 100 -#define CHANNEL_USERS_MAX 512 -#define CHANNEL_MODES_MAX 512 +#define CHANNEL_USERS_MAX 100 +#define CHANNEL_MODES_MAX 50 #define CHANNEL_NAME_MAX 64 -#define PEER_CHANNELS_MAX 32 +#define PEER_CHANNELS_MAX 10 #define PEER_NICK_MAX 16 #define PEER_USER_MAX 16 #define PEER_REAL_MAX 32 diff --git a/config.irc b/config.irc new file mode 100644 index 0000000..9902de4 --- /dev/null +++ b/config.irc @@ -0,0 +1,2 @@ +setcreation :Thu Jan 1 1970 at 00:00:00 UTC +setinfo :The best IRC server ever \o/ diff --git a/handle.c b/handle.c index 8e91404..9e8cb5f 100644 --- a/handle.c +++ b/handle.c @@ -282,6 +282,28 @@ quit(struct Message *msg, struct Peer *peer) } static int +setcreation(struct Message *msg, struct Peer *peer) +{ + ensure(peer->type == CONFIG, reply(peer, 481, "You're not a config file"), 0); + ensure(msg->params[0] && *msg->params[0], reply(peer, 461), 0); + + strlcpy(creation, msg->params[0], sizeof(creation)); + + return 0; +} + +static int +setinfo(struct Message *msg, struct Peer *peer) +{ + ensure(peer->type == CONFIG, reply(peer, 481, "You're not a config file"), 0); + ensure(msg->params[0] && *msg->params[0], reply(peer, 461), 0); + + strlcpy(info, msg->params[0], sizeof(info)); + + return 0; +} + +static int user(struct Message *msg, struct Peer *peer) { size_t i; @@ -304,6 +326,45 @@ user(struct Message *msg, struct Peer *peer) } static int +whois(struct Message *msg, struct Peer *peer) +{ + size_t i; + + ensure(peer->type, reply(peer, 451), 0); + ensure(msg->params[0] && *msg->params[0], reply(peer, 431), 0); + + for (i = 0; i < peers_c; ++i) + if (!strcmp(msg->params[0], peers[i].nick)) + break; + ensure(i != peers_c, reply(peer, 401, msg->params[0]), 0); + + reply( + peer, + 311, + peers[i].nick, + peers[i].user, + peers[i].host, + peers[i].real + ); + reply( + peer, + 312, + peers[i].nick, + hostname, + info + ); + if (peers[i].modes & OPER) + reply( + peer, + 313, + peers[i].nick + ); + reply(peer, 318, peer[i].nick); + + return 0; +} + +static int default_handler(struct Message *msg, struct Peer *peer) { ensure(peer->type, (void)0, 0); @@ -326,7 +387,10 @@ static struct Handler { { "pong", pong }, { "privmsg", privmsg }, { "quit", quit }, + { "setcreation", setcreation }, + { "setinfo", setinfo }, { "user", user }, + { "whois", whois }, }; Handler * diff --git a/ircd.h b/ircd.h index 0cde9e0..1f5bba8 100644 --- a/ircd.h +++ b/ircd.h @@ -38,7 +38,7 @@ struct Message struct Peer { int fd; - enum ClientType { UNREGD, CLIENT, SERVER, SERVICE } type; + enum ClientType { UNREGD, CLIENT, CONFIG, SERVER, SERVICE } type; char nick[PEER_NICK_MAX], user[PEER_USER_MAX], real[PEER_REAL_MAX], host[PEER_HOST_MAX]; struct Channel *channels[PEER_CHANNELS_MAX]; enum PeerStatus { @@ -80,6 +80,10 @@ extern size_t channels_c, peers_c; extern const char *hostname; extern const char *host; extern unsigned long port; +extern char creation[CREATION_MAX]; +extern char info[INFO_MAX]; + +int readcfg(const char *path); const char *getnick(const struct Peer *peer); enum PeerMode user_mode(char m); diff --git a/main.c b/main.c index 324309f..3c364a1 100644 --- a/main.c +++ b/main.c @@ -37,7 +37,7 @@ main(int argc, char **argv) for (i = 1; i < 4; ++i) if (!argv[i] || !*argv[i]) - errx(1, "usage: %s hostname bindaddr port", argv[0]); + errx(1, "usage: %s hostname bindaddr port [config]", argv[0]); hostname = argv[1]; host = argv[2]; port = strtoul(argv[3], &p, 10); @@ -45,9 +45,20 @@ main(int argc, char **argv) errx(1, "invalid port"); #ifdef __OpenBSD__ - if (pledge("stdio inet", "")) + if (argv[4] && unveil(argv[4], "r")) + err(1, "unveil()"); + if (pledge("stdio inet rpath unveil", "")) err(1, "pledge()"); #endif /* __OpenBSD__ */ + if (argv[4]) + readcfg(argv[4]); + +#ifdef __OpenBSD__ + if (argv[4] && (unveil(argv[4], "") || unveil(NULL, NULL))) + err(1, "unveil()"); + if (pledge("stdio inet", "")) + err(1, "pledge()"); +#endif /* __OpenBSD__ */ ircd(); } diff --git a/reply.c b/reply.c index 2cd8c04..a295da8 100644 --- a/reply.c +++ b/reply.c @@ -81,9 +81,10 @@ vreply(const struct Peer *peer, int number, va_list ap) hostname ), _); REPLY(3, WRITE( - ":%s 003 %s :This server was created " CREATION_DATE, + ":%s 003 %s :This server was created %s", hostname, - getnick(peer) + getnick(peer), + creation ), _); REPLY(4, WRITE( ":%s 004 %s :%s libreircd-" IRCD_VERSION " aiwroOs :", @@ -103,6 +104,35 @@ vreply(const struct Peer *peer, int number, va_list ap) peer->modes & LOCALOPER ? "O" : "", peer->modes & SNOTICE ? "s" : "" ), _); + REPLY(311, WRITE( + ":%s 311 %s %s %s %s * :%s", + hostname, + getnick(peer), + nick, + user, + host, + real + ), nick, user, host, real, _); + REPLY(312, WRITE( + ":%s 312 %s %s %s :%s", + hostname, + getnick(peer), + nick, + server, + info + ), nick, server, info, _); + REPLY(313, WRITE( + ":%s 313 %s %s :is an IRC operator", + hostname, + getnick(peer), + nick + ), nick, _); + REPLY(318, WRITE( + ":%s 318 %s %s :End of WHOIS list", + hostname, + getnick(peer), + nick + ), nick, _); REPLY(401, WRITE( ":%s 401 %s %s :No such nick/channel", hostname, @@ -187,6 +217,12 @@ vreply(const struct Peer *peer, int number, va_list ap) getnick(peer), channel ), channel, _); + REPLY(481, WRITE( + ":%s 481 %s :Permission Denied- %s", + hostname, + getnick(peer), + reason + ), reason, _); REPLY(484, WRITE( ":%s 484 %s :Your connection is restricted!", hostname, |