diff options
author | Laurent Bercot <ska-skaware@skarnet.org> | 2014-12-15 23:08:59 +0000 |
---|---|---|
committer | Laurent Bercot <ska-skaware@skarnet.org> | 2014-12-15 23:08:59 +0000 |
commit | e0fc82203d677a6f1e808e9a1a46176c109d89be (patch) | |
tree | e9609209b755e3f7a8480aea86601ffe9d4ca540 /src/minidentd | |
download | s6-networking-e0fc82203d677a6f1e808e9a1a46176c109d89be.tar.xz |
Initial commit
Diffstat (limited to 'src/minidentd')
-rwxr-xr-x | src/minidentd/deps-exe/minidentd | 4 | ||||
-rw-r--r-- | src/minidentd/mgetuid-default.c | 15 | ||||
-rw-r--r-- | src/minidentd/mgetuid-linux.c | 169 | ||||
-rw-r--r-- | src/minidentd/mgetuid.h | 11 | ||||
-rw-r--r-- | src/minidentd/minidentd.c | 273 |
5 files changed, 472 insertions, 0 deletions
diff --git a/src/minidentd/deps-exe/minidentd b/src/minidentd/deps-exe/minidentd new file mode 100755 index 0000000..37c2de8 --- /dev/null +++ b/src/minidentd/deps-exe/minidentd @@ -0,0 +1,4 @@ +mgetuid.o +-lskarnet +${SOCKET_LIB} +${TAINNOW_LIB} diff --git a/src/minidentd/mgetuid-default.c b/src/minidentd/mgetuid-default.c new file mode 100644 index 0000000..6c9ae9b --- /dev/null +++ b/src/minidentd/mgetuid-default.c @@ -0,0 +1,15 @@ +/* ISC license. */ + +#include <errno.h> +#include <skalibs/uint16.h> +#include <skalibs/uint32.h> +#include "mgetuid.h" + +int mgetuid (ip46_t const *localaddr, uint16 localport, ip46_t const *remoteaddr, uint16 remoteport) +{ + (void)localaddr ; + (void)localport ; + (void)remoteaddr ; + (void)remoteport ; + return (errno = ENOSYS, -2) ; +} diff --git a/src/minidentd/mgetuid-linux.c b/src/minidentd/mgetuid-linux.c new file mode 100644 index 0000000..442f642 --- /dev/null +++ b/src/minidentd/mgetuid-linux.c @@ -0,0 +1,169 @@ +/* ISC license. */ + +#include <skalibs/uint16.h> +#include <skalibs/uint32.h> +#include <skalibs/uint.h> +#include <skalibs/bytestr.h> +#include <skalibs/fmtscan.h> +#include <skalibs/buffer.h> +#include <skalibs/stralloc.h> +#include <skalibs/djbunix.h> +#include <skalibs/ip46.h> +#include <skalibs/skamisc.h> +#include "mgetuid.h" + +#ifdef DEBUG +#include <skalibs/strerr2.h> +#define bug(a) do { strerr_warn4x("bug parsing ", a, "remaining: ", cur) ; return 0 ; } while (0) +#else +#define bug(a) return 0 +#endif + +#define LINESIZE 256 + +static int skipspace (char **s) +{ + while (**s && ((**s == ' ') || (**s == '\t'))) + (*s)++ ; + return (int)**s ; +} + +static int parseline (char *s, unsigned int len, unsigned int *u, char *la, uint16 *lp, char *ra, uint16 *rp, int is6) +{ + char *cur = s ; + unsigned int pos ; + uint32 junk ; + register unsigned int iplen = is6 ? 16 : 4 ; + + if (!skipspace(&cur)) bug("initial whitespace") ; + pos = uint32_scan(cur, &junk) ; /* sl */ + if (!pos || (cur-s+1+pos) > len) bug("sl") ; + cur += pos ; + if ((*cur++) != ':') bug("sl:") ; + if (!skipspace(&cur)) bug("sl: SPACE") ; + + if ((cur - s + 1 + iplen) > len) bug("local_address") ; + pos = ucharn_scan(cur, la, iplen) ; /* local_address */ + if (!pos) bug("local_address") ; + cur += pos ; + if ((*cur++) != ':') bug("local_address:") ; + + pos = uint16_xscan(cur, lp) ; /* :port */ + if (!pos || (cur-s+pos) > len) bug("local_port") ; + cur += pos ; + if (!skipspace(&cur)) bug("local_port SPACE") ; + + if ((cur - s + 1 + iplen) > len) bug("remote_address") ; + pos = ucharn_scan(cur, ra, iplen) ; /* remote_address */ + if (!pos) bug("remote_address") ; + cur += pos ; + if ((*cur++) != ':') bug("remote_address:") ; + + pos = uint16_xscan(cur, rp) ; /* :port */ + if (!pos || (cur-s+pos) > len) bug("remote_port") ; + cur += pos ; + if (!skipspace(&cur)) bug("remote_port SPACE"); + + pos = uint32_xscan(cur, &junk) ; /* st */ + if (!pos || (cur-s+pos) > len) bug("st") ; + cur += pos ; + if (!skipspace(&cur)) bug("st SPACE") ; + pos = uint32_xscan(cur, &junk) ; /* tx_queue */ + if (!pos || (cur-s+1+pos) > len) bug("tx_queue") ; + cur += pos ; + if ((*cur++) != ':') bug("tx_queue:") ; + pos = uint32_xscan(cur, &junk) ; /* rx_queue */ + if (!pos || (cur-s+pos) > len) bug("rx_queue") ; + cur += pos ; + if (!skipspace(&cur)) bug("rx_queue SPACE") ; + pos = uint32_xscan(cur, &junk) ; /* tr */ + if (!pos || (cur-s+1+pos) > len) bug("tr") ; + cur += pos ; + if ((*cur++) != ':') bug("tr:") ; + pos = uint32_xscan(cur, &junk) ; /* tm->when */ + if (!pos || (cur-s+pos) > len) bug("tm->when") ; + cur += pos ; + if (!skipspace(&cur)) bug("tm->when SPACE") ; + pos = uint32_xscan(cur, &junk) ; /* retrnsmt */ + if (!pos || (cur-s+pos) > len) bug("retrnsmt") ; + cur += pos ; + + if (!skipspace(&cur)) bug("retrnsmt SPACE") ; + pos = uint_scan(cur, u) ; /* uid */ + if (!pos || (cur-s+1+pos) > len) bug("uid") ; + + return 1 ; +} + +#ifdef DEBUG + +static void debuglog (uint16 a, uint16 b, unsigned int c, char const *d, char const *e, int is6) +{ + char sa[UINT16_FMT] ; + char sb[UINT16_FMT] ; + char sc[UINT_FMT] ; + char sd[IP46_FMT] ; + char se[IP46_FMT] ; + + sa[uint16_fmt(sa, a)] = 0 ; + sb[uint16_fmt(sb, b)] = 0 ; + sc[uint_fmt(sc, c)] = 0 ; + sd[is6 ? ip6_fmt(sd, d) : ip4_fmt(sd, d)] = 0 ; + se[is6 ? ip6_fmt(se, e) : ip4_fmt(se, e)] = 0 ; + + buffer_puts(buffer_2, sd) ; + buffer_puts(buffer_2, ":") ; + buffer_puts(buffer_2, sa) ; + buffer_puts(buffer_2, " , ") ; + buffer_puts(buffer_2, se) ; + buffer_puts(buffer_2, ":") ; + buffer_puts(buffer_2, sb) ; + buffer_puts(buffer_2, " -> ") ; + buffer_puts(buffer_2, sc) ; + buffer_putsflush(buffer_2, "\n") ; +} + +#endif + +int mgetuid (ip46_t const *localaddr, uint16 localport, ip46_t const *remoteaddr, uint16 remoteport) +{ + int r ; + int u = -2 ; + stralloc line = STRALLOC_ZERO ; + buffer b ; + char y[BUFFER_INSIZE] ; + register int is6 = ip46_is6(localaddr) ; + int fd = open_readb(is6 ? "/proc/net/tcp6" : "/proc/net/tcp") ; + if (fd == -1) return -2 ; + buffer_init(&b, &buffer_read, fd, y, BUFFER_INSIZE_SMALL) ; + if (skagetln(&b, &line, '\n') < 1) goto err ; +#ifdef DEBUG + line.s[line.len-1] = 0 ; + debuglog(localport, remoteport, 65535, localaddr->ip, remoteaddr->ip, is6) ; +#endif + for (;;) + { + char la[16] ; + char ra[16] ; + unsigned int nu ; + uint16 lp, rp ; + line.len = 0 ; + r = skagetln(&b, &line, '\n') ; + if (r <= 0) { u = -1 ; break ; } + line.s[line.len-1] = 0 ; + if (!parseline(line.s, line.len, &nu, la, &lp, ra, &rp, is6)) break ; +#ifdef DEBUG + debuglog(lp, rp, nu, la, ra, is6) ; +#endif + if ((lp == localport) && (rp == remoteport) + && !byte_diff(la, is6 ? 16 : 4, localaddr->ip) + && !byte_diff(ra, is6 ? 16 : 4, remoteaddr->ip)) + { + u = nu ; break ; + } + } + stralloc_free(&line) ; + err: + fd_close(fd) ; + return u ; +} diff --git a/src/minidentd/mgetuid.h b/src/minidentd/mgetuid.h new file mode 100644 index 0000000..0572385 --- /dev/null +++ b/src/minidentd/mgetuid.h @@ -0,0 +1,11 @@ +/* ISC license. */ + +#ifndef MGETUID_H +#define MGETUID_H + +#include <skalibs/uint16.h> +#include <skalibs/ip46.h> + +extern int mgetuid (ip46_t const *, uint16, ip46_t const *, uint16) ; + +#endif 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 ; +} |