diff options
Diffstat (limited to 'src/minidentd/minidentd.c')
-rw-r--r-- | src/minidentd/minidentd.c | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/src/minidentd/minidentd.c b/src/minidentd/minidentd.c new file mode 100644 index 0000000..0bd86be --- /dev/null +++ b/src/minidentd/minidentd.c @@ -0,0 +1,273 @@ +/* ISC license. */ + +#include <unistd.h> +#include <errno.h> +#include <pwd.h> +#include <skalibs/uint16.h> +#include <skalibs/uint32.h> +#include <skalibs/uint.h> +#include <skalibs/allreadwrite.h> +#include <skalibs/bytestr.h> +#include <skalibs/fmtscan.h> +#include <skalibs/buffer.h> +#include <skalibs/strerr2.h> +#include <skalibs/stralloc.h> +#include <skalibs/djbunix.h> +#include <skalibs/sgetopt.h> +#include <skalibs/tai.h> +#include <skalibs/random.h> +#include <skalibs/unix-timed.h> +#include "mgetuid.h" + +#define USAGE "minidentd [ -v ] [ -n | -i | -r ] [ -y file ] [ -t timeout ]" +#define dieusage() strerr_dieusage(100, USAGE) + + +static int how = 0 ; +static int flagverbose = 0 ; +static char const *userfile = ".ident" ; + +static tain_t deadline ; +static unsigned int nquery = 0 ; +static char logfmt[UINT_FMT] ; + +#define DECIMAL "0123456789" +#define godecimal(s) while (*(s) && !DECIMAL[str_chr(DECIMAL, *(s))]) (s)++ + +static int parseline (char const *s, uint16 *localport, uint16 *remoteport) +{ + unsigned int pos = 0 ; + + godecimal(s) ; + if (!*s) return 0 ; + s += uint16_scan(s, localport) ; + if (!*s) return 0 ; + s += str_chr(s+pos, ',') ; + if (*s) s++ ; + godecimal(s) ; + if (!*s) return 0 ; + if (!uint16_scan(s, remoteport)) return 0 ; + return 1 ; +} + +static void formatlr (char *s, uint16 lp, uint16 rp) +{ + s += uint16_fmt(s, lp) ; + *s++ = ',' ; + *s++ = ' ' ; + s += uint16_fmt(s, rp) ; + *s = 0 ; +} + +static void reply (char const *s, char const *r, char const *info) +{ + buffer_puts(buffer_1small, s) ; + buffer_put(buffer_1small, " : ", 3) ; + buffer_puts(buffer_1small, r) ; + buffer_put(buffer_1small, " : ", 3) ; + buffer_puts(buffer_1small, info) ; + buffer_put(buffer_1small, "\r\n", 2) ; + if (!buffer_timed_flush_g(buffer_1small, &deadline)) + strerr_diefu1sys(111, "write to stdout") ; +} + +static void logquery (char const *s) +{ + if (!flagverbose) return ; + logfmt[uint_fmt(logfmt, ++nquery)] = 0 ; + buffer_put(buffer_2, "query ", 6) ; + buffer_puts(buffer_2, logfmt) ; + buffer_put(buffer_2, ": ", 2) ; + buffer_puts(buffer_2, s) ; + buffer_putflush(buffer_2, "\n", 1) ; +} + +static void logreply (char const *type, char const *reply1, char const *reply2) +{ + if (!flagverbose) return ; + buffer_puts(buffer_2, "reply type ") ; + buffer_puts(buffer_2, type) ; + buffer_put(buffer_2, ": ", 2) ; + buffer_puts(buffer_2, logfmt) ; + buffer_put(buffer_2, ": ", 2) ; + buffer_puts(buffer_2, reply1) ; + buffer_put(buffer_2, ": ", 2) ; + buffer_puts(buffer_2, reply2) ; + buffer_putflush(buffer_2, "\n", 1) ; +} + +static int userident (char *s, char const *home) +{ + int fd ; + int r = 1 ; + { + unsigned int homelen = str_len(home) ; + unsigned int userlen = str_len(userfile) ; + char tmp[homelen + userlen + 2] ; + byte_copy(tmp, homelen, home) ; + tmp[homelen] = '/' ; + byte_copy(tmp + homelen + 1, userlen + 1, userfile) ; + fd = open_readb(tmp) ; + } + if (fd == -1) return (errno != ENOENT) ? -1 : 0 ; + if (how == 1) + { + fd_close(fd) ; + return 1 ; + } + r = allread(fd, s, 14) ; + fd_close(fd) ; + if (r == -1) return -1 ; + if (!r) return 1 ; + s[r] = 0 ; + s[byte_chr(s, r, '\n')] = 0 ; + return 2 ; +} + + +static void doit (char const *s, ip46_t const *localaddr, ip46_t const *remoteaddr) +{ + char lr[15] ; + uint16 localport, remoteport ; + struct passwd *pw ; + int uid ; + if (!parseline(s, &localport, &remoteport)) + { + reply("0, 0", "ERROR", "INVALID-PORT") ; + return ; + } + formatlr(lr, localport, remoteport) ; + logquery(lr) ; + + uid = mgetuid(localaddr, localport, remoteaddr, remoteport) ; + if (uid == -2) + { + strerr_warnwu1sys("get uid") ; + reply(lr, "ERROR", "UNKNOWN-ERROR") ; + return ; + } + else if (uid == -1) + { + reply(lr, "ERROR", "NO-USER") ; + logreply("error", "ERROR", "NO-USER") ; + return ; + } + + if (how == 3) + { + char name[9] ; + char fmt[4 + UINT_FMT] = "uid " ; + fmt[4 + uint_fmt(fmt+4, uid)] = 0 ; + if (random_name(name, 8) < 8) + { + strerr_warnwu1sys("perform random") ; + reply(lr, "ERROR", "UNKNOWN-ERROR") ; + return ; + } + reply(lr, "UNIX", name) ; + logreply("random", fmt, name) ; + return ; + } + + pw = getpwuid(uid) ; + if (!pw) + { + char fmt[UINT_FMT] ; + fmt[uint_fmt(fmt, uid)] = 0 ; + strerr_warnw2x("unknown uid ", fmt) ; + reply(lr, "ERROR", "UNKNOWN-ERROR") ; + return ; + } + + if (how) + { + char s[15] ; + register int r = userident(s, pw->pw_dir) ; + if ((how == 1) || (r == 1)) + { + reply(lr, "ERROR", "HIDDEN-USER") ; + logreply("user", "ERROR", "HIDDEN-USER") ; + return ; + } + else if (r == 2) + { + reply(lr, "USERID : UNIX", s) ; + logreply("user", "UNIX", s) ; + return ; + } + } + + reply(lr, "USERID : UNIX", pw->pw_name) ; + logreply("user", "UNIX", pw->pw_name) ; +} + + +int main (int argc, char const *const *argv, char const *const *envp) +{ + stralloc line = STRALLOC_ZERO ; + tain_t tto ; + ip46_t localaddr, remoteaddr ; + PROG = "minidentd" ; + + { + subgetopt_t l = SUBGETOPT_ZERO ; + unsigned int t = 0 ; + for (;;) + { + register int opt = subgetopt_r(argc, argv, "vniry:t:", &l) ; + if (opt == -1) break ; + switch (opt) + { + case 'v' : flagverbose = 1 ; break ; + case 'n' : how = 1 ; break ; + case 'i' : how = 2 ; break ; + case 'r' : how = 3 ; break ; + case 'y' : userfile = l.arg ; break ; + case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ; + default : dieusage() ; + } + } + if (t) tain_from_millisecs(&tto, t) ; else tto = tain_infinite_relative ; + argc -= l.ind ; argv += l.ind ; + } + + { + char const *proto = env_get2(envp, "PROTO") ; + if (!proto) strerr_dienotset(100, "PROTO") ; + { + char const *x ; + unsigned int protolen = str_len(proto) ; + char tmp[protolen + 9] ; + byte_copy(tmp, protolen, proto) ; + byte_copy(tmp + protolen, 8, "LOCALIP") ; + x = env_get2(envp, tmp) ; + if (!x) strerr_dienotset(100, tmp) ; + if (!ip46_scan(x, &localaddr)) strerr_dieinvalid(100, tmp) ; + byte_copy(tmp + protolen, 9, "REMOTEIP") ; + x = env_get2(envp, tmp) ; + if (!x) strerr_dienotset(100, tmp) ; + if (!ip46_scan(x, &remoteaddr)) strerr_dieinvalid(100, tmp) ; + } + } + + if (ip46_is6(&localaddr) != ip46_is6(&remoteaddr)) + strerr_dief1x(100, "local and remote address not of the same family") ; + tain_now_g() ; + + for (;;) + { + register int r ; + line.len = 0 ; + tain_add_g(&deadline, &tto) ; + r = timed_getln_g(buffer_0small, &line, '\n', &deadline) ; + if (r == -1) + { + if (errno == ETIMEDOUT) return 1 ; + else strerr_diefu1sys(111, "read from stdin") ; + } + if (!r) break ; + line.s[line.len - 1] = 0 ; + doit(line.s, &localaddr, &remoteaddr) ; + } + return 0 ; +} |