From: ian Date: Sun, 30 Aug 1998 15:19:20 +0000 (+0000) Subject: Allow control of when the LD_PRELOAD is passed on. X-Git-Tag: debian_version_1_1 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?a=commitdiff_plain;ds=sidebyside;h=a942b07a4483cfa4a5f0a8307e3b6239f7f44998;hp=ced277da933eb4aeb199ee534cfe9a15804061cc;p=authbind.git Allow control of when the LD_PRELOAD is passed on. --- diff --git a/Makefile b/Makefile index 1932348..18a0926 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,7 @@ man8_dir=$(man_dir)/man8 etc_dir=/etc/authbind OPTIMISE= -O2 +LDFLAGS= -g CFLAGS= -g $(OPTIMISE) \ -Wall -Wwrite-strings -Wpointer-arith -Wimplicit \ -Wnested-externs -Wmissing-prototypes -Wstrict-prototypes @@ -63,11 +64,16 @@ install_man: $(MANPAGES_1) $(MANPAGES_8) 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* diff --git a/authbind.1 b/authbind.1 index a7bb5b5..8d6c335 100644 --- a/authbind.1 +++ b/authbind.1 @@ -23,8 +23,8 @@ .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 @@ -37,6 +37,28 @@ will set up some environment variables, including an 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, @@ -231,16 +253,31 @@ If set, forces .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), diff --git a/authbind.c b/authbind.c index 7f80e3e..028ccbf 100644 --- a/authbind.c +++ b/authbind.c @@ -23,27 +23,58 @@ #include #include #include +#include + +#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 [] ...\n" + "options: --deep --depth \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); @@ -54,7 +85,16 @@ int main(int argc, char *const *argv) { } 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); diff --git a/authbind.h b/authbind.h new file mode 100644 index 0000000..3911c08 --- /dev/null +++ b/authbind.h @@ -0,0 +1,37 @@ +/* + * 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 diff --git a/debian/changelog b/debian/changelog index bead4e8..43dce7e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +authbind (1.1) experimental; urgency=low + + * Allow control of when the LD_PRELOAD is passed on. + + -- Ian Jackson Sun, 30 Aug 1998 16:18:24 +0100 + authbind (1.0) experimental; urgency=low * Following testing, we can call this 1.0. diff --git a/helper.c b/helper.c index 96892ab..409ed7b 100644 --- a/helper.c +++ b/helper.c @@ -48,7 +48,7 @@ static void perrorfail(const char *m) { } 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); } diff --git a/libauthbind.c b/libauthbind.c index 3bdd58f..dd5c484 100644 --- a/libauthbind.c +++ b/libauthbind.c @@ -32,11 +32,7 @@ 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); @@ -74,23 +70,88 @@ static int exiterrno(int e) { _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 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", @@ -100,11 +161,13 @@ int bind(int fd, const struct sockaddr *addr, socklen_t addrlen) { 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); }