3 * daemon main program, collects request and forks handlers
5 * Copyright (C)1996-1997,1999 Ian Jackson
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.
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.
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.
31 #include <sys/types.h>
33 #include <sys/socket.h>
45 static pid_t checkpid= -1, detachpid= -1;
46 static sig_atomic_t needcheck= 1; /* 2 means we half-expect the server to be down */
48 static void checkstalepipes(void) {
49 /* There is an unimportant race here. If there is a stale pipe but
50 * another pair of processes with the same pids is about to create a
51 * new one we can check that the pipe is stale before they recreate
52 * it but then only remove it afterwards; then we remove the pipe
53 * they're actually using causing that invocation to fail with
54 * ENOENT on the pipe. However, this can only happen if things are
55 * already shafted, because we check for stale pipes at startup
56 * before any children have been started, and then only when a child
57 * dies unhelpfully - and we actually have to have some stale pipes
58 * for the race to exist.
64 unsigned long timediff;
67 if (time(&now) == -1) { syslog(LOG_ERR,"get current time: %m"); return; }
69 if (!dir) { syslog(LOG_ERR,"open directory " VARDIR ": %m"); return; }
70 while ((de= readdir(dir))) {
71 if (fnmatch(PIPEPATTERN,de->d_name,FNM_PATHNAME|FNM_PERIOD)) continue;
72 r= lstat(de->d_name,&stab); if (r && errno==ENOENT) continue;
73 if (r) { syslog(LOG_ERR,"could not stat `" VARDIR "/%s': %m",de->d_name); continue; }
74 timediff= (unsigned long)now - (unsigned long)stab.st_ctime;
75 if (timediff >= (~0UL>>1) || timediff < 3600) continue;
76 if (unlink(de->d_name) && errno!=ENOENT)
77 syslog(LOG_ERR,"could not remove stale pipe `%s': %m",de->d_name);
79 if (closedir(dir)) syslog(LOG_ERR,"close directory " VARDIR ": %m");
82 static void sighandler_chld(int x) {
88 r= waitpid((pid_t)-1,&status,WNOHANG);
89 if (!r || (r==-1 && errno==ECHILD)) break;
90 if (r==-1) { syslog(LOG_ERR,"wait in sigchild handler gave error: %m"); break; }
92 if (WIFEXITED(status) && WEXITSTATUS(status)==4) _exit(4);
93 fprintf(stderr,"uservd: detaching child failed with unexpected code %d\n",status);
97 if (WIFEXITED(status)) {
98 if (!WEXITSTATUS(status)) {
99 syslog(LOG_WARNING,"no longer the uservd - exiting");
101 } else if (WEXITSTATUS(status)!=1) {
102 syslog(LOG_ERR,"check pid %ld exited with status %d",
103 (long)checkpid,WEXITSTATUS(status));
105 } else if (WIFSIGNALED(status)) {
106 if (WTERMSIG(status) == SIGALRM && !WCOREDUMP(status)) {
107 syslog(LOG_WARNING,"check timed out; no longer the uservd - exiting");
110 syslog(LOG_ERR,"check pid %ld %s due to signal %s",
112 WCOREDUMP(status) ? "dumped core" : "died",
113 strsignal(WTERMSIG(status)));
116 syslog(LOG_ERR,"check pid %ld died due to unknown reason, code %d",
117 (long)checkpid,status);
120 ar= alarm(USERVD_MYSELF_CHECK);
121 if (ar<0) { syslog(LOG_CRIT,"set alarm for next check: %m"); exit(5); }
123 if (WIFSIGNALED(status)) {
124 syslog(LOG_ERR,"call pid %ld %s due to signal %s",
126 WCOREDUMP(status) ? "dumped core" : "died",
127 strsignal(WTERMSIG(status)));
128 } else if (!WIFEXITED(status)) {
129 syslog(LOG_ERR,"call pid %ld died due to unknown reason, code %d",
131 } else if (WEXITSTATUS(status)==10) {
133 } else if (WEXITSTATUS(status)>12) {
134 if (WEXITSTATUS(status)>24)
135 syslog(LOG_ERR,"call pid %ld exited with status %d >24",
136 (long)r,WEXITSTATUS(status));
146 static void sighandler_usr1(int x) {
150 static void sighandler_alrm(int x) {
154 static void sighandler_termint(int sig) {
155 syslog(LOG_NOTICE,"terminating due to signal %s",strsignal(sig));
159 static void blocksignals(int how) {
164 sigaddset(&set,SIGCHLD);
165 sigaddset(&set,SIGALRM);
166 sigaddset(&set,SIGTERM);
167 sigaddset(&set,SIGINT);
168 r= sigprocmask(how,&set,0); assert(!r);
171 static void NONRETURNING docheck(int needwanted) {
173 /* This subprocess exits with status 0 if the parent should die,
174 * 1 if it should not, and something else if it fails horribly.
178 struct opening_msg opening_mbuf;
179 struct request_msg request_mbuf;
180 unsigned long endmagic;
181 struct sigaction sig;
182 struct sockaddr_un ssockname;
184 openlog(USERVDCHECK_LOGIDENT,LOG_NDELAY|LOG_PID,USERVD_LOGFACILITY);
186 sigemptyset(&sig.sa_mask);
188 sig.sa_handler= SIG_IGN;
189 if (sigaction(SIGPIPE,&sig,0)) { syslog(LOG_ERR,"ignore sigpipe"); exit(1); }
191 sig.sa_handler= SIG_DFL;
192 if (sigaction(SIGALRM,&sig,0)) { syslog(LOG_ERR,"default sigalarm"); exit(1); }
194 sfd= socket(AF_UNIX,SOCK_STREAM,0);
195 if (!sfd) { syslog(LOG_ERR,"ignore sigpipe"); exit(1); }
197 assert(sizeof(ssockname.sun_path) > sizeof(RENDEZVOUS));
198 ssockname.sun_family= AF_UNIX;
199 strcpy(ssockname.sun_path,RENDEZVOUS);
201 r= connect(sfd,(struct sockaddr*)&ssockname,sizeof(ssockname));
203 if (errno == ECONNREFUSED || errno == ENOENT) {
205 syslog(LOG_WARNING,"real uservd daemon is not running: %m");
208 syslog(LOG_ERR,"unable to connect to uservd daemon: %m"); exit(1);
211 r= alarm(USERVD_MYSELF_TIMEOUT);
212 if (r<0) { syslog(LOG_ERR,"set alarm for read: %m"); exit(1); }
213 remain= sizeof(opening_mbuf); p= (unsigned char*)&opening_mbuf;
215 r= read(sfd,p,remain);
216 if (r<0) { syslog(LOG_ERR,"read from server: %m"); exit(1); }
217 if (r==0) { syslog(LOG_ERR,"unexpected EOF from server"); exit(1); }
220 if (opening_mbuf.magic != OPENING_MAGIC) {
221 syslog(LOG_WARNING,"magic number mismatch");
224 if (memcmp(opening_mbuf.protocolchecksumversion,protocolchecksumversion,PCSUMSIZE)) {
225 syslog(LOG_WARNING,"protocol checksum mismatch");
228 if (opening_mbuf.overlordpid != overlordpid) {
229 syslog(LOG_WARNING,"overlord pid mismatch");
232 memset(&request_mbuf,0,sizeof(request_mbuf));
233 request_mbuf.magic= REQUEST_MAGIC;
234 request_mbuf.clientpid= -1;
235 request_mbuf.serviceuserlen= 0;
236 request_mbuf.servicelen= 0;
237 request_mbuf.loginnamelen= 0;
238 request_mbuf.spoofed= 0;
239 request_mbuf.cwdlen= 0;
240 request_mbuf.overridelen= -1;
241 request_mbuf.callinguid= -1;
242 request_mbuf.ngids= 0;
243 request_mbuf.nreadfds= 0;
244 request_mbuf.nwritefds= 0;
245 request_mbuf.nargs= 0;
246 request_mbuf.nvars= 0;
247 r= write(sfd,&request_mbuf,sizeof(request_mbuf));
248 if (r==sizeof(request_mbuf)) {
249 endmagic= REQUEST_END_MAGIC;
250 write(sfd,&endmagic,sizeof(endmagic));
252 syslog(LOG_NOTICE,"uservd[%ld] is running",(long)overlordpid);
257 static void NONRETURNING startupsyscallerr(const char *what) {
259 "uservd: system call failed during startup:\n"
261 what,strerror(errno));
265 int main(int argc, char *const *argv) {
266 int mfd, sfd, nfd, csocklen, e, r, becomedaemon;
267 struct sigaction sigact;
268 struct sockaddr_un ssockname, csockname;
269 pid_t child, parentpid, sid;
272 abort(); /* Do not disable assertions in this security-critical code ! */
277 if (argv[1] && !strcmp(argv[1],"-daemon")) {
281 if (argc>1) { fputs("usage: uservd [-daemon]\n",stderr); exit(3); }
283 openlog(USERVD_LOGIDENT,LOG_NDELAY|LOG_PID,USERVD_LOGFACILITY);
285 if (chdir(VARDIR)) startupsyscallerr("cannot change to " VARDIR);
288 overlordpid= parentpid= getpid();
289 if (parentpid==-1) startupsyscallerr("cannot getpid");
291 mfd= socket(AF_UNIX,SOCK_STREAM,0);
292 if (mfd<0) startupsyscallerr("cannot create master socket");
294 assert(sizeof(ssockname.sun_path) > sizeof(RENDEZVOUS));
295 ssockname.sun_family= AF_UNIX;
296 strcpy(ssockname.sun_path,RENDEZVOUS);
298 r= bind(mfd,(struct sockaddr*)&ssockname,sizeof(ssockname));
299 if (r) startupsyscallerr("cannot bind master socket");
300 if (listen(mfd,5)) startupsyscallerr("cannot listen on master socket");
302 sigemptyset(&sigact.sa_mask);
303 sigaddset(&sigact.sa_mask,SIGCHLD);
304 sigaddset(&sigact.sa_mask,SIGALRM);
305 sigact.sa_flags= SA_NOCLDSTOP;
307 sigact.sa_handler= sighandler_chld;
308 if (sigaction(SIGCHLD,&sigact,0)) startupsyscallerr("cannot setup sigchld handler");
310 sigact.sa_handler= sighandler_alrm;
311 if (sigaction(SIGALRM,&sigact,0)) startupsyscallerr("cannot setup sigalrm handler");
314 sigact.sa_handler= sighandler_usr1;
315 if (sigaction(SIGUSR1,&sigact,0)) startupsyscallerr("cannot setup sigusr1 handler");
317 detachpid= fork(); if (detachpid==-1) startupsyscallerr("cannot fork to detach");
320 fputs("uservd: pause unexpectedly returned during detach\n",stderr);
323 sigact.sa_handler= SIG_DFL;
324 if (sigaction(SIGUSR1,&sigact,0)) startupsyscallerr("cannot restore sigusr1");
327 sigact.sa_handler= sighandler_termint;
328 if (sigaction(SIGTERM,&sigact,0)) startupsyscallerr("cannot setup sigterm handler");
329 if (sigaction(SIGINT,&sigact,0)) startupsyscallerr("cannot setup sigint handler");
332 nfd= open("/dev/null",O_RDWR);
333 if (nfd<0) startupsyscallerr("cannot open /dev/null");
334 sid= setsid(); if (sid == -1) startupsyscallerr("cannot create new session");
335 overlordpid= getpid();
336 if (overlordpid == -1) startupsyscallerr("getpid after detach");
337 if (dup2(nfd,0)<0 || dup2(nfd,1)<0)
338 startupsyscallerr("cannot dup /dev/null for stdin/out");
339 r= kill(parentpid,SIGUSR1); if (r) startupsyscallerr("send SIGUSR1 to detach");
341 if (r<0) { syslog(LOG_CRIT,"cannot dup /dev/null for stderr: %m"); exit(5); }
345 syslog(LOG_NOTICE,"started");
349 while (checkpid==-1) {
352 if (!checkpid) docheck(needcheck);
354 } else if (errno==EAGAIN) {
355 syslog(LOG_ERR,"fork for check - will wait and retry: %m");
356 r= alarm(USERVD_CHECKFORK_RETRY);
357 if (r<0) { syslog(LOG_CRIT,"set alarm for retry check: %m"); exit(5); }
359 } else if (errno!=EINTR) {
360 syslog(LOG_CRIT,"fork for check: %m"); exit(5);
365 csocklen= sizeof(csockname);
366 blocksignals(SIG_UNBLOCK);
367 sfd= accept(mfd,(struct sockaddr*)&csockname,&csocklen);
369 blocksignals(SIG_BLOCK);
372 if (errno == EINTR) continue;
373 if (errno == ENOMEM || errno == EPROTO || errno == EAGAIN) {
374 syslog(LOG_ERR,"unable to accept connection: %m");
377 syslog(LOG_CRIT,"unable to accept new connections: %m");
381 child= nondebug_fork();
382 if (child == (pid_t)-1) {
383 syslog(LOG_ERR,"unable to fork server: %m");
390 blocksignals(SIG_UNBLOCK);