Compare commits

...

10 Commits

Author SHA1 Message Date
4a74b5bcfc Nitori Engineering 2025-04-17 20:33:16 -03:00
Mike Belopuhov
2be3612092 Allow moderators to pass moderation to other users 2017-08-30 02:13:47 +02:00
Mike Belopuhov
614260fef6 Fixup debug printf 2017-08-30 02:12:02 +02:00
Mike Belopuhov
124a071881 Use the same pattern when creating Status and Error messages 2017-08-30 02:11:44 +02:00
Mike Belopuhov
d8c39673f9 Fix off-by-one in icb_sendfmt 2017-08-29 21:28:34 +02:00
Mike Belopuhov
9336c3bb36 typo 2017-08-28 16:49:01 +02:00
Mike Belopuhov
6755e15ce8 Avoid comma operator 2017-08-25 00:16:42 +02:00
Mike Belopuhov
ab3bb32b6d Convert while into a for loop 2017-08-25 00:09:11 +02:00
Mike Belopuhov
e26e89966f Spacing 2017-08-24 23:47:11 +02:00
Mike Belopuhov
094a76c402 Another lurking setusercontext 2017-08-24 23:46:25 +02:00
7 changed files with 143 additions and 48 deletions

View File

@ -1,14 +1,16 @@
PREFIX?= /usr/local
BINDIR= ${PREFIX}/sbin
MANDIR= ${PREFIX}/man/man
MANDIR= ${PREFIX}/man/man8
PROG= icbd
SRCS= cmd.c dns.c icb.c icbd.c logger.c
MAN= icbd.8
.ifdef __OpenBSD__
CFLAGS+= -W -Wall -Werror
CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations
CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual -Wsign-compare
.endif
DPADD= ${LIBEVENT}
LDADD= -levent

43
README
View File

@ -1,5 +1,38 @@
icbd: a simple ICB daemon written in C
======================================
http://www.icb.net/
http://www.icb.net/_jrudd/icb/protocol.html
_____________________
( A simple ICB daemon )
---------------------
\
\
\ ,__--**@@@**--__,
\ ,@%* *%@m,
,@* # +@*# @ *@,
,@* @ # __ @ @,
,*@m#, @, m*@ %_- ,@ ,#m@*,
,@@*-% @ # # @ %-+m,
@ @ @#=====#================#=====#@ @ %,
@* ,*@m,## ##,m@*, @
# :@ #====---__________________---====# @: @
@* :@ @ @. @: @
@ *m__m* #m, .# *m__* @
@ @ .# % @ @ @ =- @*
*, % ,% @ @ @ @. *% #, .- ,@
@ *@ @ @, @ *@ :@ @ ,@ *, @. @
@ @@. % *# @ ,@* #+* % .@ @
@ % @, @ m--#@+*+@#-- # --#@+*+@#--m @ ,@+ @
.@ @ *@# | @ @ @ @ @ @ | +@ ,@ % *,
,@ @, @ @*^ @ @*^ @ @ #%* @ %,
,@ *% @ @ @ % @ @ @ %
@ ,*@ % *=_=* *=_=* % ,*+ @
%* m* @ % % % @, @
@ @* % ,@ @, @ @ @:
@ @ @ @ *_* @ @ @ @:
@: %, %, @**__, ,__**@ @ _% @
@, *_ @, @ @. *--__, ,__--* .@ @ @ #, ,@*
*--__+# @, @ @, . ^^^^^ . ,@ * ,@ *+@@*
^*+# *%__*%,m***m,%*__%* #@@+*
O O *=
*m_m*
# #
# @*#
# -#
#+*^

24
cmd.c
View File

@ -326,10 +326,11 @@ icb_cmd_pass(struct icb_session *is, char *arg)
struct icb_session *s;
char whom[ICB_MAXNICKLEN];
if (!ig->mod) { /* if there is no mod, try grabbing it */
if (icb_modpermit(is, 0) && icb_pass(ig, ig->mod, is) < 0)
icb_error(is, "Acquiring group moderation failed.");
} else if (icb_ismod(ig, is)) {
if (icb_ismod(ig, is)) {
/*
* we're a current group moderator, allow to relinquish
* the right and to pass it down to everybody else.
*/
if (strlen(arg) == 0) {
/* no argument: relinquish moderator */
(void)icb_pass(ig, ig->mod, NULL);
@ -344,16 +345,21 @@ icb_cmd_pass(struct icb_session *is, char *arg)
icb_status(is, STATUS_NOTIFY, "No such user");
return;
}
if (icb_modpermit(s, 0) && icb_pass(ig, ig->mod, s) < 0)
icb_error(s, "Acquiring group moderation failed.");
if (icb_pass(ig, ig->mod, s) < 0)
icb_error(is, "Failed to pass group moderation.");
} else {
/*
* if group is moderated and we're not the moderator,
* but modtab is enabled, then check the permission
* and pass moderation if successful.
* and pass moderation if successful. if there's no
* current moderator, don't enforce the modtab.
*/
if (icb_modpermit(is, 1) && icb_pass(ig, ig->mod, is) < 0)
icb_error(is, "Acquiring group moderation failed.");
if (!icb_modpermit(is, ig->mod ? 1 : 0)) {
icb_error(is, "Operation not permitted.");
return;
}
if (icb_pass(ig, ig->mod, is) < 0)
icb_error(is, "Failed to acquire group moderation.");
}
}

33
dns.c
View File

@ -27,7 +27,18 @@
#include <string.h>
#include <syslog.h>
#ifdef __NetBSD__
#define NO_ASYNC
#endif
#ifdef NO_ASYNC
struct asr_result {
struct addrinfo* ar_addrinfo;
int ar_gai_errno;
};
#else
#include <asr.h>
#endif
#include "icb.h"
#include "icbd.h"
@ -85,7 +96,11 @@ void
dns_done_reverse(struct asr_result *ar, void *arg)
{
struct icb_session *is = arg;
#ifdef NO_ASYNC
struct asr_result result;
#else
struct asr_query *as;
#endif
struct addrinfo hints;
if (ISSETF(is->flags, ICB_SF_PENDINGDROP)) {
@ -99,8 +114,14 @@ dns_done_reverse(struct asr_result *ar, void *arg)
/* try to verify that it resolves back */
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
#ifdef NO_ASYNC
getaddrinfo(is->hostname, NULL, &hints, &result.ar_addrinfo);
result.ar_gai_errno = errno;
dns_done_host(&result, is);
#else
as = getaddrinfo_async(is->hostname, NULL, &hints, NULL);
event_asr_run(as, dns_done_host, is);
#endif
} else {
icbd_log(is, LOG_DEBUG, "reverse dns resolution failed: %s",
gai_strerror(ar->ar_gai_errno));
@ -129,7 +150,11 @@ cmp_addr(struct sockaddr *a, struct sockaddr *b)
void
dns_resolve(struct icb_session *is)
{
#ifdef NO_ASYNC
struct asr_result result;
#else
struct asr_query *as;
#endif
if (!dodns)
return;
@ -139,9 +164,17 @@ dns_resolve(struct icb_session *is)
if (verbose)
icbd_log(is, LOG_DEBUG, "resolving: %s", is->host);
#ifdef NO_ASYNC
getnameinfo((struct sockaddr *)&is->ss,
((struct sockaddr *)&is->ss)->sa_len, is->hostname,
sizeof is->hostname, NULL, 0, NI_NOFQDN);
result.ar_gai_errno = errno;
dns_done_reverse(&result, is);
#else
as = getnameinfo_async((struct sockaddr *)&is->ss,
((struct sockaddr *)&is->ss)->sa_len, is->hostname,
sizeof is->hostname, NULL, 0, NI_NOFQDN, NULL);
event_asr_run(as, dns_done_reverse, is);
#endif
}

42
icb.c
View File

@ -270,7 +270,7 @@ icb_groupmsg(struct icb_session *is, char *msg)
icbd_log(is, LOG_ERR, "Format error in %s", __func__);
return;
}
/* res doesn't include the terminating NUL*/
/* res doesn't include the terminating NUL */
buflen = MIN((size_t)res + 1, sizeof buf - 1);
buf[0] = buflen;
@ -328,7 +328,7 @@ icb_privmsg(struct icb_session *is, char *to, char *msg)
icbd_log(is, LOG_ERR, "Format error in %s", __func__);
return;
}
/* res doesn't include the terminating NUL*/
/* res doesn't include the terminating NUL */
buflen = MIN((size_t)res + 1, sizeof buf - 1);
buf[0] = buflen;
@ -400,7 +400,7 @@ icb_status(struct icb_session *is, int type, const char *fmt, ...)
{
va_list ap;
char buf[ICB_MSGSIZE];
int res, buflen = 1;
int res, buflen;
static const struct {
int type;
const char *msg;
@ -428,19 +428,24 @@ icb_status(struct icb_session *is, int type, const char *fmt, ...)
icbd_log(NULL, LOG_ERR, "Format error in %s", __func__);
return;
}
buflen += MIN((size_t)res, sizeof buf - 1);
if ((size_t)buflen >= sizeof buf) {
if ((size_t)res >= sizeof buf) {
icbd_log(NULL, LOG_ERR, "Status buffer too small");
return;
}
buflen = MIN((size_t)res + 1, sizeof buf - 1);
va_start(ap, fmt);
res = vsnprintf(&buf[buflen], sizeof buf - buflen, fmt, ap);
res = vsnprintf(&buf[buflen], sizeof buf - buflen - 1, fmt, ap);
va_end(ap);
buflen--; /* buf[buflen] was overwritten */
if (res < 0) {
icbd_log(NULL, LOG_ERR, "Format error in %s", __func__);
icbd_log(NULL, LOG_ERR, "Message format error in %s", __func__);
return;
}
buflen += MIN((size_t)res, sizeof buf - buflen);
if ((size_t)res + buflen >= sizeof buf) {
icbd_log(NULL, LOG_ERR, "Status message too long");
return;
}
buflen += MIN((size_t)res + 1, sizeof buf - buflen - 1);
buf[0] = buflen;
icbd_send(is, buf, buflen + 1);
}
@ -477,7 +482,7 @@ icb_error(struct icb_session *is, const char *fmt, ...)
{
char buf[ICB_MSGSIZE];
va_list ap;
int res, buflen = 1;
int res, buflen;
va_start(ap, fmt);
res = vsnprintf(&buf[2], sizeof buf - 2, fmt, ap);
@ -486,7 +491,7 @@ icb_error(struct icb_session *is, const char *fmt, ...)
icbd_log(NULL, LOG_ERR, "Format error");
return;
}
buflen += MIN((size_t)res, sizeof buf - 2);
buflen = MIN((size_t)res + 1, sizeof buf - 2);
buf[0] = ++buflen; /* account for ICB_M_ERROR */
buf[1] = ICB_M_ERROR;
icbd_send(is, buf, buflen + 1);
@ -573,7 +578,11 @@ icb_dowho(struct icb_session *is, struct icb_group *ig)
icb_cmdout(is, CMDOUT_CO, buf);
LIST_FOREACH(s, &ig->sess, entry) {
(void)snprintf(buf, sizeof buf,
#ifdef __NetBSD__
"%c%c%s%c%ld%c0%c%ld%c%s%c%s%c%s",
#else
"%c%c%s%c%lld%c0%c%lld%c%s%c%s%c%s",
#endif
icb_ismod(ig, s) ? 'm' : ' ', ICB_M_SEP,
s->nick, ICB_M_SEP, now - s->last,
ICB_M_SEP, ICB_M_SEP, s->login, ICB_M_SEP,
@ -671,7 +680,7 @@ icb_sendfmt(struct icb_session *is, const char *fmt, ...)
{
char buf[ICB_MSGSIZE];
va_list ap;
int res, buflen = 1;
int res, buflen;
va_start(ap, fmt);
res = vsnprintf(&buf[1], sizeof buf - 1, fmt, ap);
@ -680,7 +689,7 @@ icb_sendfmt(struct icb_session *is, const char *fmt, ...)
icbd_log(NULL, LOG_ERR, "Format error in %s", __func__);
return;
}
buflen += MIN((size_t)res + 1, sizeof buf - 1);
buflen = MIN((size_t)res + 1, sizeof buf - 1);
buf[0] = buflen;
icbd_send(is, buf, buflen + 1);
}
@ -757,13 +766,15 @@ icb_trim(char *buf, int len)
int
icb_vis(char *dst, const char *src, size_t dstsize, int flags)
{
int si = 0, di = 0, td;
int si, di, td;
while ((size_t)di < dstsize - 1 && src[si] != '\0') {
for (si = 0, di = 0; (size_t)di < dstsize - 1 && src[si] != '\0';
si++, di++) {
if (src[si] == '%') {
if ((size_t)di + 1 >= dstsize - 1)
break;
dst[di++] = '%', dst[di] = '%';
dst[di++] = '%';
dst[di] = '%';
} else if (src[si] == ' ' && flags & VIS_SP)
dst[di] = '_';
else if (isgraph(src[si]) || src[si] == ' ')
@ -775,7 +786,6 @@ icb_vis(char *dst, const char *src, size_t dstsize, int flags)
break;
di += td - 1;
}
si++, di++;
}
dst[MIN((size_t)di, dstsize - 1)] = '\0';
return (0);

22
icbd.c
View File

@ -1,6 +1,8 @@
/*
* Copyright (c) 2009 Mike Belopuhov
* Copyright (c) 2007 Oleg Safiullin
* Copyright (c) 2024 Nishi
* Copyright (C) 2025 Izuru Yakumo
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -174,12 +176,21 @@ main(int argc, char *argv[])
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
#ifdef __OpenBSD__
/* Apparently OpenBSD is the only one that has icb on /etc/services */
/* Sure, it could be easily added to any other system, but I'm personally against it */
/* ~Izuru Yakumo */
if ((error = getaddrinfo(addr, port ? port : "icb", &hints,
&res0)) != 0) {
syslog(LOG_ERR, "%s", gai_strerror(error));
return (EX_UNAVAILABLE);
}
#else
if ((error = getaddrinfo(addr, port ? port : "7326", &hints, &res0)) != 0) {
syslog(LOG_ERR, "%s", gai_strerror(error));
return (EX_UNAVAILABLE);
}
#endif
for (res = res0; res != NULL; res = res->ai_next) {
if ((s = socket(res->ai_family, res->ai_socktype,
res->ai_protocol)) < 0) {
@ -392,7 +403,7 @@ icbd_dispatch(struct bufferevent *bev, void *arg)
/* see you next time around */
if (is->rlen < is->length)
return;
/* null-terminate the data */
/* nul-terminate the data */
is->buffer[MIN(is->rlen, ICB_MSGSIZE - 1)] = '\0';
/* process the message in full */
if (icb_input(is))
@ -475,12 +486,11 @@ icbd_restrict(void)
syslog(LOG_ERR, "%s: %m", pw->pw_name);
exit(EX_NOPERM);
}
#ifdef __OpenBSD__
if (sb.st_uid != 0 || (sb.st_mode & (S_IWGRP|S_IWOTH)) != 0) {
syslog(LOG_ERR, "bad directory permissions");
exit(EX_NOPERM);
}
if (chroot(pw->pw_dir) < 0) {
syslog(LOG_ERR, "%s: %m", pw->pw_dir);
exit(EX_UNAVAILABLE);
@ -492,12 +502,13 @@ icbd_restrict(void)
}
chdir(ICBD_HOME);
#endif
if (setuid(pw->pw_uid) < 0) {
syslog(LOG_ERR, "%d: %m", pw->pw_uid);
exit(EX_NOPERM);
}
#ifdef __OpenBSD__
if (dodns) {
if (pledge("stdio inet rpath dns", NULL) == -1) {
syslog(LOG_ERR, "pledge");
@ -509,6 +520,7 @@ icbd_restrict(void)
exit(EX_NOPERM);
}
}
#endif
(void)setproctitle("icbd");
}

View File

@ -1,6 +1,8 @@
/*
* Copyright (c) 2014 Mike Belopuhov
* Copyright (c) 2009 Michael Shalayeff
* Copyright (c) 2014 Mike Belopuhov
* Copyright (c) 2024 Nishi
* Copyright (c) 2025 Izuru Yakumo
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -30,7 +32,6 @@
#include <syslog.h>
#include <sysexits.h>
#include <time.h>
#include <login_cap.h>
#include <event.h>
#include <pwd.h>
@ -96,11 +97,7 @@ logger_init(void)
ICBD_USER);
exit(EX_NOUSER);
}
if (setusercontext(NULL, pw, pw->pw_uid,
LOGIN_SETALL & ~LOGIN_SETUSER) < 0)
exit(EX_NOPERM);
#ifdef __OpenBSD
if (chroot(pw->pw_dir) < 0) {
syslog(LOG_ERR, "%s: %s: %m", __func__, pw->pw_dir);
exit(EX_UNAVAILABLE);
@ -117,11 +114,13 @@ logger_init(void)
syslog(LOG_ERR, "%s: %d: %m", __func__, pw->pw_uid);
exit(EX_NOPERM);
}
#endif
#ifdef __OpenBSD__
if (pledge("stdio cpath wpath", NULL) == -1) {
syslog(LOG_ERR, "%s: pledge", __func__);
exit(EX_NOPERM);
}
#endif
event_init();
@ -199,16 +198,16 @@ logger_dispatch(struct bufferevent *bev, void *arg __attribute__((unused)))
res = bufferevent_read(bev, &buf[nread],
e->length - (nread - sizeof *e));
nread += res;
if (nread - sizeof *e < e->length)
return;
#ifdef DEBUG
{
printf("logger read %lu out of %lu:\n", res, e->length);
for (i = 0; i < (int)res; i++)
printf("logger read %lu\n", nread - sizeof *e);
for (i = 0; i < (int)(nread - sizeof *e); i++)
printf(" %02x", (unsigned char)m[i]);
printf("\n");
}
#endif
if (nread - sizeof *e < e->length)
return;
/* terminate the buffer */
m[MIN(nread - sizeof *e, ICB_MSGSIZE - 1)] = '\0';
/* find the appropriate log file */