chiark / gitweb /
Initial checkin.
authorian <ian>
Sat, 29 Aug 1998 21:22:23 +0000 (21:22 +0000)
committerian <ian>
Sat, 29 Aug 1998 21:22:23 +0000 (21:22 +0000)
12 files changed:
.cvsignore [new file with mode: 0644]
Makefile [new file with mode: 0644]
authbind.c [new file with mode: 0644]
debian/.cvsignore [new file with mode: 0644]
debian/changelog [new file with mode: 0644]
debian/control [new file with mode: 0644]
debian/copyright [new file with mode: 0644]
debian/rules [new file with mode: 0755]
debian/shlibs [new file with mode: 0644]
debian/shlibs.alpha [new file with mode: 0644]
helper.c [new file with mode: 0644]
libauthbind.c [new file with mode: 0644]

diff --git a/.cvsignore b/.cvsignore
new file mode 100644 (file)
index 0000000..5f1941a
--- /dev/null
@@ -0,0 +1,4 @@
+authbind
+helper
+libauthbind.o
+libauthbind.so.0.1
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..5618a5f
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,19 @@
+#
+OPTIMISE=      -O2
+CFLAGS=                -g $(OPTIMISE) \
+               -Wall -Wwrite-strings -Wpointer-arith -Wimplicit \
+               -Wnested-externs -Wmissing-prototypes -Wstrict-prototypes
+
+TARGETS=               authbind helper libauthbind.so.0.1
+
+all:                   $(TARGETS)
+
+libauthbind.o:         libauthbind.c
+               gcc -D_REENTRANT -g $(CFLAGS) -c -o libauthbind.o -fPIC libauthbind.c
+
+libauthbind.so.0.1:    libauthbind.o
+               gcc -g -shared -Wl,-soname,libauthbind.so.0.1 -o libauthbind.so.0.1 libauthbind.o -ldl -lc
+
+clean distclean: 
+               rm -f $(TARGETS) *.o *~ ./#*# *.bak debian/*~
+               rm -f core libauthbind.so*
diff --git a/authbind.c b/authbind.c
new file mode 100644 (file)
index 0000000..6d957ae
--- /dev/null
@@ -0,0 +1,38 @@
+/**/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#define LD_PRELOAD "LD_PRELOAD"
+#define AUTHBINDLIB "AUTHBIND_LIB"
+#define LIBAUTHBIND "/usr/lib/authbind/libauthbind.so.0"
+
+int main(int argc, char *const *argv) {
+  const char *expreload, *authbindlib, *preload;
+  char *newpreload;
+
+  authbindlib= getenv(AUTHBINDLIB);
+  if (!authbindlib) {
+    if (setenv(AUTHBINDLIB,LIBAUTHBIND,0)) {
+      perror("authbind: setenv " AUTHBINDLIB);
+      exit(-1);
+    }
+    authbindlib= LIBAUTHBIND;
+  }
+    
+  if ((expreload= getenv(LD_PRELOAD))) {
+    newpreload= malloc(strlen(expreload)+strlen(authbindlib)+2);
+    strcpy(newpreload,expreload);
+    strcat(newpreload,":");
+    strcat(newpreload,authbindlib);
+    preload= newpreload;
+  } else {
+    preload= authbindlib;
+  }
+  if (setenv(LD_PRELOAD,preload,1)) { perror("authbind: setenv"); exit(-1); }
+
+  execvp(argv[1],argv+1);
+  perror(argv[1]); exit(-1);
+}
diff --git a/debian/.cvsignore b/debian/.cvsignore
new file mode 100644 (file)
index 0000000..db09c07
--- /dev/null
@@ -0,0 +1,3 @@
+files
+substvars
+tmp
diff --git a/debian/changelog b/debian/changelog
new file mode 100644 (file)
index 0000000..3ac61d6
--- /dev/null
@@ -0,0 +1,9 @@
+authbind (0.1-1) experimental; urgency=low
+
+  * Initial release.
+
+ -- Ian Jackson <ian@davenant.greenend.org.uk>  Sat, 29 Aug 1998 20:10:37 +0100
+
+Local variables:
+mode: debian-changelog
+End:
diff --git a/debian/control b/debian/control
new file mode 100644 (file)
index 0000000..261df18
--- /dev/null
@@ -0,0 +1,13 @@
+Source: authbind
+Section: utils
+Priority: extra
+Maintainer: Ian Jackson <ian@chiark.greenend.org.uk>
+Standards-Version: 2.1.1.0
+
+Package: authbind
+Architecture: any
+Depends: ${shlibs:Depends}
+Description: Allows non-root programs to bind() to low ports
+ This package allows a package to be started as non-root but
+ still bind to low ports.  The ports allowed to who are in
+ /etc/authbind/<number> - make it executable to allow.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644 (file)
index 0000000..220317d
--- /dev/null
@@ -0,0 +1 @@
+GNU copyleft joost witteveen, <joostje@debian.org>.
diff --git a/debian/rules b/debian/rules
new file mode 100755 (executable)
index 0000000..b6fc00b
--- /dev/null
@@ -0,0 +1,75 @@
+#! /usr/bin/make -f
+#   -*- mode: makefile; -*-
+#
+# Modified by Ian Jackson for authbind.
+# Then last updated: Sat Dec 17 10:52:20 EST 1994 by imurdock.
+#
+# To make the binary distribution package, the ``Debianized'' source package
+# and the context diff to the original package, type `./debian.rules dist'.
+# Make sure that `debian.rules' is executable before the final distribution
+# is made.
+#
+# Invoke each target with `./debian.rules <target>'.  All targets should be
+# invoked with the package root as the current directory.
+#
+# The `binary' target must be run as root, as it needs to install files with
+# specific ownerships.  The `diff' target assumes that you have the original
+# source package available, unpacked, in ../$(p)-$(v).orig, or that you have
+# the previous revision of the ``Debianized'' source package and context diff
+# in the parent directory.
+
+CC = gcc
+
+package=authbind
+major=0
+minor=1
+
+arch = $(shell dpkg --print-architecture)
+
+build: 
+       $(MAKE)
+
+clean: 
+       rm -rf debian/{files,substvars,tmp} build 
+       $(MAKE) distclean
+
+binary-indep:   checkroot build
+        $(checkdir)
+# There are no architecture-independent files to be uploaded
+# generated by this package.  If there were any they would be
+# made here.
+
+lab=libauthbind.so.$(major).$(minor)
+
+binary-arch:   checkroot build
+       rm -rf debian/tmp
+       install -d -g root -m 755 -o root debian/tmp/DEBIAN \
+               debian/tmp/usr/{bin,lib/$(package),doc/$(package)} \
+               debian/tmp/etc/authbind/{byport,byname,byuid}
+       install -s -g root -o root -m 755 authbind debian/tmp/usr/bin/.
+       install -s -g root -o root -m 4755 helper debian/tmp/usr/lib/authbind/.
+       install -s -g root -o root -m 755 $(lab) debian/tmp/usr/lib/authbind/.
+       ln -s $(lab) debian/tmp/usr/lib/authbind/libauthbind.so.$(major)
+       strip --strip-unneeded debian/tmp/usr/lib/authbind/$(lab)
+       install -g root -o root -m 644 debian/copyright debian/tmp/usr/doc/$(package)/
+       install -g root -o root -m 644 debian/changelog \
+               debian/tmp/usr/doc/$(package)/changelog.Debian
+       gzip -9 debian/tmp/usr/doc/$(package)/*
+ifneq ($(arch),alpha)
+       install -g root -o root -m 644 debian/shlibs debian/tmp/DEBIAN
+else
+       install -g root -o root -m 644 debian/shlibs.alpha debian/tmp/DEBIAN/shlibs
+endif
+       dpkg-shlibdeps ./authbind
+       dpkg-gencontrol
+       chown -R root.root debian/tmp
+       chmod -R g-ws debian/tmp
+       #/bin/bash #-c "ls debian/tmp"
+       #bash -c "dpkg --build debian/tmp .."
+       dpkg --build debian/tmp ..
+
+binary:         binary-indep binary-arch
+
+checkroot:
+       $(checkdir)
+       test root = "`whoami`"
diff --git a/debian/shlibs b/debian/shlibs
new file mode 100644 (file)
index 0000000..ae3640e
--- /dev/null
@@ -0,0 +1 @@
+/usr/lib/libfakeroot/libfakeroot      0       libc6
diff --git a/debian/shlibs.alpha b/debian/shlibs.alpha
new file mode 100644 (file)
index 0000000..00dfeef
--- /dev/null
@@ -0,0 +1 @@
+/usr/lib/libfakeroot/libfakeroot      0       libc6.1
diff --git a/helper.c b/helper.c
new file mode 100644 (file)
index 0000000..e086e9e
--- /dev/null
+++ b/helper.c
@@ -0,0 +1,125 @@
+/*
+ * setuid.  Invoked with socket on stdin.
+ *  Usage:  helper <addr> <port>
+ * both are hex strings, padded to the right length.
+ * they are pairs of hex digits for each byte (network byte order)
+ *
+ * If /etc/authbind cannot be chdir'd into, is an error.
+ *
+ * First, check /etc/authbind/byport/<port> with access(2,X_OK).
+ *  If OK, then authorised.
+ *  If ENOENT then keep looking.
+ *  Otherwise, not authorised, errno=whatever
+ *
+ * Then check /etc/authbind/byboth/<addr>:<port> likewise.
+ *
+ * Then try to read /etc/authbind/byuid/<uid> (with superuser privs!)
+ *  If ENOENT, then not authorised, errno=EPERM
+ *  If cannot open, then not authorised, errno=whatever
+ *  If it contains a line of the form
+ *     <addr>/<length>:<port-min>,<port-max>
+ *    then authorised, otherwise not authorised, errno=ENOENT
+ *  If read error then is an error
+ *
+ * In each case,
+ *  <addr> is dotted quad
+ *  <port> is decimal in host order
+ *  <length> is prefix length (so 0.0.0.0/32 matches any)
+ *  <uid> is decimal unsigned
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#define CONFIGDIR "/etc/authbind"
+
+static void exiterrno(int e) {
+  exit(e>0 && e<128 ? e : ENOSYS);
+}
+
+static void perrorfail(const char *m) {
+  int e;
+  e= errno;
+  fprintf(stderr,"libauthbind's helper: %s: %s\n",m,strerror(e));
+  exiterrno(e);
+}
+
+static void badusage(void) {
+  fputs("libauthbind's helper: bad usage\n",stderr);
+  exit(ENOSYS);
+}
+
+static struct sockaddr_in saddr;
+
+static void authorised(void) {
+  if (bind(0,&saddr,sizeof(saddr))) exiterrno(errno);
+  else _exit(0);
+}
+
+int main(int argc, const char *const *argv) {
+  uid_t uid;
+  char fnbuf[100];
+  char *ep;
+  const char *np;
+  unsigned long addr, port, haddr, thaddr, thmask;
+  unsigned int hport, a1,a2,a3,a4, alen,pmin,pmax;
+  int nchar;
+  FILE *file;
+
+  if (argc != 3) badusage(); 
+  addr= strtoul(argv[1],&ep,16); if (*ep || addr&~0x0ffffffffUL) badusage();
+  port= strtoul(argv[2],&ep,16); if (*ep || port&~0x0ffffUL) badusage();
+
+  if (chdir(CONFIGDIR)) perrorfail("chdir " CONFIGDIR);
+
+  fnbuf[sizeof(fnbuf)-1]= 0;
+  memset(&saddr,0,sizeof(saddr));
+  saddr.sin_family= AF_INET;
+  saddr.sin_port= port;
+  saddr.sin_addr.s_addr= addr;
+  hport= htons(port);
+
+  snprintf(fnbuf,sizeof(fnbuf)-1,"byport/%u",hport);
+  if (!access(fnbuf,X_OK)) authorised();
+  if (errno != ENOENT) exiterrno(errno);
+
+  np= inet_ntoa(saddr.sin_addr); assert(np);
+  snprintf(fnbuf,sizeof(fnbuf)-1,"byaddr/%s:%u",np,hport);
+  if (!access(fnbuf,X_OK)) authorised();
+  if (errno != ENOENT) exiterrno(errno);
+
+  uid= getuid(); if (uid==(uid_t)-1) perrorfail("getuid");
+  snprintf(fnbuf,sizeof(fnbuf)-1,"byuid/%lu",(unsigned long)uid);
+
+  file= fopen(fnbuf,"r");
+  if (!file) exiterrno(errno==ENOENT ? EPERM : errno);
+
+  haddr= ntohl(addr);
+
+  while (fgets(fnbuf,sizeof(fnbuf)-1,file)) {
+    nchar= -1;
+    sscanf(fnbuf," %u.%u.%u.%u/%u:%u,%u %n",
+          &a1,&a2,&a3,&a4,&alen,&pmin,&pmax,&nchar);
+    if (nchar != strlen(fnbuf) ||
+       alen>32 || pmin&~0x0ffff || pmax&~0x0ffff ||
+       a1&~0x0ff || a2&~0xff || a3&~0x0ff || a4&~0x0ff)
+      continue;
+    
+    if (hport<pmin || hport>pmax) continue;
+
+    thaddr= (a1<<24)|(a2<<16)|(a3<<8)|(a4);
+    thmask= 0x0ffffffffUL<<(32-alen);
+    if ((haddr&thmask) != thaddr) continue;
+    authorised();
+  }
+  if (ferror(file)) perrorfail("read per-uid file");
+  _exit(ENOENT);
+}
diff --git a/libauthbind.c b/libauthbind.c
new file mode 100644 (file)
index 0000000..d7b3f89
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ */
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <netinet/in.h>
+
+#define AUTHBIND_NESTED "AUTHBIND_NESTED"
+#define HELPER "/usr/lib/authbind/helper"
+
+typedef void anyfn_type(void);
+typedef int bindfn_type(int fd, const struct sockaddr *addr, socklen_t addrlen);
+
+#define STDERRSTR_CONST(m) write(2,m,sizeof(m)-1)
+#define STDERRSTR_STRING(m) write(2,m,strlen(m))
+
+static int find_any(const char *name, anyfn_type **keep) {
+  static const char *dlerr;
+  anyfn_type *kv;
+
+  if (*keep) return 0;
+  kv= dlsym(RTLD_NEXT,name);
+  if (kv) { *keep= kv; return 0; }
+  dlerr= dlerror(); if (!dlerr) dlerr= "dlsym() failed for no reason";
+  STDERRSTR_CONST("libauthbind: error finding original version of ");
+  STDERRSTR_STRING(name);
+  STDERRSTR_CONST(": ");
+  STDERRSTR_STRING(dlerr);
+  STDERRSTR_STRING("\n");
+  errno= ENOSYS;
+  return -1;
+}
+
+static bindfn_type find_bind, *old_bind= find_bind;
+
+int find_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
+  anyfn_type *anyfn;
+  if (find_any("bind",&anyfn)) return -1;
+  old_bind= (bindfn_type*)anyfn;
+  return old_bind(fd,addr,addrlen);
+}
+
+static int exiterrno(int e) {
+  _exit(e>0 && e<128 ? e : -1);
+}
+
+int bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
+  pid_t child, rchild;
+  char portarg[5], addrarg[9];
+  int status;
+  
+  if (addr->sa_family != AF_INET || addrlen != sizeof(struct sockaddr_in) ||
+      ntohs(((struct sockaddr_in*)addr)->sin_port) >= 1024 || !geteuid())
+    return old_bind(fd,addr,addrlen);
+
+  if (getenv(AUTHBIND_NESTED)) {
+    STDERRSTR_CONST("libauthbind: possible installation problem - "
+                   "nested invocation, perhaps helper is not setuid\n");
+    return old_bind(fd,addr,addrlen);
+  }
+
+  sprintf(addrarg,"%08lx",
+         ((unsigned long)(((struct sockaddr_in*)addr)->sin_addr.s_addr))&0x0ffffffffUL);
+  sprintf(portarg,"%04x",
+         ((unsigned int)(((struct sockaddr_in*)addr)->sin_port))&0x0ffff);
+
+  child= fork(); if (child==-1) return -1;
+
+  if (!child) {
+    if (dup2(fd,0)) exiterrno(errno);
+    if (setenv(AUTHBIND_NESTED,"1",1)) exiterrno(errno);
+    execl(HELPER,HELPER,addrarg,portarg,(char*)0);
+    status= errno;
+    STDERRSTR_CONST("libauthbind: possible installation problem - "
+                   "could not invoke " HELPER "\n");
+    exiterrno(status);
+  }
+
+  rchild= waitpid(child,&status,0);
+  if (rchild==-1) return -1;
+  if (rchild!=child) { errno= ECHILD; return -1; }
+
+  if (WIFEXITED(status)) {
+    if (WEXITSTATUS(status)) { errno= WEXITSTATUS(status); return -1; }
+    return 0;
+  } else {
+    errno= ENOSYS;
+    return -1;
+  }
+}