"Fossies" - the Fresh Open Source Software Archive

Member "citadel/server_main.c" (5 Jun 2021, 9198 Bytes) of package /linux/www/citadel.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "server_main.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 9.01_vs_902.

    1 // citserver's main() function lives here.
    2 // 
    3 // Copyright (c) 1987-2021 by the citadel.org team
    4 //
    5 // This program is open source software; you can redistribute it and/or modify
    6 // it under the terms of the GNU General Public License version 3.
    7 //
    8 // This program is distributed in the hope that it will be useful,
    9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
   10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   11 // GNU General Public License for more details.
   12 
   13 #include <stdlib.h>
   14 #include <unistd.h>
   15 #include <stdio.h>
   16 #include <sys/types.h>
   17 #include <sys/stat.h>
   18 #include <grp.h>
   19 #include <sys/file.h>
   20 #include <libcitadel.h>
   21 #include "citserver.h"
   22 #include "svn_revision.h"
   23 #include "modules_init.h"
   24 #include "config.h"
   25 #include "control.h"
   26 #include "serv_extensions.h"
   27 #include "citadel_dirs.h"
   28 #include "user_ops.h"
   29 
   30 uid_t ctdluid = 0;
   31 const char *CitadelServiceUDS="citadel-UDS";
   32 const char *CitadelServiceTCP="citadel-TCP";
   33 int sanity_diag_mode = 0;
   34 
   35 
   36 /*
   37  * Create or remove a lock file, so we only have one Citadel Server running at a time.
   38  * Set 'op' to nonzero to lock, zero to unlock.
   39  */
   40 void ctdl_lockfile(int op) {
   41     static char lockfilename[PATH_MAX];
   42     static FILE *fp;
   43 
   44     if (op) {
   45         syslog(LOG_DEBUG, "main: creating lockfile");
   46         snprintf(lockfilename, sizeof lockfilename, "%s/citadel.lock", ctdl_run_dir);
   47         fp = fopen(lockfilename, "w");
   48         if (!fp) {
   49             syslog(LOG_ERR, "%s: %m", lockfilename);
   50             exit(CTDLEXIT_DB);
   51         }
   52         if (flock(fileno(fp), (LOCK_EX|LOCK_NB)) != 0) {
   53             syslog(LOG_ERR, "main: cannot lock %s , is another citserver running?", lockfilename);
   54             exit(CTDLEXIT_DB);
   55         }
   56         return;
   57     }
   58 
   59     syslog(LOG_DEBUG, "main: removing lockfile");
   60     unlink(lockfilename);
   61     flock(fileno(fp), LOCK_UN);
   62     fclose(fp);
   63 }
   64 
   65 
   66 /*
   67  * Here's where it all begins.
   68  */
   69 int main(int argc, char **argv) {
   70 
   71     char facility[32];
   72     int a;          // General-purpose variables
   73     struct passwd pw, *pwp = NULL;
   74     char pwbuf[SIZ];
   75     int drop_root_perms = 1;
   76     int max_log_level = LOG_INFO;
   77     char *ctdldir = CTDLDIR;
   78     int syslog_facility = LOG_DAEMON;
   79     uid_t u = 0;
   80     struct passwd *p = NULL;
   81 #ifdef HAVE_RUN_DIR
   82     struct stat filestats;
   83 #endif
   84 
   85     /* Tell 'em who's in da house */
   86     syslog(LOG_INFO, " ");
   87     syslog(LOG_INFO, " ");
   88     syslog(LOG_INFO, "*** Citadel server engine ***\n");
   89     syslog(LOG_INFO, "Version %d (build %s) ***", REV_LEVEL, svn_revision());
   90     syslog(LOG_INFO, "Copyright (C) 1987-2021 by the Citadel development team.");
   91     syslog(LOG_INFO, " ");
   92     syslog(LOG_INFO, "This program is open source software: you can redistribute it and/or");
   93     syslog(LOG_INFO, "modify it under the terms of the GNU General Public License, version 3.");
   94     syslog(LOG_INFO, " ");
   95     syslog(LOG_INFO, "This program is distributed in the hope that it will be useful,");
   96     syslog(LOG_INFO, "but WITHOUT ANY WARRANTY; without even the implied warranty of");
   97     syslog(LOG_INFO, "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the");
   98     syslog(LOG_INFO, "GNU General Public License for more details.");
   99     syslog(LOG_INFO, " ");
  100     syslog(LOG_INFO, "%s", libcitadel_version_string());
  101 
  102     /* parse command-line arguments */
  103     while ((a=getopt(argc, argv, "cl:dh:x:t:B:Dru:s:")) != EOF) switch(a) {
  104 
  105         // test this binary for compatibility and exit
  106         case 'c':
  107             fprintf(stderr, "%s: binary compatibility confirmed\n", argv[0]);
  108             exit(0);
  109             break;
  110 
  111         // identify the desired syslog facility
  112         case 'l':
  113             safestrncpy(facility, optarg, sizeof(facility));
  114             syslog_facility = SyslogFacility(facility);
  115             break;
  116 
  117         // run in the background if -d was specified
  118         case 'd':
  119             running_as_daemon = 1;
  120             break;
  121 
  122         // specify the data directory
  123         case 'h':
  124             ctdldir = optarg;
  125             break;
  126 
  127         // identify the desired logging severity level
  128         case 'x':
  129             max_log_level = atoi(optarg);
  130             break;
  131 
  132         // deprecated
  133         case 't':
  134             break;
  135 
  136         // deprecated
  137                 case 'B':
  138                         break;
  139 
  140         // deprecated
  141         case 'D':
  142             break;
  143 
  144         // -r tells the server not to drop root permissions.
  145         // Don't use this unless you know what you're doing.
  146         case 'r':
  147             drop_root_perms = 0;
  148             break;
  149 
  150         // -u tells the server what uid to run under...
  151         case 'u':
  152             u = atoi(optarg);
  153             if (u > 0) {
  154                 ctdluid = u;
  155             }
  156             else {
  157                 p = getpwnam(optarg);
  158                 if (p) {
  159                     u = p->pw_uid;
  160                 }
  161             }
  162             if (u > 0) {
  163                 ctdluid = u;
  164             }
  165             break;
  166 
  167         // -s tells the server to behave differently during sanity checks
  168         case 's':
  169             sanity_diag_mode = atoi(optarg);
  170             break;
  171 
  172         // any other parameter makes it crash and burn
  173         default:
  174             fprintf(stderr, "citserver: usage: "
  175                     "citserver "
  176                     "[-l LogFacility] "
  177                     "[-x MaxLogLevel] "
  178                     "[-d] [-r] "
  179                     "[-u user] "
  180                     "[-h HomeDir]\n"
  181             );
  182             exit(1);
  183     }
  184 
  185     if (chdir(ctdldir) != 0) {
  186         syslog(LOG_ERR, "main: unable to change directory to [%s]: %m", ctdldir);
  187         exit(CTDLEXIT_HOME);
  188     }
  189     else {
  190         syslog(LOG_INFO, "main: running in data directory %s", ctdldir);
  191     }
  192 
  193     if ((ctdluid == 0) && (drop_root_perms == 0)) {
  194         fprintf(stderr, "citserver: cannot determine user to run as; please specify -r or -u options\n");
  195         exit(CTDLEXIT_UNUSER);
  196     }
  197 
  198     /* Last ditch effort to determine the user name ... if there's a user called "citadel" then use that */
  199     if (ctdluid == 0) {
  200         p = getpwnam("citadel");
  201         if (!p) {
  202             p = getpwnam("bbs");
  203         }
  204         if (!p) {
  205             p = getpwnam("guest");
  206         }
  207         if (p) {
  208             u = p->pw_uid;
  209         }
  210         if (u > 0) {
  211             ctdluid = u;
  212         }
  213     }
  214 
  215     /* initialize the master context */
  216     InitializeMasterCC();
  217     InitializeMasterTSD();
  218 
  219     setlogmask(LOG_UPTO(max_log_level));
  220     openlog("citserver",
  221         ( running_as_daemon ? (LOG_PID) : (LOG_PID | LOG_PERROR) ),
  222         syslog_facility
  223     );
  224 
  225     /* daemonize, if we were asked to */
  226     if (running_as_daemon) {
  227         start_daemon(0);
  228         drop_root_perms = 1;
  229     }
  230 
  231     if ((mkdir(ctdl_run_dir, 0755) != 0) && (errno != EEXIST)) {
  232         syslog(LOG_ERR, "main: unable to create run directory [%s]: %m", ctdl_run_dir);
  233     }
  234 
  235     if (chown(ctdl_run_dir, ctdluid, (pwp==NULL)?-1:pw.pw_gid) != 0) {
  236         syslog(LOG_ERR, "main: unable to set the access rights for [%s]: %m", ctdl_run_dir);
  237     }
  238 
  239     ctdl_lockfile(1);
  240     init_sysdep();                      // Initialize...
  241     master_startup();                   // Do non system dependent startup functions
  242     check_control();                    // Check/sanitize/initialize control record, fix user indexes
  243     syslog(LOG_INFO, "main: upgrading modules");        // Run any upgrade entry points
  244     upgrade_modules();
  245 
  246     /*
  247      * Load the user for the masterCC or create them if they don't exist
  248      */
  249     if (CtdlGetUser(&masterCC.user, "SYS_Citadel")) {
  250         /* User doesn't exist. We can't use create user here as the user number needs to be 0 */
  251         strcpy (masterCC.user.fullname, "SYS_Citadel") ;
  252         CtdlPutUser(&masterCC.user);
  253         CtdlGetUser(&masterCC.user, "SYS_Citadel"); /* Just to be safe */
  254     }
  255     
  256     /*
  257      * Bind the server to a Unix-domain socket (user client access)
  258      */
  259     CtdlRegisterServiceHook(0,
  260                 file_citadel_socket,
  261                 citproto_begin_session,
  262                 do_command_loop,
  263                 do_async_loop,
  264                 CitadelServiceUDS);
  265 
  266     /*
  267      * Bind the server to a Unix-domain socket (admin client access)
  268      */
  269     CtdlRegisterServiceHook(0,
  270                 file_citadel_admin_socket,
  271                 citproto_begin_admin_session,
  272                 do_command_loop,
  273                 do_async_loop,
  274                 CitadelServiceUDS);
  275     chmod(file_citadel_admin_socket, S_IRWXU);  /* for your eyes only */
  276 
  277     /*
  278      * Bind the server to our favorite TCP port (usually 504).
  279      */
  280     CtdlRegisterServiceHook(CtdlGetConfigInt("c_port_number"),
  281                 NULL,
  282                 citproto_begin_session,
  283                 do_command_loop,
  284                 do_async_loop,
  285                 CitadelServiceTCP);
  286 
  287     /*
  288      * Load any server-side extensions available here.
  289      */
  290     syslog(LOG_INFO, "main: initializing server extensions");
  291     initialise_modules(0);
  292 
  293     /*
  294      * If we need host auth, start our chkpwd daemon.
  295      */
  296     if (CtdlGetConfigInt("c_auth_mode") == AUTHMODE_HOST) {
  297         start_chkpwd_daemon();
  298     }
  299 
  300     /*
  301      * check, whether we're fired up another time after a crash.
  302      * if, post an aide message, so the admin has a chance to react.
  303      */
  304     checkcrash();
  305 
  306     /*
  307      * Now that we've bound the sockets, change to the Citadel user id and its corresponding group ids
  308      */
  309     if (drop_root_perms) {
  310         cdb_chmod_data();   /* make sure we own our data files */
  311         getpwuid_r(ctdluid, &pw, pwbuf, sizeof(pwbuf), &pwp);
  312         if (pwp == NULL)
  313             syslog(LOG_ERR, "main: WARNING, getpwuid(%ld): %m Group IDs will be incorrect.", (long)CTDLUID);
  314         else {
  315             initgroups(pw.pw_name, pw.pw_gid);
  316             if (setgid(pw.pw_gid)) {
  317                 syslog(LOG_ERR, "main: setgid(%ld): %m", (long)pw.pw_gid);
  318             }
  319         }
  320         syslog(LOG_INFO, "main: changing uid to %ld", (long)CTDLUID);
  321         if (setuid(CTDLUID) != 0) {
  322             syslog(LOG_ERR, "main: setuid() failed: %m");
  323         }
  324 #if defined (HAVE_SYS_PRCTL_H) && defined (PR_SET_DUMPABLE)
  325         prctl(PR_SET_DUMPABLE, 1);
  326 #endif
  327     }
  328 
  329     /* We want to check for idle sessions once per minute */
  330     CtdlRegisterSessionHook(terminate_idle_sessions, EVT_TIMER, PRIO_CLEANUP + 1);
  331 
  332     /* Go into multithreaded mode.  When this call exits, the server is stopping. */
  333     go_threading();
  334     
  335     /* Get ready to shut down the server. */
  336     int exit_code = master_cleanup(exit_signal);
  337     ctdl_lockfile(0);
  338     if (restart_server) {
  339         syslog(LOG_INFO, "main: *** CITADEL SERVER IS RESTARTING ***");
  340         execv(argv[0], argv);
  341     }
  342     return(exit_code);
  343 }