summaryrefslogtreecommitdiff
path: root/src/minidentd
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2014-12-15 23:08:59 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2014-12-15 23:08:59 +0000
commite0fc82203d677a6f1e808e9a1a46176c109d89be (patch)
treee9609209b755e3f7a8480aea86601ffe9d4ca540 /src/minidentd
downloads6-networking-e0fc82203d677a6f1e808e9a1a46176c109d89be.tar.xz
Initial commit
Diffstat (limited to 'src/minidentd')
-rwxr-xr-xsrc/minidentd/deps-exe/minidentd4
-rw-r--r--src/minidentd/mgetuid-default.c15
-rw-r--r--src/minidentd/mgetuid-linux.c169
-rw-r--r--src/minidentd/mgetuid.h11
-rw-r--r--src/minidentd/minidentd.c273
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 ;
+}