citadel
About: Citadel is an advanced messaging and collaboration system for groupware and BBS applications (preferred OS: Linux).
  Fossies Dox: citadel.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

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