chiark / gitweb /
0.57 release-0-57
authorian <ian>
Tue, 14 Oct 1997 01:05:13 +0000 (01:05 +0000)
committerian <ian>
Tue, 14 Oct 1997 01:05:13 +0000 (01:05 +0000)
Changelog
INSTALL
Makefile.in
client.c
common.h
daemon.h
overlord.c
process.c
servexec.c
spec.sgml.in

index 9af7e5c..9ea9b1c 100644 (file)
--- a/Changelog
+++ b/Changelog
@@ -1,3 +1,18 @@
+userv (0.57); urgency=high
+
+  * Services provided by root work !
+  * uservd can now go into background itself (-daemon option).
+
+  * spec now has default syslog facility for rcfile messages as `user'.
+  * Better prioritisation of syslog messages.
+  * Startup error messages now go to stderr instead.
+  * SIGTERM and SIGINT now produce a syslog message.
+
+  * Version number has VEREXT component, settable via make args &c.
+  * New sections in INSTALL about exit statuses and -daemon.
+
+ -- Ian Jackson <ian@davenant.greenend.org.uk>  Tue, 14 Oct 1997 02:04:18 +0100
+
 userv (0.56); urgency=medium
 
   * Server now checks itself every hour to see if its socket has been
diff --git a/INSTALL b/INSTALL
index dee9597..4b5d665 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -55,8 +55,9 @@ System interfaces:
     open(O_WRONLY), close(), dup2, EPIPE, SIGPIPE, &c.
     (ie, opening pipes with O_RDWR never blocks; EPIPE happens
     if you write with no readers; EOF happens if you read with
-    no buffered data and writers)
+    no buffered data and writers);
 * POSIX signal handling - sigaction(2), sigprocmask(2), sigsuspend(2);
+* POSIX sessions - setsid(2) (for -daemon flag).
 
 To format the documentation:
 
@@ -68,6 +69,106 @@ For debugging version (./configure --enable-debug):
 * initgroups(3) must use setgroups(2) and dynamic
   linking must allow overriding setgroups(2) for initgroups(3);
 
+DAEMON INVOCATION:
+
+The daemon can be invoked with no arguments, in which case it will not
+fork or detach itself.  This is suitable for running from init and
+similar arrangements.
+
+With -daemon it will attempt to detach itself from the controlling
+terminal and fork/exit so that control returns at startup.
+
+In both cases diagnostics which prevent correct startup will appear on
+stderr.
+
+SYSLOG MESSAGES:
+
+The daemon issues diagnostics of various kinds to syslog, usually with
+facility LOG_DAEMON (though this can be changed in daemon.h if you want).
+The syslog levels used are:
+ debug - verbose messages about the activity of the userv daemon.
+ info - two log message about the nature and outcome of each request.
+ notice - messages about the status of the daemon, including the
+          startup message and the hourly socket check messages.
+ warning - if the uservd exits because it believes that it no longer
+          controls the rendezvous socket (ie, its socket has become
+          orphaned), this level will receive messages indicating why
+          the daemon believes this and notifying of its shutdown.
+ err - a believed-recoverable error condition was detected by the
+       userv server in itself, the client or the operating system
+       (this includes resource shortages). The uservd will try to
+       continue.
+ crit - the uservd detected a non-recoverable error condition
+        after startup and will exit.
+ alert - not used.
+ emerg - not used.
+
+The service configuration language has the facility to direct error
+and warning messages to syslog.  The default facility and level is
+user.err, but the author of the configuration file(s) can override
+this.
+
+DAEMON EXIT STATUS:
+
+The daemon's exit code will reflect how well things went:
+
+ 0 - The daemon was asked to detach itself from the controlling
+     terminal and this appears to have been done successfully.
+ 1* - The daemon got a SIGTERM or SIGINT and shut itself down.
+ 2* - The daemon believes that it was no longer the uservd and so has
+      exited to clean itself up.
+ 3 - uservd was started with incorrect arguments.
+ 4 - A system call failure or other environmental problem occurred
+     during startup.
+ 5* - There was a non-recoverable error after startup; the uservd had
+      to exit.
+ 6 - The daemon was asked to detach itself, but its detaching child
+     died for some unexpected reason.
+
+ SIGABRT/SIGIOT* - an unexpected internal error, usually caused by a
+   bug in uservd.  This can also occur if an attempt to block signals
+   using sigprocmask fails.
+
+Outcomes marked * are not possible if the daemon is asked to detach
+itself - these exit statuses will be reaped by init instead.
+
+The daemon's per-request children will note the success level of its
+request in its exit status.  This will not usually be logged unless it
+is higher than those listed below; they are presented here for
+completeness and as programming documentation.
+
+ 2 - The connection was just an internal version check.
+
+ 4 - The client requested that the service be disconnected.  This
+     includes normal termination, which is achieved by having the
+     server tell the client that the service has completed and waiting
+     for the client to tell it to disconnect.
+
+ 8 - The client closed its end of the socket when this would not
+     usually have been expected, causing an EPIPE or unexpected EOF in
+     the server.  This is not an error condition - it can happen, for
+     example, if the client receives a fatal signal of some kind from
+     its execution environment (eg its controlling terminal).
+
+ 12 - The service failed onm the service side in an expected and
+      controlled manner, for example because it was rejected in the
+      configuration files.
+
+ 16 - A fatal system call failure or other general error occurred,
+      which ought not to have happened at all, barring system resource
+      shortages.
+
+ 20 - The client sent invalid data to the server, after the client
+      dropped all its system privilege.  On some systems this can be
+      caused by a malicious calling user.
+
+ SIGABRT/SIGIOT - The client sent invalid data to the server before it
+   dropped all its system privileges, or some other unexpected
+   internal error occurred.  This can also occur if an attempt to
+   block signals using sigprocmask fails.
+
+ 0-3,5-7,9-11,13-15,17-19 are not currently used.
+
 REENTRANCY IN THE LIBC:
 
 We assume, both in the client and server, that it is safe to use one
index 03e99ed..4339481 100644 (file)
 #  Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
 VERSION=@VERSION@
+VEREXT=std
 
 CC=@CC@
-CFLAGS=@CFLAGS@ $(XCFLAGS) -DVERSION='"$(VERSION)"'
+CFLAGS=@CFLAGS@ $(XCFLAGS) -DVERSION='"$(VERSION)"' -DVEREXT='"$(VEREXT)"'
 OPTIMISE=@OPTIMISE@
 CPPFLAGS=@DEBUGDEFS@ $(XCPPFLAGS)
 LDLIBS=@DEBUGLIBS@ $(XLDLIBS)
index 4fbb710..bc55412 100644 (file)
--- a/client.c
+++ b/client.c
@@ -434,7 +434,7 @@ static void usage(void) {
     "         --spoof-user <username>         }  or same user\n"
     "fdmodifiers:            read    write  overwrite    trunc[ate]\n"
     "(separate with commas)  append  sync   excl[usive]  creat[e]  fd\n\n"
-    "userv and uservd version " VERSION "; copyright (C)1996-1997 Ian Jackson.\n"
+    "userv and uservd version " VERSION VEREXT "; copyright (C)1996-1997 Ian Jackson.\n"
     "there is NO WARRANTY; type `userv --copyright' for details.\n",
             stderr) < 0)
     syscallerror("write usage to stderr");
@@ -1047,6 +1047,7 @@ static void server_sendrequest(int argc, char *const *argv) {
   request_mbuf.serviceuserlen= strlen(serviceuser);
   request_mbuf.servicelen= strlen(argv[0]);
   request_mbuf.lognamelen= strlen(logname);
+  request_mbuf.spoofed= spoofuser ? 1 : 0;
   request_mbuf.cwdlen= cwdbufsize;
   request_mbuf.callinguid= spoofuid;
   request_mbuf.ngids= ngids+1;
index ee243b1..f385fc9 100644 (file)
--- a/common.h
+++ b/common.h
@@ -82,10 +82,10 @@ struct opening_msg {
 
 struct request_msg {
   unsigned long magic;
-  pid_t clientpid;
+  pid_t clientpid; /* or -1 if no service is required and this was a version check */
   int serviceuserlen;
   int servicelen;
-  int lognamelen;
+  int lognamelen, spoofed; /* spoofed is 0 or 1 */
   int cwdlen, overridelen;
   uid_t callinguid;
   int ngids, nreadfds, nwritefds, nargs, nvars;
index 9efd982..945d651 100644 (file)
--- a/daemon.h
+++ b/daemon.h
@@ -77,7 +77,7 @@
 #define USERVD_LOGIDENT "uservd"
 #define USERVDCHECK_LOGIDENT "uservd/check"
 #define USERVD_LOGFACILITY LOG_DAEMON
-#define DEFUSERLOGFACILITY LOG_DAEMON
+#define DEFUSERLOGFACILITY LOG_USER
 #define DEFUSERLOGLEVEL LOG_ERR
 
 #define TOPLEVEL_CONFIGURATION "                   \n\
 
 #define USERVD_MYSELF_CHECK 3600
 #define USERVD_MYSELF_TIMEOUT 60
+#define USERVD_CHECKFORK_RETRY 60
 #define MAX_INCLUDE_NEST 40
 #define MAX_ERRMSG_LEN (MAX_ERRMSG_STRING-1024)
 #define ERRMSG_RESERVE_ERRNO 128
index e32c9a1..b18102f 100644 (file)
@@ -32,6 +32,7 @@
 #include <sys/time.h>
 #include <sys/stat.h>
 #include <sys/socket.h>
+#include <sys/fcntl.h>
 #include <dirent.h>
 #include <sys/un.h>
 
@@ -41,7 +42,7 @@
 
 pid_t overlordpid;
 
-static pid_t checkpid= -1;
+static pid_t checkpid= -1, detachpid= -1;
 static sig_atomic_t needcheck= 1;
 
 static void checkstalepipes(void) {
@@ -87,19 +88,24 @@ static void sighandler_chld(int x) {
     r= waitpid((pid_t)-1,&status,WNOHANG);
     if (!r || (r==-1 && errno==ECHILD)) break;
     if (r==-1) { syslog(LOG_ERR,"wait in sigchild handler gave error: %m"); break; }
+    if (r==detachpid) {
+      if (WIFEXITED(status) && WEXITSTATUS(status)==4) _exit(4);
+      fprintf(stderr,"uservd: detaching child failed with unexpected code %d\n",status);
+      exit(6);
+    }
     if (r==checkpid) {
       if (WIFEXITED(status)) {
        if (!WEXITSTATUS(status)) {
-         syslog(LOG_NOTICE,"no longer the uservd - exiting");
-         _exit(0);
+         syslog(LOG_WARNING,"no longer the uservd - exiting");
+         _exit(2);
        } else if (WEXITSTATUS(status)!=1) {
          syslog(LOG_ERR,"check pid %ld exited with status %d",
                 (long)checkpid,WEXITSTATUS(status));
        }
       } else if (WIFSIGNALED(status)) {
        if (WTERMSIG(status) == SIGALRM && !WCOREDUMP(status)) {
-         syslog(LOG_NOTICE,"check timed out; no longer the uservd - exiting");
-         _exit(0);
+         syslog(LOG_WARNING,"check timed out; no longer the uservd - exiting");
+         _exit(2);
        } else {
          syslog(LOG_ERR,"check pid %ld %s due to signal %s",
                 (long)checkpid,
@@ -134,10 +140,19 @@ static void sighandler_chld(int x) {
   return;
 }
 
+static void sighandler_usr1(int x) {
+  _exit(0);
+}
+
 static void sighandler_alrm(int x) {
   needcheck= 1;
 }
 
+static void sighandler_termint(int sig) {
+  syslog(LOG_NOTICE,"terminating due to signal %s",strsignal(sig));
+  _exit(1);
+}
+
 static void blocksignals(int how) {
   int r;
   sigset_t set;
@@ -145,6 +160,8 @@ static void blocksignals(int how) {
   sigemptyset(&set);
   sigaddset(&set,SIGCHLD);
   sigaddset(&set,SIGALRM);
+  sigaddset(&set,SIGTERM);
+  sigaddset(&set,SIGINT);
   r= sigprocmask(how,&set,0); assert(!r);
 }
 
@@ -156,6 +173,8 @@ static void NONRETURNING docheck(void) {
   int sfd, r, remain;
   unsigned char *p;
   struct opening_msg opening_mbuf;
+  struct request_msg request_mbuf;
+  unsigned long endmagic;
   struct sigaction sig;
   struct sockaddr_un ssockname;
 
@@ -179,7 +198,7 @@ static void NONRETURNING docheck(void) {
   r= connect(sfd,(struct sockaddr*)&ssockname,sizeof(ssockname));
   if (r) {
     if (errno == ECONNREFUSED || errno == ENOENT)
-      { syslog(LOG_NOTICE,"uservd daemon is not running: %m"); exit(0); }
+      { syslog(LOG_WARNING,"real uservd daemon is not running: %m"); exit(0); }
     syslog(LOG_ERR,"unable to connect to uservd daemon: %m"); exit(1);
   }
 
@@ -193,53 +212,86 @@ static void NONRETURNING docheck(void) {
     remain-= r; p+= r;
   }
   if (opening_mbuf.magic != OPENING_MAGIC) {
-    syslog(LOG_NOTICE,"magic number mismatch");
+    syslog(LOG_WARNING,"magic number mismatch");
     exit(0);
   }
   if (memcmp(opening_mbuf.protocolchecksumversion,protocolchecksumversion,PCSUMSIZE)) {
-    syslog(LOG_NOTICE,"protocol checksum mismatch");
+    syslog(LOG_WARNING,"protocol checksum mismatch");
     exit(0);
   }
   if (opening_mbuf.overlordpid != overlordpid) {
-    syslog(LOG_NOTICE,"overlord pid mismatch");
+    syslog(LOG_WARNING,"overlord pid mismatch");
     exit(0);
   }
-  syslog(LOG_NOTICE,"check - same daemon still running");
+  memset(&request_mbuf,0,sizeof(request_mbuf));
+  request_mbuf.magic= REQUEST_MAGIC;
+  request_mbuf.clientpid= -1;
+  request_mbuf.serviceuserlen= 0;
+  request_mbuf.servicelen= 0;
+  request_mbuf.lognamelen= 0;
+  request_mbuf.spoofed= 0;
+  request_mbuf.cwdlen= 0;
+  request_mbuf.overridelen= -1;
+  request_mbuf.callinguid= -1;
+  request_mbuf.ngids= 0;
+  request_mbuf.nreadfds= 0;
+  request_mbuf.nwritefds= 0;
+  request_mbuf.nargs= 0;
+  request_mbuf.nvars= 0;
+  r= write(sfd,&request_mbuf,sizeof(request_mbuf));
+  if (r==sizeof(request_mbuf)) {
+    endmagic= REQUEST_END_MAGIC;
+    write(sfd,&endmagic,sizeof(endmagic));
+  }
+  syslog(LOG_NOTICE,"uservd[%ld] is running",(long)overlordpid);
 #endif
   exit(1);
 }
 
+static void NONRETURNING startupsyscallerr(const char *what) {
+  fprintf(stderr,
+         "uservd: system call failed during startup:\n"
+         "uservd: %s: %s\n",
+         what,strerror(errno));
+  exit(4);
+}
+
 int main(int argc, char *const *argv) {
-  int mfd, sfd, csocklen, e;
+  int mfd, sfd, nfd, csocklen, e, r, becomedaemon;
   struct sigaction sigact;
   struct sockaddr_un ssockname, csockname;
-  pid_t child;
+  pid_t child, parentpid, sid;
 
 #ifdef NDEBUG
   abort(); /* Do not disable assertions in this security-critical code ! */
 #endif
 
-  if (argc>1) { fputs("usage: uservd\n",stderr); exit(3); }
+  becomedaemon= 0;
+  
+  if (argv[1] && !strcmp(argv[1],"-daemon")) {
+    becomedaemon= 1;
+    argv++; argc--;
+  }
+  if (argc>1) { fputs("usage: uservd [-daemon]\n",stderr); exit(3); }
 
   openlog(USERVD_LOGIDENT,LOG_NDELAY|LOG_PID,USERVD_LOGFACILITY);
 
-  if (chdir(VARDIR)) { syslog(LOG_CRIT,"cannot change to " VARDIR ": %m"); exit(4); }
+  if (chdir(VARDIR)) startupsyscallerr("cannot change to " VARDIR);
   checkstalepipes();
 
-  overlordpid= getpid();
-  if (overlordpid==-1) { syslog(LOG_CRIT,"cannot getpid: %m"); exit(4); }
+  overlordpid= parentpid= getpid();
+  if (parentpid==-1) startupsyscallerr("cannot getpid");
 
   mfd= socket(AF_UNIX,SOCK_STREAM,0);
-  if (mfd<0) { syslog(LOG_CRIT,"cannot create master socket: %m"); exit(4); }
+  if (mfd<0) startupsyscallerr("cannot create master socket");
 
   assert(sizeof(ssockname.sun_path) > sizeof(RENDEZVOUS));
   ssockname.sun_family= AF_UNIX;
   strcpy(ssockname.sun_path,RENDEZVOUS);
   unlink(RENDEZVOUS);
-  if (bind(mfd,(struct sockaddr*)&ssockname,sizeof(ssockname)))
-    { syslog(LOG_CRIT,"cannot bind master socket: %m"); exit(4); }
-  if (listen(mfd,5))
-    { syslog(LOG_CRIT,"cannot listen on master socket: %m"); exit(4); }
+  r= bind(mfd,(struct sockaddr*)&ssockname,sizeof(ssockname));
+  if (r) startupsyscallerr("cannot bind master socket");
+  if (listen(mfd,5)) startupsyscallerr("cannot listen on master socket");
 
   sigemptyset(&sigact.sa_mask);
   sigaddset(&sigact.sa_mask,SIGCHLD);
@@ -247,20 +299,62 @@ int main(int argc, char *const *argv) {
   sigact.sa_flags= SA_NOCLDSTOP;
 
   sigact.sa_handler= sighandler_chld;
-  if (sigaction(SIGCHLD,&sigact,0))
-    { syslog(LOG_CRIT,"cannot setup sigchld handler: %m"); exit(4); }
+  if (sigaction(SIGCHLD,&sigact,0)) startupsyscallerr("cannot setup sigchld handler");
 
   sigact.sa_handler= sighandler_alrm;
-  if (sigaction(SIGALRM,&sigact,0))
-    { syslog(LOG_CRIT,"cannot setup sigalrm handler: %m"); exit(4); }
+  if (sigaction(SIGALRM,&sigact,0)) startupsyscallerr("cannot setup sigalrm handler");
+
+  if (becomedaemon) {
+    sigact.sa_handler= sighandler_usr1;
+    if (sigaction(SIGUSR1,&sigact,0)) startupsyscallerr("cannot setup sigusr1 handler");
+    
+    detachpid= fork(); if (detachpid==-1) startupsyscallerr("cannot fork to detach");
+    if (detachpid) {
+      pause();
+      fputs("uservd: pause unexpectedly returned during detach\n",stderr);
+      exit(4);
+    }
+    sigact.sa_handler= SIG_DFL;
+    if (sigaction(SIGUSR1,&sigact,0)) startupsyscallerr("cannot restore sigusr1");
+  }
+
+  sigact.sa_handler= sighandler_termint;
+  if (sigaction(SIGTERM,&sigact,0)) startupsyscallerr("cannot setup sigterm handler");
+  if (sigaction(SIGINT,&sigact,0)) startupsyscallerr("cannot setup sigint handler");
+
+  if (becomedaemon) {
+    nfd= open("/dev/null",O_RDWR);
+    if (nfd<0) startupsyscallerr("cannot open /dev/null");
+    sid= setsid(); if (sid == -1) startupsyscallerr("cannot create new session");
+    overlordpid= getpid();
+    if (overlordpid == -1) startupsyscallerr("getpid after detach");
+    if (dup2(nfd,0)<0 || dup2(nfd,1)<0)
+      startupsyscallerr("cannot dup /dev/null for stdin/out");
+    r= kill(parentpid,SIGUSR1); if (r) startupsyscallerr("send SIGUSR1 to detach");
+    r= dup2(nfd,2);
+    if (r<0) { syslog(LOG_CRIT,"cannot dup /dev/null for stderr: %m"); exit(5); }
+    close(nfd);
+  }
 
   syslog(LOG_NOTICE,"started");
+
   for (;;) {
     if (needcheck) {
       assert(checkpid==-1);
-      checkpid= fork();
-      if (checkpid==-1) { syslog(LOG_CRIT,"fork for check: %m"); exit(5); }
-      if (!checkpid) docheck();
+      for (;;) {
+       checkpid= fork();
+       if (checkpid!=-1) {
+         if (!checkpid) docheck();
+         break;
+       } else if (errno==EAGAIN) {
+         syslog(LOG_ERR,"fork for check - will wait and retry: %m");
+         r= alarm(USERVD_CHECKFORK_RETRY);
+         if (r<0) { syslog(LOG_CRIT,"set alarm for retry check: %m"); exit(5); }
+         break;
+       } else if (errno!=EINTR) {
+         syslog(LOG_CRIT,"fork for check: %m"); exit(5);
+       }
+      }
       needcheck= 0;
     }
     csocklen= sizeof(csockname);
index 98bbeec..9f6fbc0 100644 (file)
--- a/process.c
+++ b/process.c
@@ -126,7 +126,7 @@ static void xfwriteerror(void) {
   if (errno != EPIPE) syscallerror("writing to client");
   blocksignals();
   ensurelogopen(USERVD_LOGFACILITY);
-  syslog(LOG_DEBUG,"client went away (broken pipe)");
+  syslog(LOG_INFO,"client went away (broken pipe)");
   disconnect(8);
 }
 
@@ -151,7 +151,7 @@ static void xfread(void *p, size_t sz) {
   if (ferror(srfile)) syscallerror("reading from client");
   blocksignals();
   assert(feof(srfile));
-  syslog(LOG_DEBUG,"client went away (unexpected EOF)");
+  syslog(LOG_INFO,"client went away (unexpected EOF)");
   swfile= 0;
   disconnect(8);
 }
@@ -183,7 +183,7 @@ static void getevent(struct event_msg *event_r) {
        blocksignals();
        syslog(LOG_ERR,"client sent bad file descriptor %d to close (max %d)",
               fd,fdarrayused-1);
-       disconnect(12);
+       disconnect(20);
       }
       if (fdarray[fd].holdfd!=-1) {
        if (close(fdarray[fd].holdfd)) syscallerror("cannot close holding fd");
@@ -192,7 +192,7 @@ static void getevent(struct event_msg *event_r) {
       break;
     case et_disconnect:
       blocksignals();
-      syslog(LOG_DEBUG,"client disconnected");
+      syslog(LOG_INFO,"client disconnected");
       disconnect(4);
     default:
       return;
@@ -218,7 +218,7 @@ void syscallerror(const char *what) {
   e= errno;
   blocksignals();
   syslog(LOG_ERR,"system call failure: %s: %s",what,strerror(e));
-  disconnect(18);
+  disconnect(16);
 }
 
 /* Functions which may be called from signal handlers.  These
@@ -287,7 +287,7 @@ static void NONRETURNING sighandler_chld(int ignored) {
   xfwrite(&progress_mbuf,sizeof(progress_mbuf),swfile);
   xfflush(swfile);
 
-  syslog(LOG_DEBUG,"service completed (status %d %d)",(status>>8)&0x0ff,status&0x0ff);
+  syslog(LOG_INFO,"service completed (status %d %d)",(status>>8)&0x0ff,status&0x0ff);
   _exit(0);
 }
 
@@ -327,7 +327,7 @@ static void NONRETURNING generalfailure(const char *prefix, int reserveerrno,
     strnytcat(errmsg,strerror(errnoval),sizeof(errmsg));
   }
   senderrmsgstderr(errmsg);
-  syslog(LOG_DEBUG,"service failed (%s)",errmsg);
+  syslog(LOG_INFO,"service failed (%s)",errmsg);
   disconnect(12);
 }
 
@@ -412,6 +412,7 @@ static void receive_request(void) {
   xfread(&request_mbuf,sizeof(request_mbuf));
   serviceuser= xfreadsetstring(request_mbuf.serviceuserlen);
   service= xfreadsetstring(request_mbuf.servicelen);
+  assert(request_mbuf.spoofed==0 || request_mbuf.spoofed==1);
   logname= xfreadsetstring(request_mbuf.lognamelen);
   cwd= xfreadsetstring(request_mbuf.cwdlen);
   if (request_mbuf.overridelen >= 0) {
@@ -509,9 +510,10 @@ static void lookup_uidsgids(void) {
   if (initgroups(pw->pw_name,pw->pw_gid)) syscallerror("initgroups");
   if (setreuid(pw->pw_uid,pw->pw_uid)) syscallerror("setreuid 1");
   if (setreuid(pw->pw_uid,pw->pw_uid)) syscallerror("setreuid 2");
-  if (pw->pw_uid)
+  if (pw->pw_uid) {
     if (!setreuid(pw->pw_uid,0)) miscerror("setreuid 3 unexpectedly succeeded");
-  if (errno != EPERM) syscallerror("setreuid 3 failed in unexpected way");
+    if (errno != EPERM) syscallerror("setreuid 3 failed in unexpected way");
+  }
 
   service_ngids= getgroups(0,0); if (service_ngids == -1) syscallerror("getgroups(0,0)");
   if (service_ngids > MAX_GIDS) miscerror("service user is in far too many groups");
@@ -711,9 +713,13 @@ void servicerequest(int sfd) {
   setup_comms(sfd);
   send_opening();
   receive_request();
+  if (request_mbuf.clientpid == (pid_t)-1) _exit(2);
   establish_pipes();
   lookup_uidsgids();
   debug_dumprequest(mypid);
+  syslog(LOG_INFO,"%s %s -> %s %c %s",
+        request_mbuf.spoofed ? "spoof" : "user",
+        logname, serviceuser, overridedata?'!':':', service);
 
   if (overridedata)
     r= parse_string(TOPLEVEL_OVERRIDDEN_CONFIGURATION,
index 2b11012..41c6d37 100644 (file)
@@ -61,7 +61,7 @@ void bisexec_version(const char *const *argv) {
   const unsigned char *p;
   int i;
   
-  printf("uservd version " VERSION "; copyright (C)1996-1997 Ian Jackson.\n"
+  printf("uservd version " VERSION VEREXT "; copyright (C)1996-1997 Ian Jackson.\n"
 #ifdef DEBUG
         "DEBUGGING VERSION"
 #else
index 8757851..6d018eb 100644 (file)
@@ -707,7 +707,7 @@ in the context of and with the privileges of the service user.
 <tag/<tt/errors-to-syslog/ [<var/facility/ [<var/level/]]/
 <item>
 Error messages will be delivered using <prgn/syslog/.  The default
-<var/facility/ is <tt/daemon/; the default <var/level/ is <tt/error/.
+<var/facility/ is <tt/user/; the default <var/level/ is <tt/error/.
 </taglist>
 
 <sect1 id="dirs-control">Control structure directives