chiark / gitweb /
Internal review up to end of p11.
[userv.git] / process.c
1 /*
2  * userv - process.c
3  * daemon code to process one request (is parent of service process)
4  *
5  * Copyright (C)1996-1997 Ian Jackson
6  *
7  * This is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with userv; if not, write to the Free Software
19  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */
21
22 /* We do some horrible asynchronous stuff with signals.
23  *
24  * The following objects &c. are used in signal handlers and so
25  * must be protected by calls to blocksignals if they are used in
26  * the main program:
27  *  the syslog() family of calls, and the associated
28  *    syslogopenfacility variable
29  *  swfile (stdio stream)
30  *
31  * The following objects are used in the main program unprotected
32  * and so must not be used in signal handlers:
33  *  srfile
34  *
35  * child and childtokill are used for communication between the
36  * main thread and the signal handlers; none of the signal handlers
37  * return so errno is OK too.
38  */
39
40 #include <stdio.h>
41 #include <stdarg.h>
42 #include <unistd.h>
43 #include <wait.h>
44 #include <assert.h>
45 #include <signal.h>
46 #include <string.h>
47 #include <stdlib.h>
48 #include <errno.h>
49 #include <syslog.h>
50 #include <pwd.h>
51 #include <grp.h>
52 #include <ctype.h>
53 #include <limits.h>
54 #include <sys/types.h>
55 #include <sys/fcntl.h>
56 #include <sys/stat.h>
57 #include <sys/socket.h>
58 #include <sys/un.h>
59
60 #include "config.h"
61 #include "common.h"
62 #include "daemon.h"
63 #include "lib.h"
64 #include "tokens.h"
65
66 /* NB: defaults for the execution state are not set here, but in
67  * the RESET_CONFIGURATION #define in daemon.h. */
68 char **argarray;
69 char *((*defvararray)[2]);
70 struct fdstate *fdarray;
71 int fdarraysize, fdarrayused;
72 int restfdwantstate= tokv_word_rejectfd, restfdwantrw;
73 struct request_msg request_mbuf;
74 char *serviceuser, *service, *logname, *cwd;
75 char *overridedata, *userrcfile;
76 char *serviceuser_dir, *serviceuser_shell, *callinguser_shell;
77 int service_ngids;
78 gid_t *calling_gids, *service_gids;
79 const char **calling_groups, **service_groups;
80 uid_t serviceuser_uid=-1;
81 char *execpath, **execargs;
82 int execute;
83 int setenvironment, suppressargs, disconnecthup;
84 int syslogopenfacility=-1;
85
86 static FILE *swfile, *srfile;
87 static pid_t child=-1, childtokill=-1;
88 static pid_t mypid;
89
90 /* Function shared with servexec.c: */
91
92 int synchread(int fd, int ch) {
93   char synchmsg;
94   int r;
95   
96   for (;;) {
97     r= read(fd,&synchmsg,1);
98     if (r==1) break;
99     if (r==0) { errno= ECONNRESET; return -1; }
100     assert(r<0);
101     if (errno!=EINTR) return -1;
102   };
103   assert(synchmsg==ch);
104   return 0;
105 }
106
107 /* General-purpose functions; these do nothing special about signals */
108
109 static void blocksignals(void) {
110   int r;
111   sigset_t set;
112
113   sigemptyset(&set);
114   sigaddset(&set,SIGCHLD);
115   sigaddset(&set,SIGPIPE);
116   r= sigprocmask(SIG_BLOCK,&set,0); assert(!r);
117 }
118
119 static void xfwriteerror(void) {
120   if (errno != EPIPE) syscallerror("writing to client");
121   blocksignals();
122   ensurelogopen(USERVD_LOGFACILITY);
123   syslog(LOG_DEBUG,"client went away (broken pipe)");
124   disconnect(8);
125 }
126
127 static void xfwrite(const void *p, size_t sz, FILE *file) {
128   size_t nr;
129   nr= fwrite(p,1,sz,file);
130   if (nr != sz) xfwriteerror();
131 }
132
133 static void xfflush(FILE *file) {
134   if (fflush(file)) xfwriteerror();
135 }
136
137 /* Functions which may be called only from the main thread.  These may
138  * use main-thread objects and must block signals before using signal
139  * handler objects.
140  */
141
142 static void xfread(void *p, size_t sz) {
143   size_t nr;
144   nr= fread(p,1,sz,srfile); if (nr == sz) return;
145   if (ferror(srfile)) syscallerror("reading from client");
146   blocksignals();
147   assert(feof(srfile));
148   syslog(LOG_DEBUG,"client went away (unexpected EOF)");
149   swfile= 0;
150   disconnect(8);
151 }
152
153 static char *xfreadsetstring(int l) {
154   char *s;
155   assert(l<=MAX_GENERAL_STRING);
156   s= xmalloc(l+1);
157   xfread(s,sizeof(*s)*l);
158   s[l]= 0;
159   return s;
160 }
161
162 static char *xfreadstring(void) {
163   int l;
164   xfread(&l,sizeof(l));
165   return xfreadsetstring(l);
166 }
167
168 static void getevent(struct event_msg *event_r) {
169   int fd;
170   
171   for (;;) {
172     xfread(event_r,sizeof(struct event_msg));
173     switch (event_r->type) {
174     case et_closereadfd:
175       fd= event_r->data.closereadfd.fd;
176       assert(fd<fdarrayused);
177       if (fdarray[fd].holdfd!=-1) {
178         if (close(fdarray[fd].holdfd)) syscallerror("cannot close holding fd");
179         fdarray[fd].holdfd= -1;
180       }
181       break;
182     case et_disconnect:
183       blocksignals();
184       syslog(LOG_DEBUG,"client disconnected");
185       disconnect(4);
186     default:
187       return;
188     }
189   }
190 }
191
192 /* Functions which may be called either from signal handlers or from
193  * the main thread.  They block signals in case they are on the main
194  * thread, and may only use signal handler objects.  None of them
195  * return.  If they did they'd have to restore the signal mask.
196  */
197
198 void miscerror(const char *what) {
199   blocksignals();
200   syslog(LOG_ERR,"failure: %s",what);
201   disconnect(16);
202 }
203
204 void syscallerror(const char *what) {
205   int e;
206
207   e= errno;
208   blocksignals();
209   syslog(LOG_ERR,"system call failure: %s: %s",what,strerror(e));
210   disconnect(18);
211 }
212
213 /* Functions which may be called from signal handlers.  These
214  * may use signal-handler objects.  The main program may only
215  * call them with signals blocked, and they may not use any
216  * main-thread objects.
217  */
218
219 void ensurelogopen(int wantfacility) {
220   if (syslogopenfacility==wantfacility) return;
221   if (syslogopenfacility!=-1) closelog();
222   openlog(USERVD_LOGIDENT,LOG_NDELAY|LOG_PID,wantfacility);
223   syslogopenfacility= wantfacility;
224 }
225
226 void NONRETURNING disconnect(int exitstatus) {
227   /* This function can sometimes indirectly call itself (eg,
228    * xfwrite, syscallerror can cause it to be called).  So, all
229    * the global variables indicating need for action are reset
230    * before the action is taken so that if it fails it isn't
231    * attempted again.
232    */
233   struct progress_msg progress_mbuf;
234   FILE *swfilereal;
235   pid_t orgtokill;
236   int r;
237   
238   if (childtokill!=-1 && disconnecthup) {
239     orgtokill= childtokill;
240     childtokill= -1;
241     if (disconnecthup) {
242       r= kill(-orgtokill,SIGHUP);
243       if (r && errno!=EPERM && errno!=ESRCH)
244         syscallerror("sending SIGHUP to service process group");
245     }
246     child= -1;
247   }
248   if (swfile) {
249     swfilereal= swfile;
250     swfile= 0;
251     memset(&progress_mbuf,0,sizeof(progress_mbuf));
252     progress_mbuf.magic= PROGRESS_MAGIC;
253     progress_mbuf.type= pt_failed;
254     xfwrite(&progress_mbuf,sizeof(progress_mbuf),swfilereal);
255     xfflush(swfilereal);
256   }
257
258   _exit(exitstatus);
259 }
260
261 static void NONRETURNING sighandler_chld(int ignored) {
262   struct progress_msg progress_mbuf;
263   int status;
264   pid_t returned;
265
266   returned= wait3(&status,WNOHANG,0);
267   if (returned==-1) syscallerror("wait for child failed");
268   if (!returned) syscallerror("spurious sigchld");
269   if (returned!=child) syscallerror("spurious child process");
270   child= childtokill= -1;
271
272   memset(&progress_mbuf,0,sizeof(progress_mbuf));
273   progress_mbuf.magic= PROGRESS_MAGIC;
274   progress_mbuf.type= pt_terminated;
275   progress_mbuf.data.terminated.status= status;
276   xfwrite(&progress_mbuf,sizeof(progress_mbuf),swfile);
277   xfflush(swfile);
278
279   syslog(LOG_DEBUG,"service completed (status %d %d)",(status>>8)&0x0ff,status&0x0ff);
280   _exit(0);
281 }
282
283 /* Functions which are called only during setup, before
284  * the signal asynchronicity starts.  They can do anything they like.
285  */
286
287 void ensurefdarray(int fd) {
288   if (fd < fdarrayused) return;
289   if (fd >= fdarraysize) {
290     fdarraysize= ((fd+2)<<1);
291     fdarray= xrealloc(fdarray,sizeof(struct fdstate)*fdarraysize);
292   }
293   while (fd >= fdarrayused) {
294     fdarray[fdarrayused].iswrite= -1;
295     fdarray[fdarrayused].realfd= -1;
296     fdarray[fdarrayused].holdfd= -1;
297     fdarray[fdarrayused].wantstate= restfdwantstate;
298     fdarray[fdarrayused].wantrw= restfdwantrw;
299     fdarrayused++;
300   }
301 }
302
303 static void NONRETURNING generalfailure(const char *prefix, int reserveerrno,
304                                         int errnoval, const char *fmt, va_list al) {
305   char errmsg[MAX_ERRMSG_LEN];
306
307   if (prefix) {
308     strnycpy(errmsg,prefix,sizeof(errmsg));
309     strnytcat(errmsg,": ",sizeof(errmsg));
310   } else {
311     errmsg[0]= 0;
312   }
313   vsnytprintfcat(errmsg,sizeof(errmsg)-reserveerrno,fmt,al);
314   if (reserveerrno) {
315     strnytcat(errmsg,": ",sizeof(errmsg));
316     strnytcat(errmsg,strerror(errnoval),sizeof(errmsg));
317   }
318   senderrmsgstderr(errmsg);
319   syslog(LOG_DEBUG,"service failed (%s)",errmsg);
320   disconnect(12);
321 }
322
323 static void NONRETURNPRINTFFORMAT(1,2) failure(const char *fmt, ...) {
324   va_list al;
325
326   va_start(al,fmt);
327   generalfailure(0,0,0,fmt,al);
328 }  
329
330 static void NONRETURNPRINTFFORMAT(1,2) syscallfailure(const char *fmt, ...) {
331   va_list al;
332   int e;
333
334   e= errno;
335   va_start(al,fmt);
336   generalfailure("system call failed",ERRMSG_RESERVE_ERRNO,e,fmt,al);
337 }
338
339 void senderrmsgstderr(const char *errmsg) {
340   struct progress_msg progress_mbuf;
341   unsigned long ul;
342   int l;
343
344   l= strlen(errmsg);
345   memset(&progress_mbuf,0,sizeof(progress_mbuf));
346   progress_mbuf.magic= PROGRESS_MAGIC;
347   progress_mbuf.type= pt_errmsg;
348   progress_mbuf.data.errmsg.messagelen= l;
349   xfwrite(&progress_mbuf,sizeof(progress_mbuf),swfile);
350   xfwrite(errmsg,l,swfile);
351   ul= PROGRESS_ERRMSG_END_MAGIC;
352   xfwrite(&ul,sizeof(ul),swfile);
353   xfflush(swfile);
354 }
355
356 static void getgroupnames(int ngids, gid_t *list, const char ***names_r) {
357   const char **names;
358   struct group *cgrp;
359   int i;
360   
361   names= xmalloc(sizeof(char*)*ngids);
362   for (i=0; i<ngids; i++) {
363     cgrp= getgrgid(list[i]);
364     if (!cgrp) miscerror("get group entry");
365     names[i]= xstrsave(cgrp->gr_name);
366   }
367   *names_r= names;
368 }
369   
370 /* The per-request main program and its subfunctions. */
371
372 static void setup_comms(int sfd) {
373   static char swbuf[BUFSIZ];
374   static char srbuf[BUFSIZ];
375
376   struct sigaction sig;
377   
378   ensurelogopen(USERVD_LOGFACILITY);
379   syslog(LOG_DEBUG,"call connected");
380
381   mypid= getpid(); if (mypid == -1) syscallerror("getpid");
382
383   sig.sa_handler= SIG_IGN;
384   sigemptyset(&sig.sa_mask);
385   sig.sa_flags= 0;
386   if (sigaction(SIGPIPE,&sig,0)) syscallerror("cannot ignore sigpipe");
387
388   srfile= fdopen(sfd,"r");
389   if (!srfile) syscallerror("turn socket fd into reading FILE*");
390   if (setvbuf(srfile,srbuf,_IOFBF,sizeof(srbuf)))
391     syscallerror("set buffering on socket reads");
392
393   swfile= fdopen(sfd,"w");
394   if (!swfile) syscallerror("turn socket fd into writing FILE*");
395   if (setvbuf(swfile,swbuf,_IOFBF,sizeof(swbuf)))
396     syscallerror("set buffering on socket writes");
397 }
398
399 static void send_opening(void) {
400   struct opening_msg opening_mbuf;
401
402   memset(&opening_mbuf,0,sizeof(opening_mbuf));
403   opening_mbuf.magic= OPENING_MAGIC;
404   memcpy(opening_mbuf.protocolchecksumversion,protocolchecksumversion,PCSUMSIZE);
405   opening_mbuf.serverpid= mypid;
406   xfwrite(&opening_mbuf,sizeof(opening_mbuf),swfile);
407   xfflush(swfile);
408 }
409
410 static void receive_request(void) {
411   int i,j, fd;
412   unsigned long ul;
413
414   xfread(&request_mbuf,sizeof(request_mbuf));
415   serviceuser= xfreadsetstring(request_mbuf.serviceuserlen);
416   service= xfreadsetstring(request_mbuf.servicelen);
417   logname= xfreadsetstring(request_mbuf.lognamelen);
418   cwd= xfreadsetstring(request_mbuf.cwdlen);
419   if (request_mbuf.overridelen >= 0) {
420     assert(request_mbuf.overridelen <= MAX_OVERRIDE_LEN);
421     overridedata= xfreadsetstring(request_mbuf.overridelen);
422   } else {
423     assert(request_mbuf.overridelen == -1);
424     overridedata= 0;
425   }
426   assert(request_mbuf.ngids <= MAX_GIDS);
427   calling_gids= xmalloc(sizeof(gid_t)*request_mbuf.ngids);
428   xfread(calling_gids,sizeof(gid_t)*request_mbuf.ngids);
429
430   fdarraysize= 4; fdarray= xmalloc(sizeof(struct fdstate)*fdarraysize);
431   fdarrayused= 1; fdarray[0].iswrite= -1;
432   fdarray[0].wantstate= tokv_word_rejectfd;
433   assert(request_mbuf.nreadfds+request_mbuf.nwritefds <= MAX_ALLOW_FD+1);
434   for (i=0; i<request_mbuf.nreadfds+request_mbuf.nwritefds; i++) {
435     xfread(&fd,sizeof(int));
436     assert(fd <= MAX_ALLOW_FD);
437     ensurefdarray(fd);
438     assert(fdarray[fd].iswrite == -1);
439     fdarray[fd].iswrite= (i>=request_mbuf.nreadfds);
440   }
441
442   assert(request_mbuf.nargs <= MAX_ARGSDEFVARS);
443   argarray= xmalloc(sizeof(char*)*(request_mbuf.nargs));
444   for (i=0; i<request_mbuf.nargs; i++) argarray[i]= xfreadstring();
445   assert(request_mbuf.nvars <= MAX_ARGSDEFVARS);
446   defvararray= xmalloc(sizeof(char*)*request_mbuf.nvars*2);
447   for (i=0; i<request_mbuf.nvars; i++)
448     for (j=0; j<2; j++) defvararray[i][j]= xfreadstring();
449   xfread(&ul,sizeof(ul));
450   assert(ul == REQUEST_END_MAGIC);
451 }
452
453 static void establish_pipes(void) {
454   int fd, tempfd;
455   char pipepathbuf[PIPEMAXLEN];
456   
457   for (fd=0; fd<fdarrayused; fd++) {
458     if (fdarray[fd].iswrite == -1) continue;
459     snyprintf(pipepathbuf,sizeof(pipepathbuf), PIPEFORMAT,
460               (unsigned long)request_mbuf.clientpid,(unsigned long)mypid,fd);
461     tempfd= open(pipepathbuf,O_RDWR);
462     if (tempfd == -1) syscallerror("prelim open pipe");
463     if (!fdarray[fd].iswrite) {
464       fdarray[fd].holdfd= open(pipepathbuf, O_WRONLY);
465       if (fdarray[fd].holdfd == -1) syscallerror("hold open pipe");
466       fdarray[fd].realfd= open(pipepathbuf, O_RDONLY);
467     } else {
468       fdarray[fd].holdfd= -1;
469       fdarray[fd].realfd= open(pipepathbuf, O_WRONLY);
470     }
471     if (fdarray[fd].realfd == -1) syscallerror("real open pipe");
472     if (unlink(pipepathbuf)) syscallerror("unlink pipe");
473     if (close(tempfd)) syscallerror("close prelim fd onto pipe");
474   }
475 }
476
477 static void lookup_uidsgids(void) {
478   struct passwd *pw;
479
480   pw= getpwnam(logname);
481   if (!pw) miscerror("look up calling user");
482   assert(!strcmp(pw->pw_name,logname));
483   callinguser_shell= xstrsave(pw->pw_shell);
484
485   pw= getpwnam(serviceuser);
486   if (!pw) miscerror("look up service user");
487   assert(!strcmp(pw->pw_name,serviceuser));
488   serviceuser_dir= xstrsave(nondebug_serviceuserdir(pw->pw_dir));
489   serviceuser_shell= xstrsave(pw->pw_shell);
490   serviceuser_uid= pw->pw_uid;
491   if (initgroups(pw->pw_name,pw->pw_gid)) syscallerror("initgroups");
492   if (setreuid(pw->pw_uid,pw->pw_uid)) syscallerror("setreuid 1");
493   if (setreuid(pw->pw_uid,pw->pw_uid)) syscallerror("setreuid 2");
494   if (pw->pw_uid)
495     if (!setreuid(pw->pw_uid,0)) miscerror("setreuid 3 unexpectedly succeeded");
496   if (errno != EPERM) syscallerror("setreuid 3 failed in unexpected way");
497
498   service_ngids= getgroups(0,0); if (service_ngids == -1) syscallerror("getgroups(0,0)");
499   if (service_ngids > MAX_GIDS) miscerror("service user is in far too many groups");
500   service_gids= xmalloc(sizeof(gid_t)*(service_ngids+1));
501   service_gids[0]= pw->pw_gid;
502   if (getgroups(service_ngids,service_gids+1) != service_ngids)
503     syscallerror("getgroups(size,list)");
504
505   getgroupnames(service_ngids,service_gids,&service_groups);
506   getgroupnames(request_mbuf.ngids,calling_gids,&calling_groups);
507 }
508
509 static void check_find_executable(void) {
510   int r, partsize;
511   char *part, *exectry;
512   const char *string, *delim, *nextstring;
513   struct stat stab;
514
515   switch (execute) {
516   case tokv_word_reject:
517     failure("request rejected");
518   case tokv_word_execute:
519     r= stat(execpath,&stab);
520     if (r) syscallfailure("checking for executable `%s'",execpath);
521     break;
522   case tokv_word_executefromdirectory:
523     r= stat(execpath,&stab);
524     if (r) syscallfailure("checking for executable in directory, `%s'",execpath);
525     break;
526   case tokv_word_executefrompath:
527     if (strchr(service,'/')) {
528       r= stat(service,&stab);
529       if (r) syscallfailure("execute-from-path (contains slash)"
530                             " cannot check for executable `%s'",service);
531       execpath= service;
532     } else {
533       string= getenv("PATH");
534       if (!string) failure("execute-from-path, but daemon inherited no PATH !");
535       while (string) {
536         delim= strchr(string,':');
537         if (delim) {
538           if (delim-string > INT_MAX)
539             failure("execute-from-path, but PATH component too long");
540           partsize= delim-string;
541           nextstring= delim+1;
542         } else {
543           partsize= strlen(string);
544           nextstring= 0;
545         }
546         part= xstrsubsave(string,partsize);
547         exectry= part[0] ? xstrcat3save(part,"/",service) : xstrsave(service);
548         free(part);
549         r= stat(exectry,&stab);
550         if (!r) { execpath= exectry; break; }
551         free(exectry);
552         string= nextstring;
553       }
554       if (!execpath) failure("execute-from-path, but program `%s' not found",service);
555     }
556     break;
557   default:
558     abort();
559   }
560 }
561
562 static void check_fds(void) {
563   int fd;
564   
565   assert(fdarrayused>=2);
566   if (!(fdarray[2].wantstate == tokv_word_requirefd ||
567         fdarray[2].wantstate == tokv_word_allowfd) ||
568       fdarray[2].wantrw != tokv_word_write)
569     failure("must have stderr (fd 2), but file descriptor setup in "
570             "configuration does not have it or not for writing");
571
572   for (fd=0; fd<fdarrayused; fd++) {
573     switch (fdarray[fd].wantstate) {
574     case tokv_word_rejectfd:
575       if (fdarray[fd].realfd != -1)
576         failure("file descriptor %d provided but rejected",fd);
577       break;
578     case tokv_word_ignorefd:
579       if (fdarray[fd].realfd != -1)
580         if (close(fdarray[fd].realfd))
581           syscallfailure("close unwanted file descriptor %d",fd);
582       fdarray[fd].realfd= -1;
583       break;
584     case tokv_word_nullfd:
585       if (fdarray[fd].realfd != -1) close(fdarray[fd].realfd);
586       fdarray[fd].realfd= open("/dev/null",
587                                fdarray[fd].iswrite == -1 ? O_RDWR :
588                                fdarray[fd].iswrite ? O_WRONLY : O_RDONLY);
589       if (fdarray[fd].realfd == -1)
590         syscallfailure("cannot open /dev/null for null fd");
591       break;
592     case tokv_word_requirefd:
593       if (fdarray[fd].realfd == -1)
594         failure("file descriptor %d not provided but required",fd);
595       /* fall through */
596     case tokv_word_allowfd:
597       if (fdarray[fd].realfd == -1) {
598         fdarray[fd].iswrite= (fdarray[fd].wantrw == tokv_word_write);
599         fdarray[fd].realfd= open("/dev/null",fdarray[fd].iswrite ? O_WRONLY : O_RDONLY);
600         if (fdarray[fd].realfd == -1)
601           syscallfailure("cannot open /dev/null for allowed but not provided fd");
602       } else {
603         if (fdarray[fd].iswrite) {
604           if (fdarray[fd].wantrw != tokv_word_write)
605             failure("file descriptor %d provided write, wanted read",fd);
606         } else {
607           if (fdarray[fd].wantrw != tokv_word_read)
608             failure("file descriptor %d provided read, wanted write",fd);
609         }
610       }
611     }
612   }
613 }
614
615 static void send_progress_ok(void) {
616   struct progress_msg progress_mbuf;
617
618   memset(&progress_mbuf,0,sizeof(progress_mbuf));
619   progress_mbuf.magic= PROGRESS_MAGIC;
620   progress_mbuf.type= pt_ok;
621   xfwrite(&progress_mbuf,sizeof(progress_mbuf),swfile);
622   xfflush(swfile);
623 }
624
625 static void fork_service_synch(void) {
626   pid_t newchild;
627   struct sigaction sig;
628   int r, synchsocket[2];
629   char synchmsg;
630
631   r= socketpair(AF_UNIX,SOCK_STREAM,0,synchsocket);
632   if (r) syscallerror("cannot create socket for synch");
633
634   sig.sa_handler= sighandler_chld;
635   sigemptyset(&sig.sa_mask);
636   sigaddset(&sig.sa_mask,SIGCHLD);
637   sig.sa_flags= 0;
638   if (sigaction(SIGCHLD,&sig,0)) syscallerror("cannot set sigchld handler");
639
640   newchild= fork();
641   if (newchild == -1) syscallerror("cannot fork to invoke service");
642   if (!newchild) execservice(synchsocket,fileno(swfile));
643   childtokill= child= newchild;
644
645   if (close(synchsocket[1])) syscallerror("cannot close other end of synch socket");
646
647   r= synchread(synchsocket[0],'y');
648   if (r) syscallerror("read synch byte from child");
649
650   childtokill= -child;
651
652   synchmsg= 'g';
653   r= write(synchsocket[0],&synchmsg,1);
654   if (r!=1) syscallerror("write synch byte to child");
655
656   if (close(synchsocket[0])) syscallerror("cannot close my end of synch socket");
657 }
658
659 void servicerequest(int sfd) {
660   struct event_msg event_mbuf;
661   int r;
662
663   setup_comms(sfd);
664   send_opening();
665   receive_request();
666   establish_pipes();
667   lookup_uidsgids();
668   debug_dumprequest(mypid);
669
670   if (overridedata)
671     r= parse_string(TOPLEVEL_OVERRIDDEN_CONFIGURATION,
672                     "<builtin toplevel override configuration>",1);
673   else
674     r= parse_string(TOPLEVEL_CONFIGURATION,
675                     "<builtin toplevel configuration>",1);
676   
677   ensurelogopen(USERVD_LOGFACILITY);
678   if (r == tokv_error) failure("error encountered while parsing configuration files");
679   assert(r == tokv_quit);
680
681   debug_dumpexecsettings();
682
683   check_find_executable();
684   check_fds();
685   send_progress_ok();
686
687   getevent(&event_mbuf);
688   assert(event_mbuf.type == et_confirm);
689
690   fork_service_synch();
691   
692   getevent(&event_mbuf);
693   abort();
694 }