1 /*! \file owampd.c */
2 /*
3  *      $Id: owampd.c 1045 2009-01-20 13:01:46Z aaron $
4  */
5 /************************************************************************
6  *                                                                      *
7  *                             Copyright (C)  2002                      *
8  *                                Internet2                             *
9  *                             All Rights Reserved                      *
10  *                                                                      *
11  ************************************************************************/
12 /*
13  *        File:         owampd.c
14  *
15  *        Author:       Anatoly Karp
16  *                      Jeff W. Boote
17  *                      Internet2
18  *
19  *        Date:         Mon Jun 03 10:57:07 MDT 2002
20  *
21  *        Description:
22  */
23 #include <owamp/owamp.h>
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <ctype.h>
28 #include <assert.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <sys/wait.h>
34 #include <sys/socket.h>
35 #include <sys/time.h>
36 #include <unistd.h>
37 #include <signal.h>
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <pwd.h>
41 #include <grp.h>
42 #include <syslog.h>
43 
44 #include "owampdP.h"
45 #include "policy.h"
46 
47 /* Global variable - the total number of allowed Control connections. */
48 static pid_t                mypid;
49 static int                  owpd_chld = 0;
50 static int                  owpd_int = 0;
51 static int                  owpd_exit = 0;
52 static int                  owpd_alrm = 0;
53 static int                  owpd_intr = 0;
54 static owampd_opts          opts;
55 static OWPPortRangeRec      portrec;
56 static I2ErrLogSyslogAttr   syslogattr;
57 static I2ErrHandle          errhand=NULL;
58 static I2Table              fdtable=NULL;
59 static I2Table              pidtable=NULL;
60 static OWPNum64             uptime;
61 
62 #if defined HAVE_DECL_OPTRESET && !HAVE_DECL_OPTRESET
63 int optreset;
64 #endif
65 
66 static void
usage(const char * progname,const char * msg)67 usage(
68         const char *progname,
69         const char *msg        __attribute__((unused))
70      )
71 {
72     fprintf(stderr, "Usage: %s [options]\n", progname);
73     fprintf(stderr, "\nWhere \"options\" are:\n\n");
74 
75     fprintf(stderr,
76             "   -a authmode       Default supported authmodes:[E]ncrypted,[A]uthenticated,[O]pen\n"
77             "   -c confidr        Configuration directory\n"
78             "   -d datadir        Data directory\n"
79             "   -e facility       Syslog \"facility\" to log errors\n"
80             "   -f                Allow owampd to run as root\n"
81             "   -G group          Run as group \"group\" :-gid also valid\n"
82             "   -h                Print this message and exit\n"
83            );
84     fprintf(stderr,
85             "   -P portrange      port range for recivers to use\n"
86             "   -R vardir         directory for owampd.pid file\n"
87             "   -S nodename:port  Srcaddr to bind to\n"
88             "   -U user           Run as user \"user\" :-uid also valid\n"
89             "   -v                verbose output\n"
90 #ifndef        NDEBUG
91             "   -w                Debugging: busy-wait children after fork to allow attachment\n"
92             "   -Z                Debugging: Run in foreground\n"
93 #endif
94             "\n"
95            );
96     fprintf(stderr, "Distribution: %s\n", PACKAGE_STRING);
97     return;
98 }
99 
100 /*
101  ** Handler function for SIG_CHLD. It updates the number
102  ** of available Control connections.
103  */
104 static void
signal_catch(int signo)105 signal_catch(
106         int        signo
107         )
108 {
109     switch(signo){
110         case SIGINT:
111             owpd_int = 1;
112             /* fallthru*/
113         case SIGTERM:
114         case SIGHUP:
115         case SIGUSR1:
116         case SIGUSR2:
117             if(!owpd_exit){
118                 owpd_exit = 1;
119             }
120             break;
121         case SIGCHLD:
122             owpd_chld = 1;
123             break;
124         case SIGALRM:
125             owpd_alrm = 1;
126             break;
127         default:
128             I2ErrLog(errhand,"signal_catch(): Invalid signal(%d)",
129                     signo);
130             _exit(OWP_CNTRL_FAILURE);
131     }
132 
133     owpd_intr = 1;
134 
135     return;
136 }
137 
138 struct ChldStateRec{
139     OWPDPolicy      policy;
140     pid_t           pid;
141     int             fd;
142     OWPDPolicyNode  node;
143     OWPDLimRec      used[2];    /* disk/bandwidth */
144 };
145 
146 typedef struct ChldStateRec ChldStateRec, *ChldState;
147 
148 static ChldState
AllocChldState(OWPDPolicy policy,pid_t pid,int fd)149 AllocChldState(
150         OWPDPolicy  policy,
151         pid_t       pid,
152         int         fd
153         )
154 {
155     ChldState   cstate = calloc(1,sizeof(*cstate));
156     I2Datum     k,v;
157 
158     if(!cstate){
159         OWPError(policy->ctx,OWPErrFATAL,ENOMEM,"malloc(): %M");
160         return NULL;
161     }
162 
163     cstate->policy = policy;
164     cstate->pid = pid;
165     cstate->fd = fd;
166 
167     /*
168      * Add cstate into the hash's.
169      */
170     v.dptr = (void*)cstate;
171     v.dsize = sizeof(*cstate);
172 
173     /*
174      * add cstate to the pidtable hash
175      */
176     k.dptr = NULL;
177     k.dsize = pid;
178     if(I2HashStore(pidtable,k,v) != 0){
179         free(cstate);
180         return NULL;
181     }
182 
183     /*
184      * add cstate to the fdtable hash
185      */
186     k.dsize = fd;
187     if(I2HashStore(fdtable,k,v) != 0){
188         k.dsize = pid;
189         I2HashDelete(pidtable,k);
190         free(cstate);
191         return NULL;
192     }
193 
194     return cstate;
195 }
196 
197 static void
FreeChldState(ChldState cstate,fd_set * readfds)198 FreeChldState(
199         ChldState   cstate,
200         fd_set      *readfds
201         )
202 {
203     I2Datum k;
204 
205     k.dptr = NULL;
206 
207     if(cstate->fd >= 0){
208 
209         while((close(cstate->fd) < 0) && (errno == EINTR));
210         FD_CLR(cstate->fd, readfds);
211 
212         k.dsize = cstate->fd;
213         if(I2HashDelete(fdtable,k) != 0){
214             OWPError(cstate->policy->ctx,OWPErrWARNING,
215                     OWPErrUNKNOWN,
216                     "fd(%d) not in fdtable!?!",cstate->fd);
217         }
218     }
219 
220     k.dsize = cstate->pid;
221     if(I2HashDelete(pidtable,k) != 0){
222         OWPError(cstate->policy->ctx,OWPErrWARNING,OWPErrUNKNOWN,
223                 "pid(%d) not in pidtable!?!",cstate->pid);
224     }
225 
226     /*
227      * TODO: Release bandwidth resources here if there are any left.
228      */
229 
230 
231     /*
232      * TODO: If exit was not normal... Should we be looking at
233      * disk usage for this class and adjusting for the fact that
234      * the file was not completely saved?
235      */
236     free(cstate);
237 
238     return;
239 }
240 
241 static void
ReapChildren(int * maxfd,fd_set * readfds)242 ReapChildren(
243         int     *maxfd,
244         fd_set  *readfds
245         )
246 {
247     int         status;
248     pid_t       child;
249     I2Datum     key;
250     I2Datum     val;
251     ChldState   cstate;
252 
253     if(!owpd_chld)
254         return;
255 
256     key.dptr = NULL;
257     while ( (child = waitpid(-1, &status, WNOHANG)) > 0){
258         key.dsize = child;
259         if(!I2HashFetch(pidtable,key,&val)){
260             OWPError(cstate->policy->ctx,OWPErrWARNING,
261                     OWPErrUNKNOWN,
262                     "pid(%d) not in pidtable!?!",child);
263         }
264         cstate = val.dptr;
265 
266         /*
267          * Let main loop know maxfd needs to be recomputed.
268          */
269         if(cstate->fd == *maxfd)
270             *maxfd = -1;
271 
272         FreeChldState(cstate,readfds);
273     }
274 
275 
276     owpd_chld = 0;
277 }
278 
279 struct CleanPipeArgRec{
280     int     *maxfd;
281     fd_set  *avail;
282     fd_set  *readfds;
283     int     nready;
284 };
285 
286 static I2Boolean
CheckFD(I2Datum fdkey,I2Datum fdval,void * app_data)287 CheckFD(
288         I2Datum fdkey       __attribute__((unused)),
289         I2Datum fdval,
290         void    *app_data
291        )
292 {
293     struct CleanPipeArgRec  *arg = (struct CleanPipeArgRec *)app_data;
294     ChldState               cstate = fdval.dptr;
295     int                     err=1;
296 
297     /*
298      * If this fd is not ready, return.
299      */
300     if(!FD_ISSET(cstate->fd,arg->avail))
301         return True;
302 
303     /*
304      * This fd needs processing - reduce the "ready" count.
305      */
306     arg->nready--;
307 
308     /*
309      * child initialization - first message.
310      * Get classname and find policy node for that class.
311      */
312     if(!cstate->node){
313         cstate->node = OWPDReadClass(cstate->policy,cstate->fd,&err);
314     }
315     else{
316         OWPDMesgT        query;
317         OWPDMesgT        resp;
318         OWPDLimRec        lim;
319 
320         /* read child request for resources */
321         if(!OWPDReadQuery(cstate->fd,&query,&lim,&err)){
322             goto done;
323         }
324 
325         /*
326          * parse tree for resource request/release
327          */
328         resp = OWPDResourceDemand(cstate->node,query,lim) ?
329             OWPDMESGOK : OWPDMESGDENIED;
330 
331         /*
332          * Send response
333          */
334         err = OWPDSendResponse(cstate->fd,resp);
335     }
336 
337 done:
338     if(err){
339         OWPError(cstate->policy->ctx,OWPErrWARNING,OWPErrUNKNOWN,
340                 "Invalid message from child pid=%d",cstate->pid);
341         (void)kill(cstate->pid,SIGTERM);
342     }
343 
344     /*
345      * Return true if there are more fd's to process.
346      */
347     return (arg->nready > 0);
348 }
349 
350 /*
351  * avail contains the fd_set of fd's that are currently readable, readfds is
352  * the set of all fd's that the server needs to pay attention to.
353  * maxfd is the largest of those.
354  */
355 static void
CleanPipes(fd_set * avail,int * maxfd,fd_set * readfds,int nready)356 CleanPipes(
357         fd_set  *avail,
358         int     *maxfd,
359         fd_set  *readfds,
360         int     nready
361         )
362 {
363     struct CleanPipeArgRec  cpargs;
364 
365     cpargs.avail = avail;
366     cpargs.maxfd = maxfd;
367     cpargs.readfds = readfds;
368     cpargs.nready = nready;
369 
370     I2HashIterate(fdtable,CheckFD,&cpargs);
371 
372     return;
373 }
374 
375 static I2Boolean
ClosePipes(I2Datum key,I2Datum value,void * app_data)376 ClosePipes(
377         I2Datum key,
378         I2Datum value,
379         void    *app_data
380         )
381 {
382     ChldState   cstate = value.dptr;
383     int         sd = 0;
384 
385     if(app_data){
386         sd = *(int *)app_data;
387     }
388 
389     /*
390      * shutdown the socket if terminating so child processes will
391      * not wait for responses when releasing resources.
392      */
393     if(sd){
394         if( (shutdown(cstate->fd,SHUT_RDWR) != 0)){
395             OWPError(cstate->policy->ctx,OWPErrWARNING,OWPErrUNKNOWN,
396                     "shutdown(%d,SHUT_RDWR): %M", cstate->fd);
397         }
398     }
399 
400     while((close(cstate->fd) < 0) && (errno == EINTR));
401     if(I2HashDelete(fdtable,key) != 0){
402         OWPError(cstate->policy->ctx,OWPErrWARNING,OWPErrUNKNOWN,
403                 "fd(%d) not in fdtable!?!",cstate->fd);
404     }
405     cstate->fd = -1;
406 
407     return True;
408 }
409 
410 
411 /*
412  * This function needs to create a new child process with a pipe to
413  * communicate with it. It needs to add the new pipefd into the readfds,
414  * and update maxfd if the new pipefd is greater than the current max.
415  */
416 static void
NewConnection(OWPDPolicy policy,I2Addr listenaddr,int * maxfd,fd_set * readfds)417 NewConnection(
418         OWPDPolicy  policy,
419         I2Addr      listenaddr,
420         int         *maxfd,
421         fd_set      *readfds
422         )
423 {
424     int                     connfd;
425     struct sockaddr_storage sbuff;
426     socklen_t               sbufflen;
427     int                     new_pipe[2];
428     pid_t                   pid;
429     OWPSessionMode          mode = opts.auth_mode;
430     int                     listenfd = I2AddrFD(listenaddr);
431     OWPControl              cntrl=NULL;
432     OWPErrSeverity          out;
433     struct itimerval        itval;
434     OWPRequestType          msgtype=OWPReqInvalid;
435 
436 ACCEPT:
437     sbufflen = sizeof(sbuff);
438     connfd = accept(listenfd, (struct sockaddr *)&sbuff, &sbufflen);
439     if (connfd < 0){
440         switch(errno){
441             case EINTR:
442                 /*
443                  * Exit signal received, no reason to do more.
444                  */
445                 if(owpd_exit){
446                     return;
447                 }
448 
449                 /*
450                  * Go ahead and reap before re-entering
451                  * accept since it could make more free
452                  * connections.
453                  */
454                 ReapChildren(maxfd,readfds);
455                 goto ACCEPT;
456                 break;
457             case ECONNABORTED:
458                 return;
459                 break;
460             default:
461                 OWPError(policy->ctx,OWPErrFATAL,OWPErrUNKNOWN,
462                         "accept(): %M");
463                 return;
464                 break;
465         }
466     }
467 
468     if (socketpair(AF_UNIX,SOCK_STREAM,0,new_pipe) < 0){
469         OWPError(policy->ctx,OWPErrFATAL,OWPErrUNKNOWN,"socketpair(): %M");
470         (void)close(connfd);
471         return;
472     }
473 
474     pid = fork();
475 
476     /* fork error */
477     if (pid < 0){
478         OWPError(policy->ctx,OWPErrFATAL,OWPErrUNKNOWN,"fork(): %M");
479         (void)close(new_pipe[0]);
480         (void)close(new_pipe[1]);
481         (void)close(connfd);
482         return;
483     }
484 
485     /* Parent */
486     if (pid > 0){
487         ChldState   chld;
488 
489 
490         /*
491          * If close is interupted, continue to try and close,
492          * otherwise, ignore the error.
493          */
494         while((close(new_pipe[1]) < 0) && (errno == EINTR));
495         while((close(connfd) < 0) && (errno == EINTR));
496 
497         if(!(chld = AllocChldState(policy,pid,new_pipe[0]))){
498             (void)close(new_pipe[0]);
499             (void)kill(pid,SIGKILL);
500             return;
501         }
502 
503         FD_SET(chld->fd, readfds);
504         if((*maxfd > -1) && (chld->fd > *maxfd))
505             *maxfd = chld->fd;
506 
507         return;
508     }
509 
510     /* Rest of function is child */
511 
512 #ifndef        NDEBUG
513     {
514         void *childwait;
515 
516         if((childwait = opts.childwait)){
517             OWPError(policy->ctx,OWPErrWARNING,OWPErrUNKNOWN,
518                     "Busy-loop...");
519             /* busy loop to wait for debug-attach */
520             while(childwait);
521             /*
522              * set OWPChildWait if you want to attach
523              * to them... (by resetting childwait back to non-zero)
524              */
525             if(childwait && !OWPContextConfigSetV(policy->ctx,OWPChildWait,
526                         childwait)){
527                 OWPError(policy->ctx,OWPErrWARNING,OWPErrUNKNOWN,
528                         "OWPContextConfigSetV(): Unable to set OWPChildWait?!");
529             }
530         }
531     }
532 #endif
533 
534     /*
535      * Close unneeded fd's (these are used by the parent)
536      */
537     I2HashIterate(fdtable,ClosePipes,NULL);
538 
539     /*
540      * reset error logging
541      */
542     I2ErrReset(errhand);
543 
544     /*
545      * check/set signal vars.
546      */
547     if(owpd_exit){
548         exit(0);
549     }
550     owpd_intr = 0;
551 
552     /*
553      * Initialize itimer struct. The it_value.tv_sec will be
554      * set to interrupt socket i/o if the message is not received
555      * within the timeout as described by owdp draft section 4
556      * (OWAMP-Control).
557      */
558     memset(&itval,0,sizeof(itval));
559 
560     /*
561      * save the pipe fd in the policy record for the hooks to
562      * pick it up.
563      */
564     policy->fd = new_pipe[1];
565 
566     /*
567      * If the daemon is configured to do open_mode, check if
568      * there is an open_mode limit defined for the given
569      * address.
570      */
571     if((mode & OWP_MODE_OPEN) && !OWPDAllowOpenMode(policy,
572                 (struct sockaddr *)&sbuff,&out)){
573         if(out != OWPErrOK){
574             exit(out);
575         }
576         mode &= ~OWP_MODE_OPEN;
577     }
578 
579     owpd_intr = 0;
580     itval.it_value.tv_sec = opts.controltimeout;
581     if(setitimer(ITIMER_REAL,&itval,NULL) != 0){
582         I2ErrLog(errhand,"setitimer(): %M");
583         exit(OWPErrFATAL);
584     }
585     cntrl = OWPControlAccept(policy->ctx,connfd,
586             (struct sockaddr *)&sbuff,sbufflen,
587             mode,uptime,&owpd_intr,&out);
588     /*
589      * session not accepted.
590      */
591     if(!cntrl){
592         exit(out);
593     }
594 
595     /*
596      * Process all requests - return when complete.
597      */
598     while(1){
599         OWPErrSeverity  rc;
600 
601         rc = OWPErrOK;
602         /*
603          * reset signal vars
604          */
605         owpd_intr = owpd_alrm = owpd_chld = 0;
606         itval.it_value.tv_sec = opts.controltimeout;
607         if(setitimer(ITIMER_REAL,&itval,NULL) != 0){
608             I2ErrLog(errhand,"setitimer(): %M");
609             goto done;
610         }
611 
612         msgtype = OWPReadRequestType(cntrl,&owpd_intr);
613 
614         switch (msgtype){
615 
616             case OWPReqTest:
617                 rc = OWPProcessTestRequest(cntrl,&owpd_intr);
618                 break;
619 
620             case OWPReqStartSessions:
621                 rc = OWPProcessStartSessions(cntrl,&owpd_intr);
622                 if(rc < OWPErrOK){
623                     break;
624                 }
625                 /*
626                  * Test session started - unset timer - wait
627                  * until all sessions are complete, then
628                  * reset the timer and wait for stopsessions
629                  * to complete.
630                  */
631                 owpd_intr = 0;
632                 itval.it_value.tv_sec = 0;
633                 if(setitimer(ITIMER_REAL,&itval,NULL) != 0){
634                     I2ErrLog(errhand,"setitimer(): %M");
635                     goto done;
636                 }
637                 while(OWPSessionsActive(cntrl,NULL)){
638                     int        wstate;
639 
640                     rc = OWPErrOK;
641                     owpd_intr = 0;
642                     wstate = OWPStopSessionsWait(cntrl,NULL,
643                             &owpd_intr,NULL,&rc);
644                     if(owpd_int){
645                         goto done;
646                     }
647                     else if(owpd_exit){
648                         /*
649                          * wstate == 2 indicates gracefull shutdown...
650                          * Continue on and let StopSessions happen.
651                          */
652                         if(wstate != 2){
653                             goto done;
654                         }
655                         break;
656                     }
657                     if(wstate == 0){
658                         goto nextreq;
659                     }
660                 }
661                 /*
662                  * Sessions are complete, but StopSessions
663                  * message has not been exchanged - set the
664                  * timer and trade StopSessions messages
665                  */
666                 owpd_intr = 0;
667                 itval.it_value.tv_sec = opts.controltimeout;
668                 if(setitimer(ITIMER_REAL,&itval,NULL) != 0){
669                     I2ErrLog(errhand,"setitimer(): %M");
670                     goto done;
671                 }
672                 rc = OWPStopSessions(cntrl,&owpd_intr,NULL);
673 
674                 break;
675 
676             case OWPReqFetchSession:
677                 /*
678                  * TODO: Should the timeout be suspended
679                  * for fetchsession?
680                  * (If session files take longer than
681                  * the timeout - this will fail... The
682                  * default is 30 min. Leave for now.
683                  * (The fix would be to leave the timeout in
684                  * place for completing the fetchsession
685                  * read, and then process the write
686                  * of the session separately.)
687                  */
688                 rc = OWPProcessFetchSession(cntrl,&owpd_intr);
689                 break;
690 
691             case OWPReqSockClose:
692             default:
693                 rc = OWPErrFATAL;
694                 break;
695         }
696 nextreq:
697         if(rc < OWPErrWARNING){
698             break;
699         }
700         if(owpd_exit){
701             break;
702         }
703     }
704 
705 done:
706     OWPControlClose(cntrl);
707 
708     if(owpd_exit){
709         exit(0);
710     }
711 
712     /*
713      * Normal socket close
714      */
715     if(msgtype == OWPReqSockClose){
716         exit(0);
717     }
718 
719     I2ErrLog(errhand,"Control session terminated abnormally...");
720 
721     exit(1);
722 }
723 
724 /*
725  * hash functions...
726  * I cheat - I use the "dsize" part of the datum for the key data since
727  * pid and fd are both integers.
728  */
729 static int
intcmp(const I2Datum x,const I2Datum y)730 intcmp(
731         const I2Datum   x,
732         const I2Datum   y
733       )
734 {
735     return(x.dsize != y.dsize);
736 }
737 
738 static uint32_t
inthash(I2Datum key)739 inthash(
740         I2Datum key
741        )
742 {
743     return (uint32_t)key.dsize;
744 }
745 
746 static I2Boolean
FindMaxFD(I2Datum key,I2Datum value,void * app_data)747 FindMaxFD(
748         I2Datum key,
749         I2Datum value       __attribute__((unused)),
750         void    *app_data
751         )
752 {
753     int *maxfd = (int *)app_data;
754 
755     if((*maxfd < 0) || ((int)key.dsize > *maxfd)){
756         *maxfd = (int)key.dsize;
757     }
758 
759     return True;
760 }
761 
762 static I2Boolean
parse_ports(char * pspec)763 parse_ports(
764         char    *pspec
765         )
766 {
767     char    *tstr,*endptr;
768     long    tint;
769 
770     if(!pspec) return False;
771 
772     tstr = pspec;
773     endptr = NULL;
774 
775     while(isspace((int)*tstr)) tstr++;
776     tint = strtol(tstr,&endptr,10);
777     if(!endptr || (tstr == endptr) || (tint < 0) || (tint > (int)0xffff)){
778         goto failed;
779     }
780     portrec.low = (uint16_t)tint;
781 
782     while(isspace((int)*endptr)) endptr++;
783 
784     switch(*endptr){
785         case '\0':
786             /* only allow a single value if it is 0 */
787             if(portrec.low){
788                 goto failed;
789             }
790             portrec.high = portrec.low;
791             goto done;
792             break;
793         case '-':
794             endptr++;
795             break;
796         default:
797             goto failed;
798     }
799 
800     tstr = endptr;
801     endptr = NULL;
802     while(isspace((int)*tstr)) tstr++;
803     tint = strtol(tstr,&endptr,10);
804     if(!endptr || (tstr == endptr) || (tint < 0) || (tint > (int)0xffff)){
805         goto failed;
806     }
807     portrec.high = (uint16_t)tint;
808 
809     if(portrec.high < portrec.low){
810         goto failed;
811     }
812 
813 done:
814     /*
815      * If ephemeral is specified, shortcut by not setting.
816      */
817     if(!portrec.high && !portrec.low)
818         return True;
819 
820     /*
821      * Set.
822      */
823     opts.portspec = &portrec;
824     return True;
825 
826 failed:
827     if(errhand){
828         I2ErrLogP(errhand,EINVAL,"Invalid port-range: \"%s\"",pspec);
829     }
830     else{
831         fprintf(stderr,"Invalid port-range: \"%s\"",pspec);
832     }
833 
834     return False;
835 }
836 
837 static void
LoadConfig(char ** lbuf,size_t * lbuf_max)838 LoadConfig(
839         char    **lbuf,
840         size_t  *lbuf_max
841         )
842 {
843     FILE    *conf;
844     char    conf_file[MAXPATHLEN+1];
845     char    keybuf[MAXPATHLEN],valbuf[MAXPATHLEN];
846     char    *key = keybuf;
847     char    *val = valbuf;
848     int     rc=0;
849 
850     conf_file[0] = '\0';
851 
852     rc = strlen(OWAMPD_CONF_FILE);
853     if(rc > MAXPATHLEN){
854         fprintf(stderr,"strlen(OWAMPD_CONF_FILE) > MAXPATHLEN\n");
855         exit(1);
856     }
857     if(opts.confdir){
858         rc += strlen(opts.confdir) + strlen(OWP_PATH_SEPARATOR);
859         if(rc > MAXPATHLEN){
860             fprintf(stderr,"Path to %s > MAXPATHLEN\n",
861                     OWAMPD_CONF_FILE);
862             exit(1);
863         }
864         strcpy(conf_file, opts.confdir);
865         strcat(conf_file, OWP_PATH_SEPARATOR);
866     }
867     strcat(conf_file, OWAMPD_CONF_FILE);
868 
869     if(!(conf = fopen(conf_file, "r"))){
870         if(opts.confdir){
871             fprintf(stderr,"Unable to open %s: %s\n",conf_file,
872                     strerror(errno));
873             exit(1);
874         }
875         return;
876     }
877 
878     while((rc = I2ReadConfVar(conf,rc,key,val,MAXPATHLEN,lbuf,lbuf_max))
879             > 0){
880 
881         /* syslog facility */
882         if(!strncasecmp(key,"facility",9)){
883             int fac = I2ErrLogSyslogFacility(val);
884             if(fac == -1){
885                 fprintf(stderr,
886                         "Invalid -e: Syslog facility \"%s\" unknown\n",
887                         val);
888                 rc = -rc;
889                 break;
890             }
891             syslogattr.facility = fac;
892         }
893         else if(!strncasecmp(key,"loglocation",12)){
894             syslogattr.line_info |= I2FILE|I2LINE;
895         }
896         else if(!strncasecmp(key,"rootfolly",10)){
897             opts.allowroot = True;
898         }
899         else if(!strncasecmp(key,"datadir",8)){
900             if(!(opts.datadir = strdup(val))) {
901                 fprintf(stderr,"strdup(): %s\n",
902                         strerror(errno));
903                 rc=-rc;
904                 break;
905             }
906         }
907         else if(!strncasecmp(key,"user",5)){
908             if(!(opts.user = strdup(val))) {
909                 fprintf(stderr,"strdup(): %s\n",
910                         strerror(errno));
911                 rc=-rc;
912                 break;
913             }
914         }
915         else if(!strncasecmp(key,"group",6)){
916             if(!(opts.group = strdup(val))) {
917                 fprintf(stderr,"strdup(): %s\n",
918                         strerror(errno));
919                 rc=-rc;
920                 break;
921             }
922         }
923         else if(!strncasecmp(key,"verbose",8)){
924             opts.verbose = True;
925         }
926         else if(!strncasecmp(key,"authmode",9)){
927             if(!(opts.authmode = strdup(val))) {
928                 fprintf(stderr,"strdup(): %s\n",
929                         strerror(errno));
930                 rc=-rc;
931                 break;
932             }
933         }
934         else if(!strncasecmp(key,"srcnode",8)){
935             if(!(opts.srcnode = strdup(val))) {
936                 fprintf(stderr,"strdup(): %s\n",
937                         strerror(errno));
938                 rc=-rc;
939                 break;
940             }
941         }
942         else if(!strncasecmp(key,"testports",10)){
943             if(!parse_ports(val)){
944                 fprintf(stderr,
945                         "Invalid test port range specified.");
946                 rc=-rc;
947                 break;
948             }
949         }
950         else if(!strncasecmp(key,"vardir",7)){
951             if(!(opts.vardir = strdup(val))) {
952                 fprintf(stderr,"strdup(): %s\n",
953                         strerror(errno));
954                 rc=-rc;
955                 break;
956             }
957         }
958         else if(!strncasecmp(key,"diskfudge",10)){
959             char        *end=NULL;
960             double        tdbl;
961 
962             errno = 0;
963             tdbl = strtod(val,&end);
964             if((end == val) || (errno == ERANGE)){
965                 fprintf(stderr,"strtod(): %s\n",
966                         strerror(errno));
967                 rc=-rc;
968                 break;
969             }
970             if((tdbl >= 1.0) && (tdbl <= 10.0)){
971                 opts.diskfudge = tdbl;
972             }
973             else{
974                 fprintf(stderr,"Invalid diskfudge \"%f\":"
975                         "valid values 1.0<=diskfudge<=10.0",
976                         tdbl);
977                 rc=-rc;
978                 break;
979             }
980         }
981         else if(!strncasecmp(key,"dieby",6)){
982             char                *end=NULL;
983             uint32_t        tlng;
984 
985             errno = 0;
986             tlng = strtoul(val,&end,10);
987             if((end == val) || (errno == ERANGE)){
988                 fprintf(stderr,"strtoul(): %s\n",
989                         strerror(errno));
990                 rc=-rc;
991                 break;
992             }
993             opts.dieby = tlng;
994         }
995         else if(!strncasecmp(key,"controltimeout",15)){
996             char                *end=NULL;
997             uint32_t        tlng;
998 
999             errno = 0;
1000             tlng = strtoul(val,&end,10);
1001             if((end == val) || (errno == ERANGE)){
1002                 fprintf(stderr,"strtoul(): %s\n",
1003                         strerror(errno));
1004                 rc=-rc;
1005                 break;
1006             }
1007             opts.controltimeout = tlng;
1008         }
1009         else if(!strncasecmp(key,"pbkdf2_count",13)){
1010             char        *end=NULL;
1011             uint32_t    tlng;
1012 
1013             errno = 0;
1014             tlng = strtoul(val,&end,10);
1015             if((end == val) || (errno == ERANGE)){
1016                 fprintf(stderr,"strtoul(): %s\n",
1017                         strerror(errno));
1018                 rc=-rc;
1019                 break;
1020             }
1021             opts.pbkdf2_count = tlng;
1022         }
1023         else if(!strncasecmp(key,"enddelay",9)){
1024             char        *end=NULL;
1025             double        tdbl;
1026 
1027             errno = 0;
1028             tdbl = strtod(val,&end);
1029             if((end == val) || (errno == ERANGE)){
1030                 fprintf(stderr,"strtod(): %s\n",
1031                         strerror(errno));
1032                 rc=-rc;
1033                 break;
1034             }
1035             if(tdbl >= 0.0){
1036                 opts.setEndDelay = True;
1037                 opts.endDelay = tdbl;
1038             }
1039             else{
1040                 fprintf(stderr,"Invalid enddelay \"%f\":"
1041                         "positive value expected",
1042                         tdbl);
1043                 rc=-rc;
1044                 break;
1045             }
1046         }
1047         else{
1048             fprintf(stderr,"Unknown key=%s\n",key);
1049             rc = -rc;
1050             break;
1051         }
1052     }
1053 
1054     if(rc < 0){
1055         fprintf(stderr,"%s:%d Problem parsing conffile\n",
1056                 conf_file,-rc);
1057         exit(1);
1058     }
1059 
1060     return;
1061 }
1062 
main(int argc,char * argv[])1063 int main(
1064         int     argc,
1065         char    *argv[]
1066         )
1067 {
1068     char                *progname=NULL;
1069     OWPErrSeverity      out = OWPErrFATAL;
1070     char                pid_file[MAXPATHLEN],
1071                         info_file[MAXPATHLEN];
1072 
1073     fd_set              readfds;
1074     int                 maxfd;    /* max fd in readfds */
1075     OWPContext          ctx;
1076     OWPDPolicy          policy;
1077     I2Addr              listenaddr = NULL;
1078     int                 listenfd;
1079     int                 rc;
1080     I2Datum             data;
1081     struct flock        flk;
1082     int                 pid_fd;
1083     FILE                *pid_fp, *info_fp;
1084     OWPTimeStamp        currtime;
1085     int                 ch;
1086     uid_t               setuser=0;
1087     gid_t               setgroup=0;
1088     char                *lbuf=NULL;
1089     size_t              lbuf_max=0;
1090 
1091     struct sigaction    ignact,setact;
1092     sigset_t            sigs;
1093 
1094 #ifndef NDEBUG
1095     char                *optstring = "a:c:d:e:fG:hP:R:S:U:vwZ";
1096 #else
1097     char                *optstring = "a:c:d:e:fG:hP:R:S:U:vZ";
1098 #endif
1099 
1100     /*
1101      * remove any path component from argv[0] for progname.
1102      */
1103     progname = (progname = strrchr(argv[0],'/')) ? progname+1 : *argv;
1104 
1105     /*
1106      * Start an error loggin session for reporting errors to the
1107      * standard error
1108      */
1109     syslogattr.ident = progname;
1110     syslogattr.logopt = LOG_PID;
1111     syslogattr.facility = LOG_DAEMON;
1112     syslogattr.priority = LOG_ERR;
1113     syslogattr.line_info = I2MSG;
1114 
1115     /* Set up options defaults */
1116     opts.verbose = False;
1117     opts.passwd = "passwd.conf";
1118     opts.vardir = opts.confdir = opts.datadir = NULL;
1119     opts.authmode = NULL;
1120     opts.srcnode = NULL;
1121     opts.daemon = 1;
1122     opts.user = opts.group = NULL;
1123     opts.diskfudge = 1.0;
1124     opts.dieby = 30;
1125     opts.controltimeout = 1800;
1126     opts.portspec = NULL;
1127 
1128     if(!getcwd(opts.cwd,sizeof(opts.cwd))){
1129         perror("getcwd()");
1130         exit(1);
1131     }
1132 
1133     /*
1134      * Fetch config file option if present
1135      */
1136     opterr = 0;
1137     while((ch = getopt(argc, argv, optstring)) != -1){
1138         switch (ch){
1139             case 'c':        /* -c "Config directory" */
1140                 if (!(opts.confdir = strdup(optarg))) {
1141                     /* eh isn't setup yet...*/
1142                     perror("strdup()");
1143                     exit(1);
1144                 }
1145                 break;
1146             default:
1147                 break;
1148         }
1149     }
1150     opterr = optreset = optind = 1;
1151 
1152     /*
1153      * Load Config file.
1154      * lbuf/lbuf_max keep track of a dynamically grown "line" buffer.
1155      * (It is grown using realloc.)
1156      * This will be used throughout all the config file reading and
1157      * should be free'd once all config files have been read.
1158      */
1159     LoadConfig(&lbuf,&lbuf_max);
1160 
1161     /*
1162      * Read cmdline options that effect syslog so the rest of cmdline
1163      * processing can be reported via syslog.
1164      */
1165     opterr = 0;
1166     while((ch = getopt(argc, argv, optstring)) != -1){
1167         switch (ch){
1168             int fac;
1169             case 'e':        /* -e "syslog err facility" */
1170             fac = I2ErrLogSyslogFacility(optarg);
1171             if(fac == -1){
1172                 fprintf(stderr,
1173                         "Invalid -e: Syslog facility \"%s\" unknown\n",
1174                         optarg);
1175                 exit(1);
1176             }
1177             syslogattr.facility = fac;
1178             break;
1179             case 'Z':
1180             opts.daemon = 0;
1181             break;
1182             default:
1183             break;
1184         }
1185     }
1186     opterr = optreset = optind = 1;
1187 
1188     /*
1189      * Always use LOG_PERROR - if daemonizing, stderr will be closed,
1190      * and this hurts nothing. And... commandline reporting is good
1191      * until after the fork.
1192      */
1193     syslogattr.logopt |= LOG_PERROR;
1194     errhand = I2ErrOpen(progname, I2ErrLogSyslog, &syslogattr, NULL, NULL);
1195     if(! errhand) {
1196         fprintf(stderr, "%s : Couldn't init error module\n", progname);
1197         exit(1);
1198     }
1199     I2ErrSetResetFunc(errhand,I2ErrLogSyslogReset);
1200 
1201     /*
1202      * Initialize the context. (Set the error handler to the app defined
1203      * one.)
1204      */
1205     if( !(ctx = OWPContextCreate(errhand))){
1206         fprintf(stderr, "%s: Unable to initialize application\n",progname);
1207         exit(1);
1208     }
1209 
1210     /*
1211      * Now deal with "all" cmdline options.
1212      */
1213     while ((ch = getopt(argc, argv, optstring)) != -1){
1214         switch (ch) {
1215             case 'a':        /* -a "authmode" */
1216                 if (!(opts.authmode = strdup(optarg))) {
1217                     I2ErrLog(errhand,"strdup(): %M");
1218                     exit(1);
1219                 }
1220                 break;
1221             case 'd':        /* -d "data directory" */
1222                 if (!(opts.datadir = strdup(optarg))) {
1223                     I2ErrLog(errhand,"strdup(): %M");
1224                     exit(1);
1225                 }
1226                 break;
1227             case 'f':       /* -f */
1228                 opts.allowroot = True;
1229                 break;
1230             case 'v':        /* -v "verbose" */
1231                 opts.verbose = True;
1232                 break;
1233             case 'S':  /* -S "src addr" */
1234                 if (!(opts.srcnode = strdup(optarg))) {
1235                     I2ErrLog(errhand,"strdup(): %M");
1236                     exit(1);
1237                 }
1238                 break;
1239             case 'U':
1240                 if(!(opts.user = strdup(optarg))){
1241                     I2ErrLog(errhand,"strdup(): %M");
1242                     exit(1);
1243                 }
1244                 break;
1245             case 'G':
1246                 if(!(opts.group = strdup(optarg))){
1247                     I2ErrLog(errhand,"strdup(): %M");
1248                     exit(1);
1249                 }
1250                 break;
1251             case 'P':
1252                 if(!parse_ports(optarg)){
1253                     I2ErrLog(errhand,
1254                             "Invalid test port range specified.");
1255                     exit(1);
1256                 }
1257                 break;
1258             case 'R':        /* -R "var/run directory" */
1259                 if (!(opts.vardir = strdup(optarg))) {
1260                     I2ErrLog(errhand,"strdup(): %M");
1261                     exit(1);
1262                 }
1263                 break;
1264             case 'c':
1265             case 'e':
1266             case 'Z':
1267                 break;
1268 #ifndef NDEBUG
1269             case 'w':
1270                 opts.childwait = (void*)True;
1271                 break;
1272 #endif
1273             case 'h':
1274             case '?':
1275             default:
1276                 usage(progname, "");
1277                 exit(0);
1278                 /* UNREACHED */
1279         }
1280     }
1281     argc -= optind;
1282     argv += optind;
1283 
1284     if (argc) {
1285         usage(progname, "");
1286         exit(1);
1287     }
1288 
1289     /*
1290      * Setup portrange
1291      */
1292     if(opts.portspec && !OWPContextConfigSetV(ctx,OWPTestPortRange,
1293                 (void*)opts.portspec)){
1294         I2ErrLog(errhand,
1295                 "OWPContextConfigSetV(): Unable to set OWPTestPortRange?!");
1296         exit(1);
1297     }
1298 
1299     /*
1300      * Setup count
1301      */
1302     if(opts.pbkdf2_count && !OWPContextConfigSetU32(ctx,OWPKeyDerivationCount,
1303                 opts.pbkdf2_count)){
1304         I2ErrLog(errhand,
1305                 "OWPContextConfigSetU32(): Can't set OWPKeyDerivationCount?!");
1306         exit(1);
1307     }
1308 
1309     /*
1310      * Setup enddelay
1311      */
1312     if(opts.setEndDelay && !OWPContextConfigSetV(ctx,OWPEndDelay,
1313                 &opts.endDelay)){
1314         I2ErrLog(errhand,
1315                 "OWPContextConfigSetV(): Can't set OWPEndDelay?!");
1316         exit(1);
1317     }
1318 
1319     if(!opts.vardir)
1320         opts.vardir = opts.cwd;
1321     if(!opts.confdir)
1322         opts.confdir = opts.cwd;
1323     if(!opts.datadir)
1324         opts.datadir = opts.cwd;
1325 
1326     /*  Get exclusive lock for pid file. */
1327     strcpy(pid_file, opts.vardir);
1328     strcat(pid_file, OWP_PATH_SEPARATOR);
1329     strcat(pid_file, "owampd.pid");
1330     if ((pid_fd = open(pid_file, O_RDWR|O_CREAT,
1331                     S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0) {
1332         I2ErrLog(errhand, "open(%s): %M", pid_file);
1333         exit(1);
1334     }
1335 
1336     memset(&flk,0,sizeof(flk));
1337     flk.l_start = 0;
1338     flk.l_len = 0;
1339     flk.l_type = F_WRLCK;
1340     flk.l_whence = SEEK_SET;
1341     while((rc=fcntl(pid_fd, F_SETLK, &flk)) < 0 && errno == EINTR);
1342     if(rc < 0){
1343         I2ErrLog(errhand,"Unable to lock file %s: %M", pid_file);
1344         exit(1);
1345     }
1346     if ((pid_fp = fdopen(pid_fd, "wr")) == NULL) {
1347         I2ErrLog(errhand, "fdopen(): %M");
1348         exit(1);
1349     }
1350 
1351     /*
1352      * Install policy for "ctx" - and return policy record.
1353      */
1354     if(!(policy = OWPDPolicyInstall(ctx,opts.datadir,opts.confdir,
1355                     opts.diskfudge,&lbuf,&lbuf_max))){
1356         I2ErrLog(errhand, "PolicyInit failed. Exiting...");
1357         exit(1);
1358     };
1359 
1360     /*
1361      * Done with the line buffer. (reset to 0 for consistancy.)
1362      */
1363     if(lbuf){
1364         free(lbuf);
1365     }
1366     lbuf = NULL;
1367     lbuf_max = 0;
1368 
1369     /*
1370      * If running as root warn if the -U/-G flags not set.
1371      */
1372     if(!geteuid()){
1373         struct passwd        *pw;
1374         struct group        *gr;
1375 
1376         /*
1377          * Validate user option.
1378          */
1379         if(opts.user){
1380             if((pw = getpwnam(opts.user))){
1381                 setuser = pw->pw_uid;
1382             }
1383             else if(opts.user[0] == '-'){
1384                 setuser = strtoul(&opts.user[1],NULL,10);
1385                 if(errno || !getpwuid(setuser)){
1386                     I2ErrLog(errhand,"Invalid user/-U option: %s",opts.user);
1387                     exit(1);
1388                 }
1389             }
1390             else{
1391                 I2ErrLog(errhand,"Invalid user/-U option: %s",opts.user);
1392                 exit(1);
1393             }
1394         }
1395 
1396         if(!setuser && !opts.allowroot){
1397             I2ErrLog(errhand,"Running owampd as root is folly!");
1398             I2ErrLog(errhand,
1399                     "Use the -U option! (or allow root with the -f option)");
1400             exit(1);
1401         }
1402 
1403         /*
1404          * Validate group option.
1405          */
1406         if(opts.group){
1407             if((gr = getgrnam(opts.group))){
1408                 setgroup = gr->gr_gid;
1409             }
1410             else if(opts.group[0] == '-'){
1411                 setgroup = strtoul(&opts.group[1],NULL,10);
1412                 if(errno || !getgrgid(setgroup))
1413                     setgroup = 0;
1414             }
1415 
1416             if(!setgroup){
1417                 I2ErrLog(errhand,"Invalid user/-G option: %s",
1418                         opts.group);
1419                 exit(1);
1420             }
1421         }
1422 
1423         /*
1424          * Only setting effective id for now. This will catch
1425          * errors, and will still allow the rename of the
1426          * pid/info file later.
1427          */
1428         if(setgroup && (setegid(setgroup) != 0)){
1429             I2ErrLog(errhand,"Unable to setgid to \"%s\": %M",
1430                     opts.group);
1431             exit(1);
1432         }
1433         if(seteuid(setuser) != 0){
1434             I2ErrLog(errhand,"Unable to setuid to \"%s\": %M",
1435                     opts.user);
1436             exit(1);
1437         }
1438     }
1439 
1440     /*
1441      * Finish policy - this part needs to be done after loosing
1442      * "root" permissions.
1443      */
1444     if( !OWPDPolicyPostInstall(policy)){
1445         I2ErrLog(errhand, "PolicyInit failed. Exiting...");
1446         exit(1);
1447     };
1448 
1449     /*
1450      * Setup the "default_mode".
1451      */
1452     if(opts.authmode){
1453         char        *s = opts.authmode;
1454         opts.auth_mode = 0;
1455         while(*s != '\0'){
1456             switch(toupper(*s)){
1457                 case 'O':
1458                     opts.auth_mode |= OWP_MODE_OPEN;
1459                     break;
1460                 case 'A':
1461                     opts.auth_mode |= OWP_MODE_AUTHENTICATED;
1462                     break;
1463                 case 'E':
1464                     opts.auth_mode |= OWP_MODE_ENCRYPTED;
1465                     break;
1466                 default:
1467                     I2ErrLogP(errhand,EINVAL,
1468                             "Invalid -authmode %c",*s);
1469                     usage(progname,NULL);
1470                     exit(1);
1471             }
1472             s++;
1473         }
1474     }
1475     else{
1476         /*
1477          * Default to all modes.
1478          */
1479         opts.auth_mode = OWP_MODE_OPEN|OWP_MODE_AUTHENTICATED|
1480             OWP_MODE_ENCRYPTED;
1481     }
1482 
1483     /*
1484      * TODO: a config test for this would probably be cleaner...
1485      */
1486     {        /* ensure intcmp will work */
1487         size_t        psize = sizeof(pid_t);
1488         assert(psize<=sizeof(data.dsize));
1489     }
1490 
1491     pidtable = I2HashInit(errhand,0,intcmp,inthash);
1492     fdtable = I2HashInit(errhand,0,intcmp,inthash);
1493     if(!pidtable || !fdtable){
1494         I2ErrLogP(errhand,0,"Unable to setup hash tables...");
1495         exit(1);
1496     }
1497 
1498     /*
1499      * Get start-time for server greeting report.
1500      */
1501     if(!OWPGetTimeOfDay(ctx,&currtime)){
1502         I2ErrLogP(errhand, errno, "OWPGetTimeOfDay: %M");
1503         kill(mypid,SIGTERM);
1504         exit(1);
1505     }
1506     uptime = currtime.owptime;
1507 
1508     /*
1509      * daemonize here
1510      */
1511     mypid = 0;
1512     if(opts.daemon){
1513 
1514         /*
1515          * chdir to '/' so filesystems can be unmounted.
1516          */
1517         if(chdir("/") < 0){
1518             I2ErrLog(errhand,"Unable to chdir to /: %M");
1519             exit(1);
1520         }
1521 
1522         /*
1523          * reopen stdin/stdout/stderr fd's
1524          */
1525         for(rc=0;rc<3;rc++){
1526             if(close(rc) == -1 || open("/dev/null",O_RDWR) != rc){
1527                 I2ErrLog(errhand,"Unable to reopen fd(%d): %M",
1528                         rc);
1529                 exit(1);
1530             }
1531         }
1532 
1533         /*
1534          * respawn self to detach from terminal.
1535          */
1536         mypid = fork();
1537         if(mypid < 0){
1538             I2ErrLog(errhand,"Unable to fork: %M");
1539             exit(1);
1540         }
1541         if((mypid == 0) && (setsid() == -1)){
1542             I2ErrLog(errhand,"setsid(): %M");
1543             exit(1);
1544         }
1545     }
1546     else{
1547         /*
1548          * Depending upon the shell that starts this -Z "foreground"
1549          * daemon, this process may or may not be the Process Group
1550          * leader... This will make sure. (Needed so HUP/TERM
1551          * catching can kill the whole process group with one
1552          * kill call.) setsid handles this when daemonizing.
1553          */
1554         mypid = getpid();
1555         if(setpgid(0,mypid) != 0){
1556             I2ErrLog(errhand,"setpgid(): %M");
1557             exit(1);
1558         }
1559     }
1560 
1561     /*
1562      * Temporarily take root permissions back.
1563      * (If this is parent of daemonizing - exit immediately after
1564      * updating pid/info files. If not daemonizing, setuid/setgid
1565      * is called after the mypid if to return to lesser
1566      * permissions.)
1567      */
1568     if((setuser) && (seteuid(getuid()) != 0)){
1569         I2ErrLog(errhand,"seteuid(): %M");
1570         kill(mypid,SIGTERM);
1571         exit(1);
1572     }
1573     if((setgroup) && (setegid(getgid()) != 0)){
1574         I2ErrLog(errhand,"setegid(): %M");
1575         kill(mypid,SIGTERM);
1576         exit(1);
1577     }
1578 
1579     /*
1580      * If this is the parent process (or not daemonizing) - write the pid
1581      * and info files.
1582      */
1583     if(mypid > 0){
1584 
1585         /* Record pid.  */
1586         ftruncate(pid_fd, 0);
1587         fprintf(pid_fp, "%lld\n", (long long)mypid);
1588         if (fflush(pid_fp) < 0) {
1589             I2ErrLogP(errhand, errno, "fflush: %M");
1590             kill(mypid,SIGTERM);
1591             exit(1);
1592         }
1593 
1594         /* Record the start timestamp in the info file. */
1595         strcpy(info_file, opts.vardir);
1596         strcat(info_file, OWP_PATH_SEPARATOR);
1597         strcat(info_file, "owampd.info");
1598         if ((info_fp = fopen(info_file, "w")) == NULL) {
1599             I2ErrLog(errhand, "fopen(%s): %M", info_file);
1600             kill(mypid,SIGTERM);
1601             exit(1);
1602         }
1603 
1604         fprintf(info_fp, "START="OWP_TSTAMPFMT"\n", uptime);
1605         fprintf(info_fp, "PID=%lld\n", (long long)mypid);
1606         while ((rc = fclose(info_fp)) < 0 && errno == EINTR);
1607         if(rc < 0){
1608             I2ErrLog(errhand,"fclose(): %M");
1609             kill(mypid,SIGTERM);
1610             exit(1);
1611         }
1612 
1613         /*
1614          * If daemonizing - this is parent - exit.
1615          */
1616         if(opts.daemon) exit(0);
1617     }
1618 
1619     /*
1620      * If the local interface was specified, use it - otherwise use NULL
1621      * for wildcard.
1622      */
1623     if(opts.srcnode && !(listenaddr = I2AddrByNode(ctx,opts.srcnode))){
1624         OWPError(ctx,OWPErrFATAL,OWPErrUNKNOWN,
1625                 "Invalid source address specified: %s",opts.srcnode);
1626         exit(1);
1627     }
1628     listenaddr = OWPServerSockCreate(ctx,listenaddr,&out);
1629     if(!listenaddr){
1630         OWPError(ctx,OWPErrFATAL,OWPErrUNKNOWN,
1631                 "Unable to create server socket. Exiting...");
1632         exit(1);
1633     }
1634 
1635     /*
1636      * set real uid/gid, not just effective.
1637      */
1638     if((setgroup) && (setgid(setgroup) != 0)){
1639         I2ErrLog(errhand,"setegid(): %M");
1640         exit(1);
1641     }
1642     if((setuser) && (setuid(setuser) != 0)){
1643         I2ErrLog(errhand,"setuid(): %M");
1644         exit(1);
1645     }
1646 
1647     /*
1648      * Set up signal handling.
1649      */
1650     memset(&ignact,0,sizeof(ignact));
1651     memset(&setact,0,sizeof(setact));
1652 
1653     ignact.sa_handler = SIG_IGN;
1654     setact.sa_handler = signal_catch;
1655     sigemptyset(&ignact.sa_mask);
1656     sigemptyset(&setact.sa_mask);
1657     ignact.sa_flags = setact.sa_flags = 0;
1658 
1659     if(     (sigaction(SIGPIPE,&ignact,NULL) != 0)  ||
1660             (sigaction(SIGTERM,&setact,NULL) != 0)  ||
1661             (sigaction(SIGUSR1,&setact,NULL) != 0)  ||
1662             (sigaction(SIGUSR2,&setact,NULL) != 0)  ||
1663             (sigaction(SIGINT,&setact,NULL) != 0)   ||
1664             (sigaction(SIGHUP,&setact,NULL) != 0)   ||
1665             (sigaction(SIGCHLD,&setact,NULL) != 0)  ||
1666             (sigaction(SIGALRM,&setact,NULL) != 0)  ){
1667         I2ErrLog(errhand,"sigaction(): %M");
1668         exit(1);
1669     }
1670 
1671     listenfd = I2AddrFD(listenaddr);
1672     FD_ZERO(&readfds);
1673     FD_SET(listenfd,&readfds);
1674     maxfd = listenfd;
1675 
1676     while (1) {
1677         int     nfound;
1678         fd_set  ready;
1679 
1680         if(maxfd < 0){
1681             I2HashIterate(fdtable,FindMaxFD,&maxfd);
1682             maxfd = MAX(maxfd,listenfd);
1683         }
1684         ready = readfds;
1685 
1686         if(owpd_exit){
1687             break;
1688         }
1689 
1690         nfound = select(maxfd+1,&ready,NULL,NULL,NULL);
1691 
1692         /*
1693          * Handle select interupts/errors.
1694          */
1695         if(nfound < 0){
1696             if(errno == EINTR){
1697                 if(owpd_exit){
1698                     break;
1699                 }
1700                 ReapChildren(&maxfd,&readfds);
1701                 continue;
1702             }
1703             OWPError(ctx,OWPErrFATAL,errno,"select(): %M");
1704             exit(1);
1705         }
1706 
1707         /*
1708          * shouldn't happen, but for completeness...
1709          */
1710         if(nfound == 0)
1711             continue;
1712 
1713         if(FD_ISSET(listenfd, &ready)){ /* new connection */
1714             NewConnection(policy,listenaddr,&maxfd,&readfds);
1715         }
1716         else{
1717             CleanPipes(&ready,&maxfd,&readfds,nfound);
1718         }
1719 
1720         if(owpd_exit){
1721             break;
1722         }
1723 
1724         ReapChildren(&maxfd,&readfds);
1725     }
1726 
1727     I2ErrLog(errhand,"%s: exiting...",progname);
1728     /*
1729      * Close the server socket. reset the readfds/maxfd so they
1730      * can't confuse later ReapChildren calls.
1731      */
1732     I2AddrFree(listenaddr);
1733     FD_ZERO(&readfds);
1734     maxfd = -1;
1735 
1736     /*
1737      * Signal the process group to exit.
1738      */
1739     kill(-mypid,SIGTERM);
1740 
1741     /*
1742      * Set an alarm to exit by even if graceful shutdown doesn't occur.
1743      */
1744     owpd_alrm = 0;
1745     alarm(opts.dieby);
1746 
1747     /*
1748      * Close all the pipes so pipe i/o can stay simple. (Don't have
1749      * to deal with interrupts for this.)
1750      */
1751     rc=1;
1752     I2HashIterate(fdtable,ClosePipes,&rc);
1753 
1754     /*
1755      * Loop until all children have been waited for, or until
1756      * alarm goes off.
1757      */
1758     sigemptyset(&sigs);
1759     while(!owpd_alrm && (I2HashNumEntries(pidtable) > 0)){
1760         if(!owpd_chld){
1761             (void)sigsuspend(&sigs);
1762         }
1763         ReapChildren(&maxfd,&readfds);
1764     }
1765 
1766     /*
1767      * If children didn't die, report the error - send SIGKILL and exit.
1768      */
1769     if(I2HashNumEntries(pidtable) > 0){
1770         I2ErrLog(errhand,
1771                 "Children still alive... Time for brute force.");
1772         kill(-mypid,SIGKILL);
1773     }
1774 
1775     I2ErrLog(errhand,"%s: exited.",progname);
1776 
1777     exit(0);
1778 }
1779