From bd5ce5f0d78a8cfd13ac02e853396ac7c66e4bd3 Mon Sep 17 00:00:00 2001 From: Johannes Schauer Date: Sun, 26 Jul 2015 10:23:35 +0100 Subject: [PATCH] authbind (2.1.1+nmu1) unstable; urgency=medium * Non-maintainer upload. * Fix mtimes before building binary packages to produce reproducible output Based on patch by akira (Closes: #792945) [dgit import package authbind 2.1.1+nmu1] --- Makefile | 89 ++++++++++++ authbind-helper.8 | 94 ++++++++++++ authbind.1 | 359 ++++++++++++++++++++++++++++++++++++++++++++++ authbind.c | 98 +++++++++++++ authbind.h | 37 +++++ debian/changelog | 171 ++++++++++++++++++++++ debian/control | 12 ++ debian/copyright | 26 ++++ debian/postinst | 9 ++ debian/postrm | 6 + debian/prerm | 7 + debian/rules | 103 +++++++++++++ helper.c | 269 ++++++++++++++++++++++++++++++++++ libauthbind.c | 232 ++++++++++++++++++++++++++++++ 14 files changed, 1512 insertions(+) create mode 100644 Makefile create mode 100644 authbind-helper.8 create mode 100644 authbind.1 create mode 100644 authbind.c create mode 100644 authbind.h create mode 100644 debian/changelog create mode 100644 debian/control create mode 100644 debian/copyright create mode 100644 debian/postinst create mode 100755 debian/postrm create mode 100644 debian/prerm create mode 100755 debian/rules create mode 100644 helper.c create mode 100644 libauthbind.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c1eed73 --- /dev/null +++ b/Makefile @@ -0,0 +1,89 @@ +# Makefile for authbind +# +# 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. + +prefix=/usr/local + +bin_dir=$(prefix)/bin +lib_dir=$(prefix)/lib/authbind +libexec_dir=$(lib_dir) + +share_dir=$(prefix)/share +man_dir=$(share_dir)/man +man1_dir=$(man_dir)/man1 +man8_dir=$(man_dir)/man8 + +etc_dir=/etc/authbind + +INSTALL_FILE ?= install -o root -g root -m 644 +INSTALL_PROGRAM ?= install -o root -g root -m 755 -s +INSTALL_DIR ?= install -o root -g root -m 755 -d +STRIP ?= strip + +OPTIMISE= -O2 +LDFLAGS= -g +LIBS= -ldl -lc +CFLAGS= -g $(OPTIMISE) \ + -Wall -Wwrite-strings -Wpointer-arith -Wimplicit \ + -Wnested-externs -Wmissing-prototypes -Wstrict-prototypes +CPPFLAGS= -DMAJOR_VER='"$(MAJOR)"' -DMINOR_VER='"$(MINOR)"' \ + -DLIBAUTHBIND='"$(lib_dir)/$(LIBCANON)"' \ + -DHELPER='"$(libexec_dir)/$(HELPER)"' -DCONFIGDIR='"$(etc_dir)"' \ + -D_GNU_SOURCE + +MAJOR=1 +MINOR=0 +LIBCANON= libauthbind.so.$(MAJOR) +LIBTARGET= $(LIBCANON).$(MINOR) +BINTARGETS= authbind +HELPER= helper + +TARGETS= $(BINTARGETS) $(HELPER) $(LIBTARGET) +MANPAGES_1= authbind.1 +MANPAGES_8= authbind-helper.8 + +all: $(TARGETS) + +install: $(TARGETS) + $(INSTALL_DIR) $(lib_dir) $(man1_dir) $(man8_dir) + $(INSTALL_PROGRAM) $(BINTARGETS) $(bin_dir)/. + $(INSTALL_FILE) $(LIBTARGET) $(lib_dir)/. + $(STRIP) --strip-unneeded $(lib_dir)/$(LIBTARGET) + ln -sf $(LIBTARGET) $(lib_dir)/$(LIBCANON) + $(INSTALL_PROGRAM) $(HELPER) $(libexec_dir)/. + chmod u+s $(libexec_dir)/$(HELPER) + $(INSTALL_DIR) $(etc_dir) \ + $(etc_dir)/byport $(etc_dir)/byaddr $(etc_dir)/byuid + +install_man: $(MANPAGES_1) $(MANPAGES_8) + $(INSTALL_FILE) $(MANPAGES_1) $(man1_dir)/. + $(INSTALL_FILE) $(MANPAGES_8) $(man8_dir)/. + +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 + ld -shared -soname $(LIBCANON) -o $@ $< $(LIBS) + +clean distclean: + rm -f $(TARGETS) *.o *~ ./#*# *.bak *.new core + rm -f libauthbind.so* *.core diff --git a/authbind-helper.8 b/authbind-helper.8 new file mode 100644 index 0000000..b9c25e8 --- /dev/null +++ b/authbind-helper.8 @@ -0,0 +1,94 @@ +.\" Hey, Emacs! This is an -*- nroff -*- source file. +.\" Authors: Ian Jackson +.\" +.\" 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. +.\" +.TH AUTHBIND\-HELPER 8 "30th August 1998" "Debian Project" "Debian Linux manual" +.br +.SH NAME +authbind\-helper \- helper program to bind sockets to privileged ports without root +.SH SYNOPSIS +.BI /usr/lib/authbind/helper " addr4\-hex port\-hex " < socket +.br +.BI /usr/lib/authbind/helper " addr6\-hex port\-hex 6 " < socket +.SH DESCRIPTION +.B helper +is the program used by +.BR libauthbind , +which is in turn used by +.B authbind +to allow programs which do not or should not run as root to bind to +low-numbered ports in a controlled way. See +.BR authbind (1). +.PP +It may also be used standalone, i.e. without assistance from +.BR authbind . +Its standard input should be a TCP/IP socket, and it should be passed +two or three arguments. +.PP +The arguments are the address and port number, respectively, to which +the caller desires that the socket be bound, and the address family +(ommitted for IPv4; the fixed string +.B 6 +for IPv6). +.I addr4-hex +and +.I port-hex +should be hex strings, +.I without +leading +.BR 0x , +of exactly the right length (8 and 4 digits, respectively), being +a pair of hex digits for each byte in the address or port number when +expressed in host byte order. For example, the port argument is the +result of something like +.B sprintf(arg, +.B """%04X"", +.BR sin.sin_port) . +.I addr6-hex +should be a string of 32 hex digits, being a pair for each byte in +the address, in network byte order. +.SH EXIT STATUS +.B helper +will exit with code 0 on success. +.PP +If possible, +.B helper +will return an appropriate +.B errno +value as its exit status. If this is not possible it may exit with +status 255 or with an exit status corresponding to +.B ENOSYS +.RI ( "Function not implemented" ). +.SH ACCESS CONTROL +See +.BR authbind (1) +for details of the access control regime implemented by +.BR helper . +.SH SEE ALSO +.BR authbind (1), +.BR bind (2) +.SH AUTHOR +.B authbind +and this manpage were written by Ian Jackson. They are +Copyright (C)1998,2012 +by him and released under the GNU General Public Licence; there is NO +WARRANTY. See +.B /usr/doc/authbind/copyright +and +.B /usr/doc/copyright/GPL +for details. diff --git a/authbind.1 b/authbind.1 new file mode 100644 index 0000000..d73e998 --- /dev/null +++ b/authbind.1 @@ -0,0 +1,359 @@ +.\" Hey, Emacs! This is an -*- nroff -*- source file. +.\" Authors: Ian Jackson +.\" +.\" 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. +.\" +.TH AUTHBIND 1 "30th August 1998" "Debian Project" "Debian Linux manual" +.SH NAME +authbind \- bind sockets to privileged ports without root +.SH SYNOPSIS +.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 +low-numbered ports in a controlled way. +.PP +You must invoke the program using +.BR authbind ". " authbind +will set up some environment variables, including an +.BR LD_PRELOAD , +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, +.BR /etc/authbind . +.PP +Firstly, +.BI /etc/authbind/byport/ port +is tested. If this file is accessible for execution to the calling +user, according to +.BR access (2), +then binding to the port is authorised. If the file can be seen not +to exist (the existence check returns +.BR ENOENT ) +then further tests will be used to find authorisation; otherwise, +binding is not authorised, and the +.B bind +call will return with the +.B errno +value from the +.BR access (2) +call, usually +.B EACCES +.RI ( "Permission denied" ). +.PP +Secondly, if that test fails to resolve the matter, +.BI /etc/authbind/byaddr/ addr , port +(any protocol) or failing that +.BI /etc/authbind/byaddr/ addr : port +(IPv4 only) +is tested, in the same manner as above. Here +.I addr +is as from +.BR inet_ntop , +and +.I port +is the (local) TCP or UDP port number, expressed as an unsigned +integer in the minimal non-zero number of digits. +.PP +Thirdly, for IPv6 only: since the textual representation from +.B inet_ntop +is complicated to predict, a variant of +.I addr +is also tested which does not use the double colon abbreviation: +each 16-byte chunk expressed in the minimal nonzero number +of hex digits (i.e. with leading zeroes removed), the chunks +being separated by colons as is conventional. +.PP +Fourthly, if the question is still unresolved, the file +.BI /etc/authbind/byuid/ uid +will be opened and read. If the file does not exist then the binding +is not authorised and +.B bind +will return +.B EPERM +.RI ( "Operation not permitted" ", or " "Not owner" ). +If the file does exist it will be searched for a line of the form +.nf +.IR addrmin [\fB\-\fR addrmax ]\fB,\fR portmin [\fB\-\fR portmax ] +.IR addr [\fB/\fR length ]\fB,\fR portmin [\fB\-\fR portmax ] +.IB addr4 / length : portmin , portmax +.fi +matching the request. +The first form requires that the address lies in the +relevant range (inclusive at both ends). +The second and third forms require that the initial +.I length +bits of +.I addr +match those in the proposed +.B bind +call. The third form is only available for IPv4 since IPv6 addresses +contain colons. +Addresses in the byuid file can +be in any form acceptable to inet_pton. In all cases +the proposed port number must lie is in the inclusive range +specified. If such a line is found then the binding is authorised. +Otherwise it is not, and +.B bind +will fail with +.B ENOENT +.RI ( "No such file or directory" ). +.PP +If a read error occurs, or the directory +.B /etc/authbind +cannot be accessed, then not only will +.B bind +fail, but an error message will be printed to stderr. Unrecognised +lines in +.BI /etc/authbind/byuid/ uid +files are silently ignored, as are lines whose +.I addr +has non-zero bits more than +.I length +from the top or where some +.I min +is larger than +.IR max . +.SH EXAMPLE +So for example an attempt by uid 432 +to bind to port 80 of address [2620:106:e002:f00f::21] +would result in authbind calling +.I access(2) +on, in order, +.RS +.B /etc/authbind/byport/80 +.br +.B /etc/authbind/byaddr/2620:106:e002:f00f::21,80 +.br +.B /etc/authbind/byaddr/2620:106:e002:f00f:0:0:0:21,80 +.RE +If none of these files exist, authbind will read +.RS +.B /etc/authbind/byuid/432 +.RE +and search for a line to permit +the relevant access; examples of lines which would do so are: +.RS +.B 2620:106:e002:f00f::21,80 +.br +.B ::/0,80 +.RE +.SH PORTS 512-1023 +Authorising binding to ports from 512 to 1023 inclusive is +not recommended. Some protocols (including some versions of NFS) +authorise clients by seeing that they are using a port number in this +range. So by authorising a program to be a server for such a port, +you are also authorising it to impersonate the whole host for those +protocols. + +To make sure that this isn't done by accident, +if the port number requested is in the range 512-1023, authbind +will expect the permission files to have an additional +.B ! +at the start of their leafname. +.SH MECHANISM +The shared library loaded using +.B LD_PRELOAD +overrides the +.BR bind (2) +system call. When a program invoked via +.B authbind +calls +.B bind +to bind a socket to a low-numbered TCP/IP port, and if the program +doesn't already have an effective uid of 0, the version of +.B bind +supposed by +.B authbind +forks and executes a setuid-root helper program. For non-TCP/IP +sockets, high-numbered ports, or programs which are already root, +.B authbind +passes the call to the original +.BR bind (2) +system call, which is found using +.BR dlsym (3) +with the handle +.BR RTLD_NEXT . +.PP +.SH ERROR HANDLING +Usually the normal C error handling mechanisms apply. If +.B authbind +cannot find the program it has been asked to execute it will print a +message to stderr and exit with code 255. +.PP +The helper program usually reports back to the shared library with an +exit status containing an +.B errno +value which encodes whether the +.B bind +was permitted and successful. This will be returned to the calling +program in the usual way. +.PP +In the case of apparent configuration or other serious errors the +library and/or the helper program may cause messages to be printed to +the program's stderr, was well as returning -1 from +.BR bind . +.SH BUGS +.B authbind +currently only supports IPv4 and IPv6 sockets. +Programs which open other kinds +of sockets will not benefit from +.BR authbind , +but it won't get in their way. +.PP +The use of +.B LD_PRELOAD +makes an +.B authbind +installation specific to a particular C library. This version is for +GNU/Linux libc6 (glibc2). +.PP +.B authbind +may not operate correctly with multithreaded programs. It is +inherently very difficult (if not impossible) to perform the kind of +trickery that authbind does while preventing all undesirable +interactions between authbind's activities and those of (say) a +threading runtime system. +.PP +It is quite possible that +.B authbind +and other programs and facilities which use +.B LD_PRELOAD +may interfere with each other, causing unpredictable behaviour or even +core dumps. +.B authbind +is known sometimes not to work correctly with +.BR fakeroot , +for example (even supposing it could be determined what `correctly' +means in this context). +.PP +.B authbind +is ineffective with setuid programs, because they do not honour +.B LD_PRELOAD +references outside the system directories, for security reasons. (In +fact, setuid programs should not honour +.B LD_PRELOAD +at all.) +Of course a setuid-root program does not need +.BR authbind , +but it might be useful to apply it to program which are setuid to +another user or setgid. If the author or builder of such a programs +wishes it to use authbind they could have it load the +.B libauthbind +library explicitly rather than via +.BR LD_PRELOAD . +.PP +Some programs may have trouble because +.B authbind +spawns a child process `under their feet', causing (for example) a +.BR fork (2) +to happen and +.B SIGCHLD +signal to be delivered. Unfortunately the Unix API does not make +it possible to deal with this problem in a sane way. +.PP +The access control configuration scheme is somewhat strange. +.SH FILES AND ENVIRONMENT VARIABLES +.TP +.I /usr/lib/authbind/libauthbind.so.1.0 +The shared library which +.B authbind +causes to be loaded using +.BR LD_PRELOAD , +and which actually implements the diversion of +.BR bind (2) +to an external program. +.TP +.I LD_PRELOAD +The variable used by the dynamic linker when starting dynamically +linked programs and deciding which shared libraries to load and +modifed by the +.B authbind +program to allow it to override the usual meaning of +.BR bind (2) . +.TP +.I AUTHBIND_LIB +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. 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_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), +.BR dlsym (3), +.BR ld.so (8) +.SH AUTHOR +.B authbind +and this manpage were written by Ian Jackson. They are +Copyright (C)1998,2012 +by him and released under the GNU General Public Licence; there is NO +WARRANTY. See +.B /usr/doc/authbind/copyright +and +.B /usr/doc/copyright/GPL +for details. diff --git a/authbind.c b/authbind.c new file mode 100644 index 0000000..8dd8f0c --- /dev/null +++ b/authbind.c @@ -0,0 +1,98 @@ +/* + * authbind.c - main invoker program + * + * 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. + * + */ + +#include +#include +#include +#include +#include + +#include "authbind.h" + +static void printusage(FILE *f) { + if (fprintf(f, + "usage: authbind [] ...\n" + "options: --deep --depth \n") + == EOF) { perror("printf usage"); exit(-1); } +} + +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, *ep; + char buf[50]; + unsigned long depth; + + depth= 1; + while (argc>1 && argv[1][0]=='-') { + argc--; argv++; + if (!argv[0][1]) break; + if (!strcmp("--deep",argv[0])) { depth= 0; } + 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; + mustsetenv(AUTHBINDLIB_VAR,authbindlib); + } + + if ((expreload= getenv(PRELOAD_VAR))) { + newpreload= malloc(strlen(expreload)+strlen(authbindlib)+2); + strcpy(newpreload,expreload); + strcat(newpreload,":"); + strcat(newpreload,authbindlib); + preload= newpreload; + } else { + preload= authbindlib; + } + mustsetenv(PRELOAD_VAR,preload); + + if (depth > 1) { + sprintf(buf,"%ld",depth-1); + mustsetenv(AUTHBIND_LEVELS_VAR,buf); + } else if (depth == 0) { + 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 new file mode 100644 index 0000000..531fbbd --- /dev/null +++ b/debian/changelog @@ -0,0 +1,171 @@ +authbind (2.1.1+nmu1) unstable; urgency=medium + + * Non-maintainer upload. + * Fix mtimes before building binary packages to produce reproducible output + Based on patch by akira (Closes: #792945) + + -- Johannes Schauer Sun, 26 Jul 2015 11:23:35 +0200 + +authbind (2.1.1) unstable; urgency=low + + * Manpage has an example of which files will be checked and read + Closes: #676540. + * Do not include library version number in usage output from helper; the + library and package version numbers are not the same, so this is + misleading, and we do not want to introduce new machinery just to + plumb the package version number through. Closes: #676440. + * Another minor wording fix in the manpage.x + + -- Ian Jackson Sun, 10 Jun 2012 23:17:14 +0100 + +authbind (2.1.0) unstable; urgency=low + + * Permissions file lines can contain IPv6 mask/length. + * Permissions file lines need only contain one port number. + * Manpage improvements. + + -- Ian Jackson Sun, 03 Jun 2012 12:33:53 +0100 + +authbind (2.0.1) unstable; urgency=low + + Bugfix: + * 0-length ipv4 address masks (ie, 0.0.0.0/0) in byuid files wouldn't + work because they would attempt a 32-bit shift. This was reported + against Ubuntu in Launchpad but the but is here too. LP: #514278. + + -- Ian Jackson Sun, 03 Jun 2012 01:50:13 +0100 + +authbind (2.0.0) unstable; urgency=medium + + Important new functionality: + * Support IPv6. (Closes: #596921.) + * Support ports 512-1023 if the user really wants. + Explain the problem more clearly in the manpage. (Closes: 654706.) + + Bugfixes: + * Correct manpage description of helper protocol to have + actually-implemented byte order convention. (Closes: #651694.) + * Improve wording in BUGS section of manpage about forking. + + Packaging fixes: + * Remove shlibs files. These are not needed because nothing should + actually link to libauthbind. + * Update Standards-Version. + * Upstream repo is now in git. + * Change my email address. + * Set Priority to optional as in ftpmaster override file. + + -- Ian Jackson Sat, 02 Jun 2012 01:56:37 +0100 + +authbind (1.2.0) unstable; urgency=low + + * Block signals during our child's execution. Closes: #186439. + * manpage: fix subtle error in description of interaction between + set-id and LD_PRELOAD. Closes: #36890. + * Say in manpage that we may not work properly with multithreaded + programs. See also Bug#186439. + * Make sure we don't try to encode errno's >127 in a status code. + * New make variables for improved portability and customisation of + locations: LIBS, libexec_dir, HELPER, BINTARGETS. + * make clean removes *.core too. + * #include in libauthbind.c. + * Set SHELL=/bin/bash in debian/rules. Closes: #374586. + * Revert Amaya's accidental change to CC= line in debian/rules. + * Debian-native again. Closes: #393556. + * Do not strip if DEB_BUILD_OPTIONS=nostrip (Closes: #436489): + - in Makefile, do not set INSTALL_* or STRIP if already set + - in rules, export STRIP=: if nostrip + * Change my email address in Maintainer: to davenant. + + -- Ian Jackson Sun, 23 Sep 2007 20:23:50 +0100 + +authbind (1.1.5.2-0.2) unstable; urgency=low + + * Non-maintainer upload. + * Get rid of the /usr/doc link (Closes: #359363). + * Revamped packaging a bit: + - Get rid of Build-Depends on libc6-dev (build-essential) + - spelling-error-in-copyright Debian/GNU Linux Debian GNU/Linux + - Not debian-native anymore + - Updated ancient-standards-version to 3.7.2, no changes needed. + + -- Amaya Rodrigo Sastre Wed, 12 Jul 2006 12:28:12 +0200 + +authbind (1.1.5.2-0.1) unstable; urgency=low + + * Non-maintainer Upload + * Moved man pages to /usr/share/man and docs to + /usr/share/doc/authbind. Added a prerm and a postinst script to set + the /usr/doc/authbind link. (closes: #91112, #91376, #91387) + * Fixed the path to the common licenses in debian/copyright + * Added a section and priority field to the changelog + * Added support for the `nostrip' and `debug' options in + DEB_BUILD_OPTIONS. + * Boosted Standards-Version to 3.5.2 + + -- Bas Zoetekouw Sun, 13 May 2001 18:00:52 +0200 + +authbind (1.1.5.2) frozen unstable; urgency=low + + * Non-maintainer upload. + * Makefile: Add -D_GNU_SOURCE, closes: 89944 + + -- Stephen Frost Fri, 16 Mar 2001 19:42:05 -0500 + +authbind (1.1.5.1) frozen unstable; urgency=low + + * Non-maintainer upload. + * debian/rules (clean): use tab not spaces, so `debian/rules clean' + actually works. [#27360] + * debian/rules (binary-arch): don't compress the copyright file. + * Makefile: install the shared library non-executable. + + -- James Troup Sun, 3 Jan 1999 21:23:50 +0000 + +authbind (1.1.5) unstable; urgency=low + + * Fix coredump bug ! + + -- Ian Jackson Mon, 31 Aug 1998 15:32:44 +0100 + +authbind (1.1.4) unstable; urgency=low + + * Allow bind() to port 0 ! + + -- Ian Jackson Mon, 31 Aug 1998 15:23:30 +0100 + +authbind (1.1.3) unstable; urgency=low + + * Make IPPORT_RESERVED check work (oops!). + + -- Ian Jackson Sun, 30 Aug 1998 20:52:10 +0100 + +authbind (1.1.2) unstable; urgency=low + + * Make --deep option actually work (oops). + + -- Ian Jackson Sun, 30 Aug 1998 20:09:39 +0100 + +authbind (1.1.1) unstable; urgency=low + + * Fix Description. + + -- Ian Jackson Sun, 30 Aug 1998 16:34:28 +0100 + +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. + + -- Ian Jackson Sun, 30 Aug 1998 03:15:21 +0100 + +authbind (0.1-1) experimental; urgency=low + + * Initial release. + + -- Ian Jackson Sat, 29 Aug 1998 20:10:37 +0100 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..d36c6e3 --- /dev/null +++ b/debian/control @@ -0,0 +1,12 @@ +Source: authbind +Section: utils +Priority: optional +Maintainer: Ian Jackson +Standards-Version: 3.9.1 + +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, without any changes to the application. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..4d351a2 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,26 @@ +This is the Debian GNU/Linux prepackaged version of my `authbind' +utility for allowing non-root programs to bind to privileged ports, +subject to configuration by the sysadmin. + +This package was put together by me, Ian Jackson +, from my git repository. + + +authbind is Copyright (C)1998,2012 Ian Jackson . + +authbind 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 of the License, 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 with +your Debian GNU/Linux system, in /usr/share/common-licenses, or with the +Debian GNU/Linux authbind source package as the file COPYING; if not, +email me at one of the addresses above. + +$Id$ diff --git a/debian/postinst b/debian/postinst new file mode 100644 index 0000000..cb07120 --- /dev/null +++ b/debian/postinst @@ -0,0 +1,9 @@ +#!/bin/sh + +if [ "$1" = "configure" ]; then + if [ -d /usr/doc -a -h /usr/doc/authbind -a -d /usr/share/doc/authbind ]; then + rm -f /usr/doc/authbind + fi +fi + + diff --git a/debian/postrm b/debian/postrm new file mode 100755 index 0000000..54aa82d --- /dev/null +++ b/debian/postrm @@ -0,0 +1,6 @@ +#!/bin/sh +set -e +if test "$1" = purge +then + rm -rf /etc/authbind +fi diff --git a/debian/prerm b/debian/prerm new file mode 100644 index 0000000..31beffd --- /dev/null +++ b/debian/prerm @@ -0,0 +1,7 @@ +#!/bin/sh + +if [ \( "$1" = "upgrade" -o "$1" = "remove" \) -a -L /usr/doc/authbind ]; +then + rm -f /usr/doc/authbind +fi + diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..c9091ed --- /dev/null +++ b/debian/rules @@ -0,0 +1,103 @@ +#! /usr/bin/make -f +# +# debian/rules for authbind +# +# 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. +# +# $Id$ + +CC= gcc +SHELL=/bin/bash + +package=authbind +major=1 +minor=0 + +arch = $(shell dpkg --print-architecture) + +export SOURCE_DATE_EPOCH = $(shell date -d "$$(dpkg-parsechangelog --count 1 -SDate)" +%s) + +INSTALL = install +INSTALL_FILE = $(INSTALL) -p -o root -g root -m 644 +INSTALL_PROGRAM = $(INSTALL) -p -o root -g root -m 755 +INSTALL_SCRIPT = $(INSTALL) -p -o root -g root -m 755 +INSTALL_DIR = $(INSTALL) -p -d -o root -g root -m 755 + +CFLAGS = -O2 -Wall +LDFLAGS = + + +CFLAGS += -g +LDFLAGS += -g + +ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) +INSTALL_PROGRAM += -s +STRIP=strip +else +STRIP=: +endif + +export CFLAGS +export LDFLAGS +export INSTALL +export INSTALL_FILE +export INSTALL_PROGRAM +export INSTALL_SCRIPT +export INSTALL_DIR +export STRIP + + +build: + $(MAKE) prefix=/usr + +clean: + $(MAKE) distclean + rm -rf debian/{files,substvars,tmp} build + rm -f debian/*~ debian/#*# debian/core debian/*.bak + +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) +udp=debian/tmp/usr/share/doc/$(package) + +binary-arch: checkroot build + rm -rf debian/tmp + install -d -g root -m 755 -o root debian/tmp/DEBIAN $(udp) \ + debian/tmp/usr/{bin,lib/$(package),share/man} + $(MAKE) prefix=debian/tmp/usr etc_dir=debian/tmp/etc/authbind \ + man_dir=debian/tmp/usr/share/man install install_man + $(INSTALL_FILE) debian/changelog $(udp)/changelog + gzip -9 debian/tmp/usr/share/man/man*/* $(udp)/* + $(INSTALL_FILE) debian/copyright $(udp)/. + $(INSTALL_SCRIPT) debian/{postrm,prerm,postinst} debian/tmp/DEBIAN + dpkg-shlibdeps ./authbind + dpkg-gencontrol -isp + chown -R root.root debian/tmp + chmod -R g-ws debian/tmp + find debian/tmp -newermt "@$$SOURCE_DATE_EPOCH" -print0 | \ + xargs -0r touch --no-dereference --date="@$$SOURCE_DATE_EPOCH" + dpkg --build debian/tmp .. + +binary: binary-indep binary-arch + +checkroot: + $(checkdir) + test root = "`whoami`" diff --git a/helper.c b/helper.c new file mode 100644 index 0000000..a58e7aa --- /dev/null +++ b/helper.c @@ -0,0 +1,269 @@ +/* + * helper.c - setuid helper program for authbind + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef CONFIGDIR +# define CONFIGDIR "/etc/authbind" +#endif + +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) { + fprintf(stderr,"libauthbind's helper: bad usage\n"); + exit(ENOSYS); +} + +static struct sockaddr_in saddr4; +static struct sockaddr_in6 saddr6; + +static struct sockaddr *saddr_any; +static const void *addr_any; +static size_t saddrlen_any, addrlen_any; + +static void authorised(void) { + if (bind(0,saddr_any,saddrlen_any)) exiterrno(errno); + else _exit(0); +} + +static void checkexecflagfile(const char *file) { + if (!access(file,X_OK)) authorised(); + if (errno != ENOENT) exiterrno(errno); +} + +static void hex2bytes(const char *string, unsigned char *out, int len) { + int i; + for (i=0; i= IPPORT_RESERVED/2) tophalfchar= "!"; + + if (chdir(CONFIGDIR)) perrorfail("chdir " CONFIGDIR); + + fnbuf[sizeof(fnbuf)-1]= 0; + + switch (af) { + case AF_INET: + saddr4.sin_family= af; + saddr4.sin_port= port; + saddr4.sin_addr.s_addr= addr4; + break; + case AF_INET6: + saddr6.sin6_family= af; + saddr6.sin6_port= port; + break; + default: + abort(); + } + + snprintf(fnbuf,sizeof(fnbuf)-1,"byport/%s%u",tophalfchar,hport); + if (!access(fnbuf,X_OK)) authorised(); + if (errno != ENOENT) exiterrno(errno); + + char npbuf[INET_ADDRSTRLEN + INET6_ADDRSTRLEN]; + np= inet_ntop(af,addr_any,npbuf,sizeof(npbuf)); + assert(np); + + if (af == AF_INET) { + snprintf(fnbuf,sizeof(fnbuf)-1,"byaddr/%s%s:%u",tophalfchar,np,hport); + checkexecflagfile(fnbuf); + } + + snprintf(fnbuf,sizeof(fnbuf)-1,"byaddr/%s%s,%u",tophalfchar,np,hport); + checkexecflagfile(fnbuf); + + if (af == AF_INET6) { + char sbuf[addrlen_any*3+1], *sp = sbuf; + const unsigned char *ip = addr_any; + int i; + for (i=0; i<8; i++) { + unsigned val = 0; + val |= *ip++; val <<= 8; + val |= *ip++; + if (i) *sp++ = ':'; + sp += sprintf(sp,"%x",val); + } + snprintf(fnbuf,sizeof(fnbuf)-1,"byaddr/%s%s,%u",tophalfchar,sbuf,hport); + checkexecflagfile(fnbuf); + } + + uid= getuid(); if (uid==(uid_t)-1) perrorfail("getuid"); + snprintf(fnbuf,sizeof(fnbuf)-1,"byuid/%s%lu",tophalfchar,(unsigned long)uid); + + file= fopen(fnbuf,"r"); + if (!file) exiterrno(errno==ENOENT ? EPERM : errno); + + while (fgets(fnbuf,sizeof(fnbuf)-1,file)) { + unsigned int a1,a2,a3,a4, alen,pmin,pmax; + int nchar; + + if (af == AF_INET && + (nchar = -1, + sscanf(fnbuf," %u.%u.%u.%u/%u: %u,%u %n", + &a1,&a2,&a3,&a4,&alen,&pmin,&pmax,&nchar), + nchar == strlen(fnbuf))) { + + if (alen>32 || pmin&~0x0ffff || pmax&~0x0ffff || + a1&~0x0ff || a2&~0xff || a3&~0x0ff || a4&~0x0ff) + continue; + + unsigned long thaddr, thmask; + thaddr= (a1<<24)|(a2<<16)|(a3<<8)|(a4); + thmask= alen ? 0x0ffffffffUL<<(32-alen) : 0; + if ((haddr4&thmask) != thaddr) continue; + + } else { + + char *comma = strchr(fnbuf,','); + if (!comma) continue; + *comma++ = '\0'; + + char *slash = strchr(fnbuf,'/'); + char *hyphen = strchr(fnbuf,'-'); + + if (slash && hyphen) + continue; + + if (slash) { + int alen; + *slash++ = '\0'; + nchar = -1; + sscanf(slash," %u %n",&alen,&nchar); + if (nchar != strlen(slash)) + continue; + unsigned char thaddr[addrlen_any]; + if (inet_pton(af,fnbuf,thaddr) != 1) + continue; + int pfxlen_remain = alen; + int i; + for (i=0; i> pfxlen_thisbyte); + unsigned thaddr_thisbyte = thaddr[i]; + unsigned addr_thisbyte = ((unsigned char*)addr_any)[i]; + if ((addr_thisbyte & mask_thisbyte) != thaddr_thisbyte) + goto badline; + } + if (pfxlen_remain) badline: continue; + /* hooray */ + } else { + const char *min, *max; + if (hyphen) { + *hyphen++ = '\0'; + min = fnbuf; + max = hyphen; + } else { + min = fnbuf; + max = fnbuf; + } + unsigned char minaddr[addrlen_any]; + unsigned char maxaddr[addrlen_any]; + if (inet_pton(af,min,minaddr) != 1 || + inet_pton(af,max,maxaddr) != 1) + continue; + if (memcmp(addr_any,minaddr,addrlen_any) < 0 || + memcmp(addr_any,maxaddr,addrlen_any) > 0) + continue; + } + + if (nchar = -1, + sscanf(comma," %u-%u %n", + &pmin,&pmax,&nchar), + nchar == strlen(comma)) { + /* good */ + } else if (nchar = -1, + sscanf(comma," %u %n", + &pmin,&nchar), + nchar == strlen(comma)) { + pmax = pmin; + } else { + continue; + } + + } + if (hportpmax) continue; + + authorised(); + } + if (ferror(file)) perrorfail("read per-uid file"); + _exit(ENOENT); +} diff --git a/libauthbind.c b/libauthbind.c new file mode 100644 index 0000000..a685ce3 --- /dev/null +++ b/libauthbind.c @@ -0,0 +1,232 @@ +/* + * libauthbind.c - bind(2)-redirector library for authbind + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "authbind.h" + +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 anyfn_type *find_any(const char *name) { + static const char *dlerr; + anyfn_type *kv; + + kv= dlsym(RTLD_NEXT,name); if (kv) return kv; + 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 0; +} + +static bindfn_type find_bind, *old_bind= find_bind; + +int find_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) { + anyfn_type *anyfn; + anyfn= find_any("bind"); if (!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); +} + +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; +} + +static const int evilsignals[]= { SIGFPE, SIGILL, SIGSEGV, SIGBUS, 0 }; + +int bind(int fd, const struct sockaddr *addr, socklen_t addrlen) { + pid_t child, rchild; + char portarg[5], addrarg[33]; + const char *afarg; + int i, r, status; + const int *evilsignal; + sigset_t block, saved; + unsigned int portval; + + switch (addr->sa_family) { + case AF_INET: + portval = ((struct sockaddr_in*)addr)->sin_port; + if (addrlen != sizeof(struct sockaddr_in)) goto bail; + break; + case AF_INET6: + portval = ((struct sockaddr_in6*)addr)->sin6_port; + if (addrlen != sizeof(struct sockaddr_in6)) goto bail; + break; + default: + goto bail; + } + + if (!geteuid() || portval == 0 || ntohs(portval) >= IPPORT_RESERVED) { + bail: + return old_bind(fd,addr,addrlen); + } + + sigfillset(&block); + for (evilsignal=evilsignals; + *evilsignal; + evilsignal++) + sigdelset(&block,*evilsignal); + if (sigprocmask(SIG_BLOCK,&block,&saved)) return -1; + + switch (addr->sa_family) { + case AF_INET: + afarg = 0; + sprintf(addrarg,"%08lx", + ((unsigned long)(((struct sockaddr_in*)addr)->sin_addr.s_addr)) + &0x0ffffffffUL); + break; + case AF_INET6: + afarg = "6"; + for (i=0; i<16; i++) + sprintf(addrarg+i*2,"%02x", + ((struct sockaddr_in6*)addr)->sin6_addr.s6_addr[i]); + break; + default: + abort(); + } + sprintf(portarg,"%04x", + portval&0x0ffff); + + child= fork(); if (child==-1) goto x_err; + + if (!child) { + if (dup2(fd,0)) exiterrno(errno); + removepreload(); + execl(HELPER,HELPER,addrarg,portarg,afarg,(char*)0); + status= errno > 0 && errno < 127 ? errno : 127; + STDERRSTR_CONST("libauthbind: possible installation problem - " + "could not invoke " HELPER "\n"); + exiterrno(status); + } + + rchild= waitpid(child,&status,0); + if (rchild==-1) goto x_err; + if (rchild!=child) { errno= ECHILD; goto x_err; } + + if (WIFEXITED(status)) { + if (WEXITSTATUS(status)) { + errno= WEXITSTATUS(status); + if (errno >= 127) errno= ENXIO; + goto x_err; + } + r= 0; + goto x; + } else { + errno= ENOSYS; + goto x_err; + } + +x_err: + r= -1; +x: + if (sigprocmask(SIG_SETMASK,&saved,0)) abort(); + return r; +} -- 2.30.2