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