Compare commits
10 Commits
4c0746156e
...
4a74b5bcfc
Author | SHA1 | Date | |
---|---|---|---|
4a74b5bcfc | |||
![]() |
2be3612092 | ||
![]() |
614260fef6 | ||
![]() |
124a071881 | ||
![]() |
d8c39673f9 | ||
![]() |
9336c3bb36 | ||
![]() |
6755e15ce8 | ||
![]() |
ab3bb32b6d | ||
![]() |
e26e89966f | ||
![]() |
094a76c402 |
4
Makefile
4
Makefile
@ -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
43
README
@ -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
24
cmd.c
@ -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
33
dns.c
@ -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
42
icb.c
@ -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
22
icbd.c
@ -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");
|
||||
}
|
||||
|
23
logger.c
23
logger.c
@ -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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user