etc_dir=/etc/authbind
OPTIMISE= -O2
+LDFLAGS= -g
CFLAGS= -g $(OPTIMISE) \
-Wall -Wwrite-strings -Wpointer-arith -Wimplicit \
-Wnested-externs -Wmissing-prototypes -Wstrict-prototypes
install -o root -g root -m 644 $(MANPAGES_1) $(man1_dir)/.
install -o root -g root -m 644 $(MANPAGES_8) $(man8_dir)/.
-libauthbind.o: libauthbind.c
+libauthbind.o: libauthbind.c authbind.h
$(CC) -D_REENTRANT $(CFLAGS) $(CPPFLAGS) -c -o $@ -fPIC $<
+authbind: authbind.o
+helper: helper.o
+
+helper.o authbind.o: authbind.h
+
$(LIBTARGET): libauthbind.o
- gcc -g -shared -Wl,-soname,$(LIBCANON) -o $@ $< -ldl -lc
+ ld -shared -soname $(LIBCANON) -o $@ $< -ldl -lc
clean distclean:
rm -f $(TARGETS) *.o *~ ./#*# *.bak *.new core libauthbind.so*
.SH NAME
authbind \- bind sockets to privileged ports without root
.SH SYNOPSIS
-.BI authbind " program"
-.RI [ argument " ...]"
+.BR authbind
+.RI [ options "] " program " [" argument " ...]"
.SH DESCRIPTION
.B authbind
allows a program which does not or should not run as root to bind to
which will allow the program (including any subprocesses it may run)
to bind to low-numbered (<512) ports if the system is configured to
allow this.
+.SH OPTIONS
+.TP
+.B --deep
+Normally,
+.B authbind
+arranges for only the program which it directly invokes to be affected
+by its special version of
+.BR bind (2).
+If you specify
+.B --deep
+then all programs which that program invokes directly or indirectly
+will be affected, so long as they do not unset the environment
+variables set up by
+.BR authbind .
+.TP
+.BI --depth " levels"
+Causes
+.B authbind
+to affect programs which are
+.I levels
+deep in the calling graph. The default is
+.BR "--depth 1" .
.SH ACCESS CONTROL
Access to low numbered ports is controlled by permissions and contents
of files in a configuration area,
.B authbind
to use its value as the path to the shared library to put in
.BR LD_PRELOAD ,
-instead of the compiled-in value.
+instead of the compiled-in value. In any case, unless
+.B --deep
+was specified,
+.B authbind
+will set this variable to the name of the library actually added to
+.BR LD_PRELOAD ,
+so that the library can find and remove the right entry.
.TP
-.I AUTHBIND_NESTED
-Do not set this variable. It is set to
-.B 1
-by
-.B libauthbind
-when it invokes the helper program. This allows detection of the
-situation where the helper has not been installed setuid, which would
-otherwise lead to infinite recursion.
+.I AUTHBIND_LEVELS
+This variable is set by
+.B authbind
+to the number of levels left from the
+.B --depth
+or
+.B --deep
+option, minus one. It is decremented during
+.B _init
+by the library on each program call, and the library will remove
+itself from the
+.B LD_PRELOAD
+when it reaches zero. The special value
+.B y
+means
+.B --deep
+was specified.
.SH SEE ALSO
.BR bind (2),
.BR authbind\-helper (8),
#include <string.h>
#include <stdio.h>
#include <unistd.h>
+#include <assert.h>
+
+#include "authbind.h"
static const char *rcsid="$Id$";
-#ifndef LIBAUTHBIND
-# define "/usr/local/lib/authbind/libauthbind.so." MAJOR_VER
-#endif
+static void printusage(FILE *f) {
+ if (fprintf(f,
+ "usage: authbind [<options>] <program> <arg> <arg> ...\n"
+ "options: --deep --depth <levels>\n"
+ "version: " MAJOR_VER "." MINOR_VER " %s\n",
+ rcsid) == EOF) { perror("printf usage"); exit(-1); }
+}
-#define PRELOAD_VAR "LD_PRELOAD"
-#define AUTHBINDLIB_VAR "AUTHBIND_LIB"
+static void usageerror(const char *msg) {
+ fprintf(stderr,"usage error: %s\n",msg);
+ printusage(stderr);
+ exit(-1);
+}
+
+static void mustsetenv(const char *var, const char *val) {
+ if (setenv(var,val,1)) { perror("authbind: setenv"); exit(-1); }
+}
int main(int argc, char *const *argv) {
const char *expreload, *authbindlib, *preload;
- char *newpreload;
+ char *newpreload, *ep;
+ char buf[50];
+ unsigned long depth;
- if (argc<2 || argv[1][0]=='-') {
- fprintf(stderr,"authbind: usage: authbind program arg arg ...\n %s\n",rcsid);
- exit(-1);
+ depth= 1;
+ while (argc>1 && argv[1][0]=='-') {
+ argc--; argv++;
+ if (!argv[0][1]) break;
+ if (!strcmp("--deep",argv[0])) { depth= -1; }
+ else if (!strcmp("--depth",argv[0])) {
+ if (argc<=1) usageerror("--depth requires a value");
+ argc--; argv++;
+ depth= strtoul(argv[0],&ep,10);
+ if (*ep || depth<=0 || depth>100) usageerror("--depth value is not valid");
+ } else if (!strcmp("--help",argv[0]) || !strcmp("--help",argv[0])) {
+ printusage(stdout);
+ exit(0);
+ }
}
+ if (argc<2) usageerror("need program name");
authbindlib= getenv(AUTHBINDLIB_VAR);
- if (!authbindlib) authbindlib= LIBAUTHBIND;
+ if (!authbindlib) {
+ authbindlib= LIBAUTHBIND;
+ mustsetenv(AUTHBINDLIB_VAR,authbindlib);
+ }
if ((expreload= getenv(PRELOAD_VAR))) {
newpreload= malloc(strlen(expreload)+strlen(authbindlib)+2);
} else {
preload= authbindlib;
}
- if (setenv(PRELOAD_VAR,preload,1)) { perror("authbind: setenv"); exit(-1); }
+ mustsetenv(PRELOAD_VAR,preload);
+
+ if (depth > 1) {
+ sprintf(buf,"%ld",depth-1);
+ mustsetenv(AUTHBIND_LEVELS_VAR,buf);
+ } else if (depth == -1) {
+ mustsetenv(AUTHBIND_LEVELS_VAR,"y");
+ } else {
+ assert(depth==1);
+ }
execvp(argv[1],argv+1);
perror(argv[1]); exit(-1);
--- /dev/null
+/*
+ * authbind.h - various definitions
+ *
+ * authbind is Copyright (C) 1998 Ian Jackson
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef AUTHBIND_H
+#define AUTHBIND_H
+
+#ifndef LIBAUTHBIND
+# define LIBAUTHBIND "/usr/local/lib/authbind/libauthbind.so." MAJOR_VER
+#endif
+
+#ifndef HELPER
+# define HELPER "/usr/local/lib/authbind/helper"
+#endif
+
+#define PRELOAD_VAR "LD_PRELOAD"
+#define AUTHBINDLIB_VAR "AUTHBIND_LIB"
+#define AUTHBIND_LEVELS_VAR "AUTHBIND_LEVELS"
+
+#endif
+authbind (1.1) experimental; urgency=low
+
+ * Allow control of when the LD_PRELOAD is passed on.
+
+ -- Ian Jackson <ian@davenant.greenend.org.uk> Sun, 30 Aug 1998 16:18:24 +0100
+
authbind (1.0) experimental; urgency=low
* Following testing, we can call this 1.0.
}
static void badusage(void) {
- fprintf(stderr,"libauthbind's helper: bad usage\n %s\n",rcsid);
+ fprintf(stderr,"libauthbind's helper: bad usage\n (%s)\n",rcsid);
exit(ENOSYS);
}
static const char *rcsid="$Id$";
-#ifndef HELPER
-# define HELPER "/usr/local/lib/authbind/helper"
-#endif
-
-#define AUTHBIND_NESTED_VAR "AUTHBIND_NESTED"
+#include "authbind.h"
typedef void anyfn_type(void);
typedef int bindfn_type(int fd, const struct sockaddr *addr, socklen_t addrlen);
_exit(e>0 && e<128 ? e : -1);
}
+static void removepreload(void) {
+ const char *myself, *found;
+ char *newval, *preload;
+ int lpreload, lmyself, before, after;
+
+ preload= getenv(PRELOAD_VAR);
+ myself= getenv(AUTHBINDLIB_VAR);
+ if (!myself || !preload) return;
+
+ lpreload= strlen(preload);
+ lmyself= strlen(myself);
+
+ if (lmyself < 1 || lpreload<lmyself) return;
+ if (lpreload==lmyself) {
+ if (!strcmp(preload,myself)) unsetenv(PRELOAD_VAR);
+ return;
+ }
+ if (!memcmp(preload,myself,lmyself) && preload[lmyself]==':') {
+ before= 0; after= lpreload-(lmyself+1);
+ } else if (!memcmp(preload+lpreload-lmyself,myself,lmyself) &&
+ preload[lpreload-(lmyself+1)]==':') {
+ before= lpreload-(lmyself+1); after= 0;
+ } else {
+ if (lpreload<lmyself+2) return;
+ found= preload+1;
+ for (;;) {
+ found= strstr(found,myself); if (!found) return;
+ if (found > preload+lpreload-(lmyself+1)) return;
+ if (found[-1]==':' && found[lmyself]==':') break;
+ found++;
+ }
+ before= found-preload;
+ after= lpreload-(before+lmyself+1);
+ }
+ newval= malloc(before+after+1);
+ if (newval) {
+ memcpy(newval,preload,before);
+ strcpy(newval+before,preload+lpreload-after);
+ if (setenv(PRELOAD_VAR,newval,1)) return;
+ free(newval);
+ }
+ strcpy(preload+before,preload+lpreload-after);
+ return;
+}
+
+int _init(void);
+int _init(void) {
+ char *levels;
+ int levelno;
+
+ /* If AUTHBIND_LEVELS is
+ * unset => always strip from preload
+ * set and starts with `y' => never strip from preload, keep AUTHBIND_LEVELS
+ * set to integer > 1 => do not strip now, subtract one from AUTHBIND_LEVELS
+ * set to integer 1 => do not strip now, unset AUTHBIND_LEVELS
+ * set to empty string or 0 => strip now, unset AUTHBIND_LEVELS
+ */
+ levels= getenv(AUTHBIND_LEVELS_VAR);
+ if (levels) {
+ if (levels[0]=='y') return 0;
+ levelno= atoi(levels);
+ if (levelno > 0) {
+ levelno--;
+ if (levelno > 0) sprintf(levels,"%d",levelno);
+ else unsetenv(AUTHBIND_LEVELS_VAR);
+ return 0;
+ }
+ unsetenv(AUTHBIND_LEVELS_VAR);
+ }
+ removepreload();
+ return 0;
+}
+
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) >= IPPORT_RESERVED/2 || !geteuid())
return old_bind(fd,addr,addrlen);
- if (getenv(AUTHBIND_NESTED_VAR)) {
- STDERRSTR_CONST("libauthbind: possible installation problem - "
- "nested invocation, perhaps helper is not setuid\n ");
- STDERRSTR_STRING(rcsid);
- STDERRSTR_CONST("\n");
- return old_bind(fd,addr,addrlen);
- }
-
sprintf(addrarg,"%08lx",
((unsigned long)(((struct sockaddr_in*)addr)->sin_addr.s_addr))&0x0ffffffffUL);
sprintf(portarg,"%04x",
if (!child) {
if (dup2(fd,0)) exiterrno(errno);
- if (setenv(AUTHBIND_NESTED_VAR,"1",1)) exiterrno(errno);
+ removepreload();
execl(HELPER,HELPER,addrarg,portarg,(char*)0);
status= errno;
STDERRSTR_CONST("libauthbind: possible installation problem - "
- "could not invoke " HELPER "\n");
+ "could not invoke " HELPER " (");
+ STDERRSTR_STRING(rcsid);
+ STDERRSTR_CONST(")\n");
exiterrno(status);
}