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