Revert "try to restart the server if a child dies"
[aox:aox.git] / server / server.cpp
1 // Copyright Oryx Mail Systems GmbH. All enquiries to info@oryx.com, please.
2
3 // getpwnam
4 #include <pwd.h>
5 // getgrnam
6 #include <grp.h>
7 // write, getpid, getdtablesize, close, dup, getuid, geteuid, chroot,
8 // chdir, setregid, setreuid, fork
9 #include <unistd.h>
10 // open, O_RDWR
11 #include <sys/stat.h>
12 #include <fcntl.h>
13 // opendir
14 #include <dirent.h>
15 // exit
16 #include <stdlib.h>
17 // errno
18 #include <errno.h>
19 // fork
20 #include <sys/types.h>
21 // fprintf, stderr
22 #include <stdio.h>
23 // sigaction, sigemptyset
24 #include <signal.h>
25
26 // our own includes, _after_ the system header files. lots of system
27 // header files break if we've already defined UINT_MAX, etc.
28
29 #include "server.h"
30
31 #include "log.h"
32 #include "file.h"
33 #include "scope.h"
34 #include "estring.h"
35 #include "logclient.h"
36 #include "eventloop.h"
37 #include "connection.h"
38 #include "configuration.h"
39 #include "eventloop.h"
40 #include "allocator.h"
41 #include "resolver.h"
42 #include "entropy.h"
43 #include "query.h"
44
45
46 class ServerData
47     : public Garbage
48 {
49 public:
50     ServerData( const char * n )
51         : name( n ), stage( Server::Configuration ),
52           secured( false ), fork( false ), useCache( USECACHE ),
53           chrootMode( Server::JailDir ),
54           queries( new List< Query > ),
55           children( 0 ),
56           mainProcess( false )
57     {}
58
59     EString name;
60     Server::Stage stage;
61     EString configFile;
62     bool secured;
63     bool fork;
64     bool useCache;
65     Server::ChrootMode chrootMode;
66     List< Query > *queries;
67     List<pid_t> * children;
68     bool mainProcess;
69 };
70
71
72 ServerData * Server::d;
73
74
75 /*! \class Server server.h
76
77     The Server class performs the server startup functions that are
78     common to most/all Archiveopteryx servers. The functions are
79     performed in a fixed order - you call setup( x ) to continue up to
80     stage x, then return.
81 */
82
83
84 /*! Constructs a Server for \a name. \a name will be used for the pid
85     file, etc. \a argc and \a argv are parsed to find command-line
86     options.
87 */
88
89 Server::Server( const char * name, int argc, char * argv[] )
90 {
91     d = new ServerData( name );
92     Allocator::addEternal( d, "Server data" );
93
94     bool uc = false;
95     int c;
96     while ( (c=getopt( argc, argv, "fc:C" )) != -1 ) {
97         switch ( c ) {
98         case 'f':
99             if ( d->fork ) {
100                 fprintf( stderr, "%s: -f specified twice\n", name );
101                 exit( 1 );
102             }
103             d->fork = true;
104             break;
105         case 'c':
106             if ( !d->configFile.isEmpty() ) {
107                 fprintf( stderr, "%s: -c specified twice\n", name );
108                 exit( 1 );
109             }
110             else {
111                 d->configFile = optarg;
112                 File tmp( d->configFile );
113                 if ( !tmp.valid() ) {
114                     fprintf( stderr,
115                              "%s: Config file %s not accessible/readable\n",
116                              name, tmp.name().cstr() );
117                     exit( 1 );
118                 }
119             }
120             break;
121         case 'C':
122             // -C is undocumented on purpose. it should not change
123             // anything except performance, and exists only for
124             // testing.
125             d->useCache = !d->useCache;
126             uc = true;
127             break;
128         default:
129             exit( 1 );
130             break;
131         }
132     }
133     if ( argc > optind ) {
134         fprintf( stderr, "%s: Parse error for argument %d (%s)\n",
135                  name, optind, argv[optind] );
136         exit( 1 );
137     }
138     if ( uc || !d->useCache )
139         fprintf( stdout, "%s: Will%s use caches\n",
140                  name, d->useCache ? "" : " not" );
141 }
142
143
144 /*! Notifies the Server that it is to chroot according to \a mode. If
145     \a mode is JailDir, secure() will chroot into the jail directory
146     and check that '/' is inaccesssible. If \a mode is LogDir,
147     secure() will chroot into the logfile directory, where the server
148     hopefully can access the logfile.
149 */
150
151 void Server::setChrootMode( ChrootMode mode )
152 {
153     d->chrootMode = mode;
154 }
155
156
157 /*! Performs server setup for each stage up to but NOT including \a s. */
158
159 void Server::setup( Stage s )
160 {
161     try {
162         while ( d->stage < s ) {
163             switch ( d->stage ) {
164             case Configuration:
165                 configuration();
166                 break;
167             case NameResolution:
168                 nameResolution();
169                 break;
170             case Files:
171                 files();
172                 break;
173             case LogSetup:
174                 logSetup();
175                 break;
176             case Loop:
177                 loop();
178                 break;
179             case Report:
180                 // This just gives us a good place to stop in main.
181                 break;
182             case Fork:
183                 fork();
184                 break;
185             case PidFile:
186                 pidFile();
187                 break;
188             case LogStartup:
189                 logStartup();
190                 break;
191             case Secure:
192                 secure();
193                 break;
194             case Finish:
195                 break;
196             }
197             d->stage = (Stage)(d->stage + 1);
198         }
199     } catch ( Exception e ) {
200         // don't allocate memory or call anything here.
201         const char * c = 0;
202         switch (e) {
203         case Invariant:
204             c = "Invariant failed during server startup.";
205             break;
206         case Segfault:
207             c = "Segfault detected during server startup.";
208             break;
209         case Memory:
210             c = "Out of memory during server startup.";
211             break;
212         case FD:
213             c = "FD error during server startup.";
214             break;
215         };
216         uint i = 0;
217         while( c[i] )
218             i++;
219         ::write( 2, c, i );
220         ::write( 2, "\n", 1 );
221         exit( 1 );
222     }
223 }
224
225
226 /*! Reads server configuration, either from the default config file or
227     from the one supplied in argc.
228 */
229
230 void Server::configuration()
231 {
232     if ( d->configFile.isEmpty() )
233         Configuration::setup( "archiveopteryx.conf" );
234     else
235         Configuration::setup( d->configFile );
236     if ( d->useCache && !Configuration::scalar( Configuration::MemoryLimit ) )
237         d->useCache = false;
238 }
239
240
241 /*! Resolves any domain names used in the configuration file before we
242     chroot.
243 */
244
245 void Server::nameResolution()
246 {
247     List<Configuration::Text>::Iterator i( Configuration::addressVariables() );
248     while ( i ) {
249         const EStringList & r
250             = Resolver::resolve( Configuration::text( *i ) );
251         if ( r.isEmpty() ) {
252             log( EString("Unable to resolve ") +
253                  Configuration::name( *i ) +
254                  " = " + Configuration::text( *i ),
255                  Log::Disaster );
256         }
257         ++i;
258     }
259     if ( !Log::disastersYet() )
260         return;
261
262     EStringList::Iterator e( Resolver::errors() );
263     while ( e ) {
264         log( *e );
265         ++e;
266     }
267 }
268
269
270 /*! Closes all files except stdout and stderr. Attaches stdin to
271     /dev/null in case something uses it. stderr is kept open so
272     that we can tell our daddy about any disasters.
273 */
274
275 void Server::files()
276 {
277     int s = getdtablesize();
278     while ( s > 0 ) {
279         s--;
280         if ( s != 2 && s != 1 )
281             close( s );
282     }
283     s = open( "/dev/null", O_RDWR );
284
285     Entropy::setup();
286 }
287
288
289 /*! Creates the global logging context, and sets up a LogClient if no
290     Logger has been created already.
291
292     This also creates the Loop object, so that the LogClient doesn't
293     feel alone in the world, abandoned by its parents, depressed and
294     generally bad.
295 */
296
297 void Server::logSetup()
298 {
299     EventLoop::setup();
300     if ( !Logger::global() )
301         LogClient::setup( d->name );
302     Scope::current()->setLog( new Log );
303     log( name() + ", Archiveopteryx version " +
304          Configuration::compiledIn( Configuration::Version ) );
305     Allocator::setReporting( true );
306 }
307
308
309 static void shutdownLoop( int )
310 {
311     Server::killChildren();
312     if ( EventLoop::global() )
313         EventLoop::global()->stop( 2 );
314 }
315
316
317 static void closeGuiltyConnection( int )
318 {
319     die( Segfault );
320 }
321
322
323 static void dumpCoreAndGoOn( int )
324 {
325     if ( fork() )
326         return;
327
328     // we're now a child process. we can dump core and the real server
329     // will just go on.
330
331     // do we need to do anything about the files? no? I think not.
332
333     abort();
334 }
335
336
337 /*! Called by signal handling to kill any children started in fork(). */
338
339 void Server::killChildren()
340 {
341     List<pid_t>::Iterator child( d->children );
342     while ( child ) {
343         ::kill( *child, SIGTERM );
344         ++child;
345     }
346 }
347
348
349 /*! Initializes the global event loop. */
350
351 void Server::loop()
352 {
353     struct sigaction sa;
354     sa.sa_handler = 0;
355     sa.sa_sigaction = 0; // may be union with sa_handler above
356     sigemptyset( &sa.sa_mask ); // we block no other signals
357     sa.sa_flags = 0; // in particular, we don't want SA_RESETHAND
358
359     // we cannot reread files, so we ignore sighup
360     sa.sa_handler = SIG_IGN;
361     ::sigaction( SIGHUP, &sa, 0 );
362
363     // sigint and sigterm both should stop the server
364     sa.sa_handler = shutdownLoop;
365     ::sigaction( SIGINT, &sa, 0 );
366     ::sigaction( SIGTERM, &sa, 0 );
367
368     // sigpipe happens if we're writing to an already-closed fd. we'll
369     // discover that it's closed a little later.
370     sa.sa_handler = SIG_IGN;
371     ::sigaction( SIGPIPE, &sa, 0 );
372
373     // if we dereference a null pointer, we usually can close some fd
374     // and go on
375     sa.sa_handler = closeGuiltyConnection;
376     ::sigaction( SIGSEGV, &sa, 0 );
377
378     // a custom signal to dump core and go on
379     sa.sa_handler = dumpCoreAndGoOn;
380     ::sigaction( SIGUSR1, &sa, 0 );
381 }
382
383
384 /*! Forks the server as required by -f and the configuration variable
385     server-processes.
386
387     If -f is specified, the parent exits in this function and does not
388     return from this function.
389
390     As many processes as specified by server-processes return.
391 */
392
393 void Server::fork()
394 {
395     if ( !d->fork )
396         return;
397
398     pid_t p = ::fork();
399     if ( p < 0 ) {
400         log( "Unable to fork. Error code " + fn( errno ),
401              Log::Disaster );
402         exit( 1 );
403     } else if ( p > 0 ) {
404         exit( 0 );
405     }
406     d->mainProcess = true;
407     uint children = 0;
408     if ( d->name == "archiveopteryx" ) {
409         children = Configuration::scalar( Configuration::ServerProcesses );
410         if ( children > 1 )
411             d->children = new List<pid_t>;
412     }
413     uint i = 1;
414     while ( d->children && i < children ) {
415         pid_t * child = new pid_t;
416         *child = ::fork();
417         if ( *child < 0 ) {
418             log( "Unable to fork server; pressing on. Error code " +
419                  fn( errno ), Log::Error );
420         }
421         else if ( *child > 0 ) {
422             log( "Process " + fn( getpid() ) + " forked " + fn( *child ) );
423             d->children->append( child );
424         }
425         else {
426             d->mainProcess = false;
427             d->children = 0;
428             EventLoop::global()->closeAllExceptListeners();
429             log( "Process " + fn( getpid() ) + " started" );
430             if ( Configuration::toggle( Configuration::UseStatistics ) ) {
431                 uint port
432                     = Configuration::scalar( Configuration::StatisticsPort );
433                 log( "Using port " + fn( port + i ) +
434                      " for statistics queries" );
435                 Configuration::add( "statistics-port = " + fn( port + i ) );
436             }
437         }
438         i++;
439     }
440 }
441
442
443 /*! Writes the server's pid to an almost hardcoded pidfile. We don't
444     lock the file, since most of these servers don't have a problem
445     with multiple instances of themselves. The pidfile is just a
446     convenience for tools like start-stop-daemon.
447 */
448
449 void Server::pidFile()
450 {
451     if ( !d->mainProcess )
452         return;
453
454     EString dir( Configuration::compiledIn( Configuration::PidFileDir ) );
455
456     EString n = dir + "/" + d->name + ".pid";
457     File f( n, File::Write );
458     if ( f.valid() )
459         f.write( fn( getpid() ) + "\n" );
460     else
461         log( "Unable to write to PID file " + n );
462 }
463
464
465 /*! Logs the startup details. By this time, the logger must be in
466     working order.
467 */
468
469 void Server::logStartup()
470 {
471     log( "Starting server " + d->name +
472          " (host " + Configuration::hostname() + ")" +
473          " (pid " + fn( getpid() ) + ") " +
474          EString( d->secured ? "securely" : "insecurely" ) );
475 }
476
477
478 /*! Loses all rights. Dies with an error if that isn't possible, or if
479     anything fails.
480 */
481
482 void Server::secure()
483 {
484     if ( Configuration::present( Configuration::DbOwnerPassword ) ) {
485         log( "db-owner-password specified in archiveopteryx.conf "
486              "(should be in aoxsuper.conf)",
487              Log::Disaster );
488         exit( 1 );
489     }
490     bool security = Configuration::toggle( Configuration::Security );
491     if ( !security ) {
492         if ( getuid() == 0 || geteuid() == 0 )
493             log( "Warning: Starting " + d->name + " insecurely as root" );
494         d->secured = false;
495         return;
496     }
497
498     EString user( Configuration::text( Configuration::JailUser ) );
499     struct passwd * pw = getpwnam( user.cstr() );
500     if ( !pw ) {
501         log( "Cannot secure server " + d->name +
502              " since " + user + " is not a valid login (says getpwnam())",
503              Log::Disaster );
504         exit( 1 );
505     }
506     if ( pw->pw_uid == 0 ) {
507         log( "Cannot secure server " + d->name + " since " + user +
508              " has UID 0",
509              Log::Disaster );
510         exit( 1 );
511     }
512
513     EString group( Configuration::text( Configuration::JailGroup ) );
514     struct group * gr = getgrnam( group.cstr() );
515     if ( !gr ) {
516         log( "Cannot secure server " + d->name +
517              " since " + group + " is not a valid group (says getgrnam())",
518              Log::Disaster );
519         exit( 1 );
520     }
521
522     EString cfn( d->configFile );
523     if ( cfn.isEmpty() )
524         cfn = Configuration::configFile();
525
526     struct stat st;
527     if ( stat( cfn.cstr(), &st ) < 0 ) {
528         log( "Cannot stat configuration file " + cfn,
529              Log::Disaster );
530         exit( 1 );
531     }
532     if ( st.st_uid != pw->pw_uid ) {
533         log( "Configuration file " + cfn +
534              " must be owned by " + user +
535              " (uid " + fn( pw->pw_uid ) + ")" +
536              " (is owned by uid " +
537              fn( st.st_uid ) + ")",
538              Log::Disaster );
539         exit( 1 );
540     }
541     if ( (gid_t)st.st_gid != (gid_t)gr->gr_gid ) {
542         log( "Configuration file " + cfn +
543              " must be in group " + user +
544              " (gid " + fn( gr->gr_gid ) + ")" +
545              " (is in gid " +
546              fn( st.st_gid ) + ")",
547              Log::Disaster );
548         exit( 1 );
549     }
550     if ( (st.st_mode & 027) != 0 ) {
551         log( "Configuration file " + cfn +
552              " must be readable for user " + user + "/group " + group +
553              " only (mode is " +
554              fn( st.st_mode & 0777, 8 ) + ", should be " +
555              fn( st.st_mode & 0740, 8 ) + ")",
556              Log::Disaster );
557         exit( 1 );
558     }
559
560     EString root;
561     switch ( d->chrootMode ) {
562     case MessageCopyDir:
563         root = Configuration::text( Configuration::MessageCopyDir );
564         break;
565     case JailDir:
566         root = Configuration::text( Configuration::JailDir );
567         break;
568     case TlsProxyDir:
569         root = Configuration::compiledIn( Configuration::LibDir );
570         if ( !root.endsWith( "/" ) )
571             root.append( "/" );
572         root.append( "tlsproxy" );
573         break;
574     case LogDir:
575         root = Configuration::text( Configuration::LogFile );
576         if ( root == "-" ) {
577             root = Configuration::text( Configuration::JailDir );
578         }
579         else if ( root.startsWith( "syslog/" ) ) {
580             root = "/";
581         }
582         else {
583             uint i = root.length();
584             while ( i > 0 && root[i] != '/' )
585                 i--;
586             if ( i == 0 ) {
587                 log( "Cannot secure server " + d->name +
588                      " since logfile does not contain '/'",
589                      Log::Disaster );
590                 log( "Value of logfile: " + root, Log::Info );
591                 exit( 1 );
592             }
593             root.truncate( i );
594         }
595         break;
596     }
597     if ( chroot( root.cstr() ) ) {
598         log( "Cannot secure server " + d->name + " since chroot( \"" +
599              root + "\" ) failed with error " + fn( errno ),
600              Log::Disaster );
601         exit( 1 );
602     }
603     if ( chdir( "/" ) ) {
604         log( "Cannot secure server " + d->name + " since chdir( \"/\" ) "
605              "failed in jail directory (\"" + root + "\") with error " +
606              fn( errno ),
607              Log::Disaster );
608         exit( 1 );
609     }
610     File::setRoot( root );
611
612     if ( setregid( gr->gr_gid, gr->gr_gid ) ) {
613         log( "Cannot secure server " + d->name + " since setregid( " +
614              fn( gr->gr_gid ) + ", " + fn( gr->gr_gid ) + " ) "
615              "failed with error " + fn( errno ),
616              Log::Disaster );
617         exit( 1 );
618     }
619
620     if ( setgroups( 1, (gid_t*)&(gr->gr_gid) ) ) {
621         log( "Cannot secure server " + d->name + " since setgroups( 1, [" +
622              fn( gr->gr_gid ) + "] ) failed with error " + fn( errno ),
623              Log::Disaster );
624         exit( 1 );
625     }
626
627     if ( setreuid( pw->pw_uid, pw->pw_uid ) ) {
628         log( "Cannot secure server " + d->name + " since setreuid( " +
629              fn( pw->pw_uid ) + ", " + fn( pw->pw_uid ) + " ) "
630              "failed with error " + fn( errno ),
631              Log::Disaster );
632         exit( 1 );
633     }
634
635     if ( d->chrootMode == JailDir ) {
636         // check that the jail directory really is a jail
637         DIR * slash = opendir( "/" ); // checks 'x' access
638         int fd = open( "/does/not/exist", O_RDONLY ); // checks 'r'
639         if ( slash || fd >= 0 || errno != EACCES ) {
640             log( "Cannot secure server " + d->name +
641                  " since jail directory " + root +
642                  " is accessible to user " + user,
643                  Log::Disaster );
644             exit( 1 );
645         }
646         if ( fd >= 0 ) {
647         }
648     }
649
650     // one final check...
651     if ( geteuid() != pw->pw_uid || getuid() != pw->pw_uid ) {
652         log( "Cannot secure server " + d->name +
653              " since setreuid() failed. Desired uid " +
654              fn( pw->pw_uid ) + ", got uid " + fn( getuid() ) +
655              " and euid " + fn( geteuid() ),
656              Log::Disaster );
657         exit( 1 );
658     }
659
660     // success
661     log( "Secured server " + d->name + " using jail directory " + root +
662          ", uid " + fn( pw->pw_uid ) + ", gid " + fn( gr->gr_gid ) );
663     d->secured = true;
664 }
665
666
667 /*! Finishes setup and runs the main loop of the server. */
668
669 void Server::run()
670 {
671     setup( Finish );
672     Configuration::report();
673
674     uint listeners = 0;
675     List< Connection >::Iterator it( EventLoop::global()->connections() );
676     while ( it ) {
677         if ( it->type() == Connection::Listener )
678             listeners++;
679         ++it;
680     }
681
682     if ( listeners == 0 ) {
683         log( "No active listeners. " + d->name + " exiting.", Log::Disaster );
684         exit( 1 );
685     }
686
687     if ( Scope::current()->log()->disastersYet() ) {
688         log( "Aborting server " + d->name + " due to earlier problems." );
689         exit( 1 );
690     }
691
692     dup2( 0, 1 );
693     if ( d->fork )
694         dup2( 0, 2 );
695     EventLoop::global()->start();
696
697     if ( Scope::current()->log()->disastersYet() )
698         exit( 1 );
699     exit( 0 );
700 }
701
702
703 /*! This static function returns the name of the application.
704     Is server the right way to publicise this name?
705 */
706
707 EString Server::name()
708 {
709     if ( d )
710         return d->name;
711     return "";
712 }
713
714
715 /*! Returns true if this server is configured to cache this and that,
716     and false if it shouldn't cache.
717
718     Running without cache is a debugging aid.
719 */
720
721
722 bool Server::useCache()
723 {
724     if ( d )
725         return d->useCache;
726     return false;
727 }