/[svn]/vendor/ircservices-5.1.24/init.c
ViewVC logotype

Annotation of /vendor/ircservices-5.1.24/init.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3389 - (hide annotations)
Fri Apr 25 14:12:15 2014 UTC (6 years, 3 months ago) by michael
File MIME type: text/x-chdr
File size: 46932 byte(s)
- Imported ircservices-5.1.24

1 michael 3389 /* Initalization and related routines.
2     *
3     * IRC Services is copyright (c) 1996-2009 Andrew Church.
4     * E-mail: <achurch@achurch.org>
5     * Parts written by Andrew Kempe and others.
6     * This program is free but copyrighted software; see the file GPL.txt for
7     * details.
8     */
9    
10     #include "services.h"
11     #include "conffile.h"
12     #include "databases.h"
13     #include "messages.h"
14     #include "modules.h"
15     #include "language.h"
16     #include "version.h"
17    
18     #if HAVE_SETGRENT
19     # include <grp.h>
20     #endif
21     #if HAVE_UMASK
22     # include <sys/stat.h> /* for umask() on some systems */
23     #endif
24     #if HAVE_GETSETRLIMIT
25     # include <sys/resource.h>
26     #endif
27    
28     /*************************************************************************/
29    
30     /* Callbacks used in this file: */
31     static int cb_introduce_user = -1;
32     static int cb_cmdline = -1;
33    
34     /*************************************************************************/
35     /************************* Configuration options *************************/
36     /*************************************************************************/
37    
38     /* Configurable variables: */
39    
40     char **LoadModules;
41     int LoadModules_count;
42     char **LoadLanguageText;
43     int LoadLanguageText_count;
44    
45     char * RemoteServer;
46     int32 RemotePort;
47     char * RemotePassword;
48     char * LocalHost;
49     int32 LocalPort;
50    
51     char * ServerName;
52     char * ServerDesc;
53     char * ServiceUser;
54     char * ServiceHost;
55    
56     char * LogFilename;
57     char PIDFilename[PATH_MAX+1];
58     char * MOTDFilename;
59     char * LockFilename;
60    
61     int16 DefTimeZone;
62    
63     int NoBouncyModes;
64     int NoSplitRecovery;
65     int StrictPasswords;
66     int NoAdminPasswordCheck;
67     int32 BadPassLimit;
68     time_t BadPassTimeout;
69     int32 BadPassWarning;
70     int32 IgnoreDecay;
71     double IgnoreThreshold;
72     time_t UpdateTimeout;
73     time_t WarningTimeout;
74     int32 ReadTimeout;
75     int32 TimeoutCheck;
76     time_t PingFrequency;
77     int32 MergeChannelModes;
78     int32 TotalNetBufferSize;
79     int32 NetBufferSize;
80     int32 NetBufferLimitInactive;
81     int32 NetBufferLimitIgnore;
82    
83     char * EncryptionType;
84     char * GuestNickPrefix;
85     char **RejectEmail;
86     int RejectEmail_count;
87     int32 ListMax;
88     int LogMaxUsers;
89     int EnableGetpass;
90     int WallAdminPrivs;
91    
92     /* Routines to handle special directives: */
93     static int do_DefTimeZone(const char *filename, int linenum, char *param);
94     static int do_IgnoreThreshold(const char *filename, int linenum, char *param);
95     static int do_LoadLanguageText(const char *filename, int linenum, char *param);
96     static int do_LoadModule(const char *filename, int linenum, char *param);
97     static int do_PIDFilename(const char *filename, int linenum, char *param);
98     static int do_RejectEmail(const char *filename, int linenum, char *param);
99     static int do_RunGroup(const char *filename, int linenum, char *param);
100     static int do_ServiceUser(const char *filename, int linenum, char *param);
101     static int do_Umask(const char *filename, int linenum, char *param);
102    
103     /*************************************************************************/
104    
105     /* List of directives for ircservices.conf (main configuration file): */
106    
107     static ConfigDirective main_directives[] = {
108     { "BadPassLimit", { { CD_POSINT, 0, &BadPassLimit } } },
109     { "BadPassTimeout", { { CD_TIME, 0, &BadPassTimeout } } },
110     { "BadPassWarning", { { CD_POSINT, 0, &BadPassWarning } } },
111     { "DefTimeZone", { { CD_FUNC, 0, do_DefTimeZone } } },
112     { "EnableGetpass", { { CD_SET, 0, &EnableGetpass } } },
113     { "EncryptionType", { { CD_STRING, 0, &EncryptionType } } },
114     { "ExpireTimeout", { { CD_DEPRECATED, 0 } } },
115     { "GuestNickPrefix", { { CD_STRING, CF_DIRREQ, &GuestNickPrefix } } },
116     { "IgnoreDecay", { { CD_TIMEMSEC, 0, &IgnoreDecay } } },
117     { "IgnoreThreshold", { { CD_FUNC, 0, do_IgnoreThreshold } } },
118     { "ListMax", { { CD_POSINT, CF_DIRREQ, &ListMax } } },
119     { "LoadLanguageText", { { CD_FUNC, 0, do_LoadLanguageText } } },
120     { "LoadModule", { { CD_FUNC, 0, do_LoadModule } } },
121     { "LocalAddress", { { CD_STRING, 0, &LocalHost },
122     { CD_PORT, CF_OPTIONAL, &LocalPort } } },
123     { "LockFilename", { { CD_STRING, CF_DIRREQ, &LockFilename } } },
124     { "LogFilename", { { CD_STRING, CF_DIRREQ, &LogFilename } } },
125     { "LogMaxUsers", { { CD_SET, 0, &LogMaxUsers } } },
126     { "MergeChannelModes",{ { CD_TIMEMSEC, 0, &MergeChannelModes } } },
127     { "MOTDFilename", { { CD_STRING, CF_DIRREQ, &MOTDFilename } } },
128     { "NetBufferLimit", { { CD_POSINT, 0, &NetBufferLimitInactive },
129     { CD_POSINT, CF_OPTIONAL, &NetBufferLimitIgnore}}},
130     { "NetBufferSize", { { CD_POSINT, 0, &TotalNetBufferSize },
131     { CD_POSINT, CF_OPTIONAL, &NetBufferSize } } },
132     { "NoAdminPasswordCheck",{{CD_SET, 0, &NoAdminPasswordCheck } } },
133     { "NoBouncyModes", { { CD_SET, 0, &NoBouncyModes } } },
134     { "NoSplitRecovery", { { CD_SET, 0, &NoSplitRecovery } } },
135     { "PIDFilename", { { CD_FUNC, 0, do_PIDFilename } } },
136     { "PingFrequency", { { CD_TIME, 0, &PingFrequency } } },
137     { "ReadTimeout", { { CD_TIMEMSEC, 0, &ReadTimeout } } },
138     { "RejectEmail", { { CD_FUNC, 0, do_RejectEmail } } },
139     { "RemoteServer", { { CD_STRING, CF_DIRREQ, &RemoteServer },
140     { CD_PORT, 0, &RemotePort },
141     { CD_STRING, 0, &RemotePassword } } },
142     { "RunGroup", { { CD_FUNC, 0, do_RunGroup } } },
143     { "ServerDesc", { { CD_STRING, CF_DIRREQ, &ServerDesc } } },
144     { "ServerName", { { CD_STRING, CF_DIRREQ, &ServerName } } },
145     { "ServiceUser", { { CD_FUNC, CF_DIRREQ, do_ServiceUser } } },
146     { "StrictPasswords", { { CD_SET, 0, &StrictPasswords } } },
147     { "TimeoutCheck", { { CD_TIMEMSEC, CF_DIRREQ, &TimeoutCheck } } },
148     { "Umask", { { CD_FUNC, 0, do_Umask } } },
149     { "UpdateTimeout", { { CD_TIME, CF_DIRREQ, &UpdateTimeout } } },
150     { "WallAdminPrivs", { { CD_SET, 0, &WallAdminPrivs } } },
151     { "WarningTimeout", { { CD_TIME, CF_DIRREQ, &WarningTimeout } } },
152     { NULL }
153     };
154    
155     /*************************************************************************/
156    
157     /* read_config(): Read the main configuration file. If an error occurs
158     * while reading the file or a required directive is not
159     * found, print and log an appropriate error message and
160     * return 0; otherwise, return 1.
161     */
162    
163     static int read_config(void)
164     {
165     int retval = 1;
166    
167     if (!configure(NULL, main_directives, CONFIGURE_READ | CONFIGURE_SET))
168     return 0;
169    
170     if (TotalNetBufferSize) {
171     if (TotalNetBufferSize < SOCK_MIN_BUFSIZE*2) {
172     config_error(IRCSERVICES_CONF, 0,
173     "Buffer size limit for NetBufferSize must be at"
174     " least %d", SOCK_MIN_BUFSIZE*2);
175     retval = 0;
176     } else {
177     /* Make sure it's a multiple of SOCK_MIN_BUFSIZE */
178     TotalNetBufferSize /= SOCK_MIN_BUFSIZE;
179     TotalNetBufferSize *= SOCK_MIN_BUFSIZE;
180     if (NetBufferSize) {
181     if (NetBufferSize < SOCK_MIN_BUFSIZE*2) {
182     config_error(IRCSERVICES_CONF, 0,
183     "Per-connection buffer size limit for"
184     " NetBufferSize must be at least %d",
185     SOCK_MIN_BUFSIZE*2);
186     retval = 0;
187     } else if (NetBufferSize > TotalNetBufferSize) {
188     config_error(IRCSERVICES_CONF, 0,
189     "Per-connection buffer size limit for"
190     " NetBufferSize must be no more than total"
191     " limit");
192     retval = 0;
193     } else {
194     NetBufferSize /= SOCK_MIN_BUFSIZE;
195     NetBufferSize *= SOCK_MIN_BUFSIZE;
196     }
197     }
198     }
199     } /* if (TotalNetBufferSize) */
200    
201     if (NetBufferLimitInactive) {
202     if (!TotalNetBufferSize) {
203     NetBufferLimitInactive = NetBufferLimitIgnore = 0;
204     } else {
205     if (NetBufferLimitInactive > 99 || NetBufferLimitIgnore > 99) {
206     config_error(IRCSERVICES_CONF, 0,
207     "Thresholds for NetBufferLimit must be between"
208     " 1 and 99 inclusive");
209     retval = 0;
210     }
211     if (NetBufferLimitIgnore
212     && NetBufferLimitIgnore < NetBufferLimitInactive
213     ) {
214     config_error(IRCSERVICES_CONF, 0,
215     "Ignore threshold for NetBufferLimit must be"
216     " greater than or equal to inactive threshold");
217     retval = 0;
218     }
219     }
220     }
221    
222     return retval;
223     }
224    
225     /*************************************************************************/
226     /*************************************************************************/
227    
228     /* Configuration directive callback functions: */
229    
230     /*************************************************************************/
231    
232     #define TZ_MAXLEN 16
233    
234     static int do_DefTimeZone(const char *filename, int linenum, char *param)
235     {
236     static const char *origTZ = NULL;
237     static char newTZ[TZ_MAXLEN+1];
238     static char tzbuf[TZ_MAXLEN+4]; /* for setting TZ */
239    
240     if (!filename) {
241     switch (linenum) {
242     case CDFUNC_INIT:
243     /* Prepare for reading config file */
244     *newTZ = 0;
245     if (!origTZ) {
246     /* Obtain current value of TZ environment variable (once
247     * only, at start of program), and truncate to TZ_MAXLEN */
248     origTZ = getenv("TZ");
249     if (!origTZ)
250     origTZ = "";
251     if (strlen(origTZ) > TZ_MAXLEN) {
252     static char new_origTZ[TZ_MAXLEN+1];
253     memcpy(new_origTZ, origTZ, TZ_MAXLEN);
254     new_origTZ[TZ_MAXLEN] = 0;
255     origTZ = new_origTZ;
256     }
257     }
258     break;
259     case CDFUNC_SET:
260     /* Copy data to config variables */
261     if (!origTZ) {
262     log("BUG: origTZ not set in do_DefTimeZone/CDFUNC_SET");
263     break;
264     }
265     snprintf(tzbuf, sizeof(tzbuf), "TZ=%s", *newTZ ? newTZ : origTZ);
266     if (putenv(tzbuf) < 0) {
267     log("Warning: putenv(%s) failed, time zone may be incorrect",
268     tzbuf);
269     }
270     break;
271     case CDFUNC_DECONFIG:
272     /* Reset to initial values */
273     if (!origTZ) {
274     log("BUG: origTZ not set in do_DefTimeZone/CDFUNC_DECONFIG");
275     break;
276     }
277     snprintf(tzbuf, sizeof(tzbuf), "TZ=%s", origTZ);
278     if (putenv(tzbuf) < 0) {
279     log("Warning: putenv(%s) failed, time zone may be incorrect",
280     tzbuf);
281     }
282     break;
283     } /* switch (linenum) */
284     } else { /* filename != NULL, process parameter */
285     if (strlen(param) > TZ_MAXLEN) {
286     config_error(filename, linenum, "DefTimeZone parameter must not"
287     " be longer than %d characters", TZ_MAXLEN);
288     return 0;
289     } else {
290     strbcpy(newTZ, param);
291     }
292     }
293     return 1;
294     }
295    
296     /*************************************************************************/
297    
298     static int do_IgnoreThreshold(const char *filename, int linenum, char *param)
299     {
300     static double new_IgnoreThreshold = 0;
301    
302     if (filename) {
303     new_IgnoreThreshold = strtod(param, &param);
304     if (*param || new_IgnoreThreshold <= 0) {
305     config_error(filename, linenum, "Parameter for IgnoreThreshold"
306     " must be a positive number");
307     return 0;
308     }
309     } else if (linenum == CDFUNC_INIT) {
310     new_IgnoreThreshold = 0;
311     } else if (linenum == CDFUNC_SET) {
312     IgnoreThreshold = new_IgnoreThreshold;
313     } else if (linenum == CDFUNC_DECONFIG) {
314     IgnoreThreshold = 0;
315     }
316     return 1;
317     }
318    
319     /*************************************************************************/
320    
321     static int do_LoadLanguageText(const char *filename, int linenum, char *param)
322     {
323     static char **new_LoadLanguageText = NULL;
324     static int new_LoadLanguageText_count = 0;
325     int i;
326    
327     if (!filename) {
328     switch (linenum) {
329     case CDFUNC_INIT:
330     /* Prepare for reading config file: clear out "new" array */
331     ARRAY_FOREACH (i, new_LoadLanguageText)
332     free(new_LoadLanguageText[i]);
333     free(new_LoadLanguageText);
334     new_LoadLanguageText = NULL;
335     new_LoadLanguageText_count = 0;
336     break;
337     case CDFUNC_SET:
338     /* Copy data to config variables */
339     ARRAY_FOREACH (i, LoadLanguageText)
340     free(LoadLanguageText[i]);
341     free(LoadLanguageText);
342     LoadLanguageText = new_LoadLanguageText;
343     LoadLanguageText_count = new_LoadLanguageText_count;
344     new_LoadLanguageText = NULL;
345     new_LoadLanguageText_count = 0;
346     break;
347     case CDFUNC_DECONFIG:
348     /* Clear out config variables */
349     ARRAY_FOREACH (i, LoadLanguageText)
350     free(LoadLanguageText[i]);
351     free(LoadLanguageText);
352     LoadLanguageText = NULL;
353     LoadLanguageText_count = 0;
354     break;
355     }
356     return 1;
357     } /* if (!filename) */
358    
359     /* We can't use ARRAY_EXTEND because SIGUSR1 (for srealloc()) may not
360     * be ready yet */
361     if (new_LoadLanguageText_count+1 < new_LoadLanguageText_count) {
362     config_error(filename, linenum, "LoadLanguageText: too many files!");
363     return 0;
364     }
365     new_LoadLanguageText = realloc(new_LoadLanguageText,
366     sizeof(char *) * (new_LoadLanguageText_count+1));
367     param = strdup(param);
368     if (!new_LoadLanguageText || !param) {
369     config_error(filename, linenum, "LoadLanguageText: out of memory!");
370     return 0;
371     }
372     new_LoadLanguageText[new_LoadLanguageText_count++] = param;
373     return 1;
374     }
375    
376     /*************************************************************************/
377    
378     static int do_LoadModule(const char *filename, int linenum, char *param)
379     {
380     static char **new_LoadModules = NULL;
381     static int new_LoadModules_count = 0;
382     int i;
383    
384     if (!filename) {
385     switch (linenum) {
386     case CDFUNC_INIT:
387     /* Prepare for reading config file: clear out "new" array */
388     ARRAY_FOREACH (i, new_LoadModules)
389     free(new_LoadModules[i]);
390     free(new_LoadModules);
391     new_LoadModules = NULL;
392     new_LoadModules_count = 0;
393     break;
394     case CDFUNC_SET:
395     /* Copy data to config variables */
396     ARRAY_FOREACH (i, LoadModules)
397     free(LoadModules[i]);
398     free(LoadModules);
399     LoadModules = new_LoadModules;
400     LoadModules_count = new_LoadModules_count;
401     new_LoadModules = NULL;
402     new_LoadModules_count = 0;
403     break;
404     case CDFUNC_DECONFIG:
405     /* Clear out config variables */
406     ARRAY_FOREACH (i, LoadModules)
407     free(LoadModules[i]);
408     free(LoadModules);
409     LoadModules = NULL;
410     LoadModules_count = 0;
411     break;
412     }
413     return 1;
414     } /* if (!filename) */
415    
416     /* We can't use ARRAY_EXTEND because SIGUSR1 (for srealloc()) may not
417     * be ready yet */
418     if (new_LoadModules_count+1 < new_LoadModules_count) {
419     config_error(filename, linenum, "LoadModule: too many modules!");
420     return 0;
421     }
422     new_LoadModules = realloc(new_LoadModules,
423     sizeof(char *) * (new_LoadModules_count+1));
424     param = strdup(param);
425     if (!new_LoadModules || !param) {
426     config_error(filename, linenum, "LoadModule: out of memory!");
427     return 0;
428     }
429     new_LoadModules[new_LoadModules_count++] = param;
430     return 1;
431     }
432    
433     /*************************************************************************/
434    
435     static int do_PIDFilename(const char *filename, int linenum, char *param)
436     {
437     static char *new_PIDFilename = NULL;
438    
439     if (!filename) {
440     switch (linenum) {
441     case CDFUNC_INIT:
442     /* Prepare for reading config file */
443     free(new_PIDFilename);
444     new_PIDFilename = NULL;
445     break;
446     case CDFUNC_SET:
447     /* Copy data to config variables */
448     if (new_PIDFilename) {
449     strbcpy(PIDFilename, new_PIDFilename);
450     } else {
451     *PIDFilename = 0;
452     }
453     free(new_PIDFilename);
454     new_PIDFilename = NULL;
455     break;
456     case CDFUNC_DECONFIG:
457     /* Clear out config variables. For PIDFilename, however, we
458     * leave the value in place so the file can be removed on exit
459     * properly. */
460     break;
461     }
462     return 1;
463     } /* if (!filename) */
464    
465     if (strlen(param) >= sizeof(PIDFilename)) {
466     config_error(filename, linenum, "PIDFilename: Path too long");
467     return 0;
468     }
469     new_PIDFilename = strdup(param);
470     if (!new_PIDFilename) {
471     config_error(filename, linenum, "PIDFilename: Out of memory!");
472     return 0;
473     }
474     return 1;
475     }
476    
477     /*************************************************************************/
478    
479     static int do_RejectEmail(const char *filename, int linenum, char *param)
480     {
481     static char **new_RejectEmail = NULL;
482     static int new_RejectEmail_count = 0;
483     int i;
484    
485     if (!filename) {
486     switch (linenum) {
487     case CDFUNC_INIT:
488     /* Prepare for reading config file: clear out "new" array */
489     ARRAY_FOREACH (i, new_RejectEmail)
490     free(new_RejectEmail[i]);
491     free(new_RejectEmail);
492     new_RejectEmail = NULL;
493     new_RejectEmail_count = 0;
494     break;
495     case CDFUNC_SET:
496     /* Copy data to config variables */
497     ARRAY_FOREACH (i, RejectEmail)
498     free(RejectEmail[i]);
499     free(RejectEmail);
500     RejectEmail = new_RejectEmail;
501     RejectEmail_count = new_RejectEmail_count;
502     new_RejectEmail = NULL;
503     new_RejectEmail_count = 0;
504     break;
505     case CDFUNC_DECONFIG:
506     /* Clear out config variables */
507     ARRAY_FOREACH (i, RejectEmail)
508     free(RejectEmail[i]);
509     free(RejectEmail);
510     RejectEmail = NULL;
511     RejectEmail_count = 0;
512     break;
513     }
514     return 1;
515     } /* if (!filename) */
516    
517     ARRAY_EXTEND(new_RejectEmail);
518     new_RejectEmail[new_RejectEmail_count-1] = sstrdup(param);
519     return 1;
520     }
521    
522     /*************************************************************************/
523    
524     static int do_RunGroup(const char *filename, int linenum, char *param)
525     {
526     #ifndef SIZEOF_GID_T
527     config_error(filename, linenum,
528     "RunGroup: groups not supported on this system");
529     return 0;
530     #else
531     static gid_t groupnum = -1;
532     long tmp;
533    
534     if (filename) {
535    
536     if (*param == '=') {
537     if (!param[1]) {
538     config_error(filename, linenum,
539     "RunGroup: group number required after `='");
540     return 0;
541     }
542     errno = 0;
543     tmp = strtol(param+1, &param, 0);
544     # if SIZEOF_GID_T >= 4
545     if (errno == ERANGE)
546     # else
547     if (tmp < -32768 || tmp > 65535)
548     # endif
549     {
550     config_error(filename, linenum,
551     "RunGroup: group number out of range (0..%ld)",
552     # if SIZEOF_GID_T >= 4
553     0x7FFFFFFFL
554     # else
555     65535L
556     # endif
557     );
558     return 0;
559     }
560     groupnum = tmp;
561     } else { /* *param != '=' */
562     # if !HAVE_SETGRENT
563     config_error(filename, linenum,
564     "RunGroup: group names not supported on this system");
565     return 0;
566     # else
567     struct group *gr;
568     setgrent();
569     while ((gr = getgrent()) != NULL) {
570     if (strcmp(gr->gr_name, param) == 0)
571     break;
572     }
573     endgrent();
574     if (!gr) {
575     config_error(filename, linenum,
576     "RunGroup: unknown group `%s'", param);
577     return 0;
578     }
579     groupnum = gr->gr_gid;
580     # endif
581     }
582    
583     } else { /* !filename */
584    
585     # if HAVE_SETREGID
586     if (setregid(groupnum, groupnum) < 0) {
587     # else
588     if (setegid(groupnum) < 0 || setgid(groupnum) < 0) {
589     # endif
590     config_error(filename, linenum,
591     "RunGroup: unable to set group: %s", strerror(errno));
592     return 0;
593     }
594    
595     } /* if (filename) */
596    
597     return 1;
598    
599     #endif /* have gid_t? */
600     }
601    
602     /*************************************************************************/
603    
604     static int do_ServiceUser(const char *filename, int linenum, char *param)
605     {
606     char *s;
607     static char *new_ServiceUser = NULL, *new_ServiceHost = NULL;
608    
609     if (filename) {
610     /* Make sure the string has an @ and there's at least one character
611     * on each side */
612     s = strchr(param, '@');
613     if (!s || s == param || s[1] == 0) {
614     config_error(filename, linenum,
615     "`user@host' string required for ServiceUser");
616     return 0;
617     }
618     /* Store user and hostname parts (after freeing any old ones) */
619     *s++ = 0;
620     free(new_ServiceUser);
621     free(new_ServiceHost);
622     new_ServiceUser = strdup(param);
623     new_ServiceHost = strdup(s);
624     if (!new_ServiceUser || !new_ServiceHost) {
625     free(new_ServiceUser); /* still alloc'ed if ServiceHost failed */
626     new_ServiceUser = NULL;
627     config_error(filename, linenum, "Out of memory");
628     return 0;
629     }
630     } else if (linenum == CDFUNC_SET) {
631     /* Copy new values to config variables and clear */
632     if (new_ServiceUser && new_ServiceHost) { /* paranoia */
633     free(ServiceUser);
634     free(ServiceHost);
635     ServiceUser = new_ServiceUser;
636     ServiceHost = new_ServiceHost;
637     } else {
638     free(new_ServiceUser);
639     free(new_ServiceHost);
640     }
641     new_ServiceUser = new_ServiceHost = NULL;
642     } else if (linenum == CDFUNC_DECONFIG) {
643     /* Reset to defaults */
644     free(ServiceUser);
645     free(ServiceHost);
646     ServiceUser = NULL;
647     ServiceHost = NULL;
648     }
649     return 1;
650     }
651    
652     /*************************************************************************/
653    
654     static int do_Umask(const char *filename, int linenum, char *param)
655     {
656     #if !HAVE_UMASK
657     config_error(filename, linenum, "Umask is not supported on this system");
658     return 0;
659     #else
660     char *s;
661     static int umask_val = -1;
662    
663     if (filename) {
664     umask_val = strtol(param, &s, 8);
665     if (*s || umask_val < 0 || umask_val > 0777) {
666     config_error(filename, linenum,
667     "Expected an octal value between 000 and 777");
668     return 0;
669     }
670     } else {
671     if (umask_val >= 0)
672     umask(umask_val);
673     umask_val = -1;
674     }
675     return 1;
676     #endif /* HAVE_UMASK */
677     }
678    
679     /*************************************************************************/
680     /*********************** Introducing pseudoclients ***********************/
681     /*************************************************************************/
682    
683     /* If `user' is the name of a Services pseudo-client, send a NICK command
684     * for that given pseudo-client. If `user' is NULL, send NICK commands for
685     * all the pseudo-clients. Return 1 if we sent a NICK command, else 0.
686     */
687    
688     int introduce_user(const char *user)
689     {
690     int retval;
691    
692     retval = call_callback_1(cb_introduce_user, user);
693     if (user == NULL) {
694     if (retval > 0)
695     log("introduce_user(): callback returned nonzero for user==NULL");
696     retval = 1;
697     }
698    
699     /* Watch out for infinite loops... */
700     if (retval) {
701     #define LTSIZE 20
702     static int lasttimes[LTSIZE];
703     if (lasttimes[0] >= time(NULL)-3)
704     fatal("introduce_user() loop detected");
705     memmove(lasttimes, lasttimes+1, sizeof(lasttimes)-sizeof(*lasttimes));
706     lasttimes[LTSIZE-1] = time(NULL);
707     #undef LTSIZE
708     }
709    
710     return retval;
711     }
712    
713     /*************************************************************************/
714     /************************* Command-line parsing **************************/
715     /*************************************************************************/
716    
717     /* Parse command-line options. If `call_modules' is zero, parse main
718     * options and ignore unrecognized ones; if nonzero, ignore main options,
719     * call "command line" callback to check module options, and fail on
720     * unrecognized ones. Return 0 if all went well, -1 for an error with an
721     * option, or 1 if Services should exit successfully. Calls exit(0) if
722     * "-help", "--help", or "-h" is present.
723     */
724    
725     static int parse_options(int ac, char **av, int call_modules)
726     {
727     int i;
728     char *s, *t;
729    
730     if (!call_modules) /* only initialize it once */
731     debug = 0;
732    
733     for (i = 1; i < ac; i++) {
734     s = av[i];
735     if (*s == '-') {
736     s++;
737     if (*s == '-')
738     s++;
739     if (strncmp(s, "dir", 3) == 0 && (!s[3] || s[3] == '=')) {
740     if (!call_modules) {
741     if (!s[3]) {
742     fprintf(stderr, "-dir requires a parameter\n");
743     return -1;
744     }
745     services_dir = s+4;
746     }
747     } else if (strncmp(s, "remote", 6) == 0 && (!s[6] || s[6]=='=')) {
748     if (!call_modules) {
749     if (!s[6]) {
750     fprintf(stderr, "-remote requires hostname[:port]\n");
751     return -1;
752     }
753     s += 7;
754     t = strchr(s, ':');
755     if (t) {
756     *t = 0;
757     if (atoi(t+1) > 0)
758     RemotePort = atoi(t+1);
759     else {
760     fprintf(stderr, "-remote: port number must be a"
761     " positive integer. Using default.\n");
762     return -1;
763     }
764     }
765     free(RemoteServer);
766     RemoteServer = strdup(s);
767     if (!RemoteServer) {
768     fprintf(stderr, "Out of memory\n");
769     exit(-1);
770     }
771     if (t) /* put the colon back for next time around */
772     *t = ':';
773     }
774     } else if (strncmp(s, "log", 3) == 0 && (!s[3] || s[3] == '=')) {
775     if (!call_modules) {
776     if (!s[3]) {
777     fprintf(stderr, "-log requires a parameter\n");
778     return -1;
779     }
780     free(LogFilename);
781     LogFilename = sstrdup(s+4);
782     }
783     } else if (strcmp(s, "debug") == 0) {
784     if (!call_modules)
785     debug++;
786     } else if (strcmp(s, "readonly") == 0) {
787     if (!call_modules)
788     readonly = 1;
789     } else if (strcmp(s, "nofork") == 0) {
790     if (!call_modules)
791     nofork = 1;
792     } else if (strcmp(s, "noexpire") == 0) {
793     if (!call_modules)
794     noexpire = 1;
795     } else if (strcmp(s, "noakill") == 0) {
796     if (!call_modules)
797     noakill = 1;
798     } else if (strcmp(s, "forceload") == 0) {
799     if (!call_modules)
800     forceload = 1;
801     } else if (strcmp(s, "encrypt-all") == 0) {
802     if (!call_modules)
803     encrypt_all = 1;
804     } else if (strcmp(s, "h") == 0 || strcmp(s, "help") == 0
805     || strcmp(s, "-help") == 0) {
806     fputs(
807     "The following options are recognized:\n"
808     " -dir=directory Directory containing Services' data files\n"
809     " (e.g. /usr/local/lib/ircservices)\n"
810     " -remote=server[:port] Remote server to connect to\n"
811     " -log=filename Services log filename (e.g. services.log)\n"
812     " -debug Enable debugging mode--more info sent to log\n"
813     " (give option more times for more info)\n"
814     " -readonly Enable read-only mode--no changes to\n"
815     " databases allowed, .db files and log\n"
816     " not written\n"
817     " -nofork Do not fork after startup; log messages will\n"
818     " be written to terminal (as well as to\n"
819     " the log file if not in read-only mode)\n"
820     " -noexpire Prevents all expirations (nicknames, channels,\n"
821     " akills, session limit exceptions, etc.)\n"
822     " -noakill Disables autokill checking\n"
823     " -forceload Try to load as much of the databases as\n"
824     " possible, even if errors are encountered\n"
825     " -encrypt-all Re-encrypt all passwords on startup\n"
826     "Other options may be available depending on loaded modules; see the manual\n"
827     "for details.\n"
828     , stdout);
829     exit(0);
830     } else if (call_modules) {
831     int res;
832     t = strchr(s, '=');
833     if (t)
834     *t++ = 0;
835     res = call_callback_2(cb_cmdline, s, t);
836     switch (res) {
837     case 0:
838     fprintf(stderr, "Unknown option -%s. Use \"-help\" for"
839     " help.\n", s);
840     return -1;
841     case 1:
842     break;
843     case 2:
844     return -1;
845     case 3:
846     return 1;
847     default:
848     log("init: bad return value (%d) from command line"
849     " callback for `-%s%s%s'", res, s, t ? "=" : "", t);
850     return -1;
851     }
852     }
853     } else {
854     fprintf(stderr, "Non-option arguments not allowed\n");
855     return -1;
856     }
857     }
858     return 0;
859     }
860    
861     /*************************************************************************/
862     /*************************** PID file handling ***************************/
863     /*************************************************************************/
864    
865     /* Remove our PID file. Done at exit. */
866    
867     static void remove_pidfile(void)
868     {
869     if (*PIDFilename)
870     remove(PIDFilename);
871     }
872    
873     /*************************************************************************/
874    
875     /* Create our PID file and write the PID to it. Returns nonzero on
876     * success, zero on failure.
877     */
878    
879     static int write_pidfile(void)
880     {
881     FILE *pidfile;
882    
883     pidfile = fopen(PIDFilename, "w");
884     if (!pidfile)
885     return 0;
886     fprintf(pidfile, "%d\n", (int)getpid());
887     fclose(pidfile);
888     atexit(remove_pidfile);
889     return 1;
890     }
891    
892     /*************************************************************************/
893     /********************** Main initialization routine **********************/
894     /*************************************************************************/
895    
896     /* Overall initialization routine. Returns 0 on success, -1 on failure.
897     * Never returns failure after forking / closing standard file descriptors.
898     */
899    
900     int init(int ac, char **av)
901     {
902     int i;
903     int openlog_failed = 0, openlog_errno = 0;
904     int started_from_term = isatty(0) && isatty(1) && isatty(2);
905    
906    
907     /* Initialize memory log, to catch messages written before the log file
908     is opened (if any). */
909     open_memory_log();
910    
911     /* Account for runtime memory. */
912     init_memory();
913    
914     /* Parse command-line options; exit if an error occurs. */
915     if (parse_options(ac, av, 0) < 0)
916     return -1;
917    
918     /* Chdir to Services data directory. */
919     if (chdir(services_dir) < 0) {
920     fprintf(stderr, "chdir(%s): %s\n", services_dir, strerror(errno));
921     return -1;
922     }
923    
924     /* Read configuration file; exit if there are problems. */
925     if (!read_config())
926     return -1;
927    
928     /* Re-parse command-line options (to override configuration file). */
929     parse_options(ac, av, 0);
930    
931     /* Open logfile, and complain if we couldn't. */
932     set_logfile(LogFilename);
933     if (!open_log()) {
934     openlog_errno = errno;
935     if (started_from_term) {
936     fprintf(stderr, "Warning: unable to open log file %s: %s\n",
937     LogFilename, strerror(errno));
938     } else {
939     openlog_failed = 1;
940     }
941     }
942    
943     /* Announce ourselves to the logfile. */
944     if (debug || readonly || noexpire) {
945     log("IRC Services %s starting up (options:%s%s%s)",
946     version_number,
947     debug ? " debug" : "",
948     readonly ? " readonly" : "",
949     noexpire ? " noexpire" : "");
950     } else {
951     log("IRC Services %s starting up", version_number);
952     }
953     start_time = time(NULL);
954    
955     /* If in read-only mode, close the logfile again. */
956     if (readonly)
957     close_log();
958    
959    
960     /* If DUMPCORE is set and the OS supports get/setrlimit(), then attempt
961     * to remove, or at least raise to maximum, the core file size limit. */
962     #if DUMPCORE && HAVE_GETSETRLIMIT
963     {
964     struct rlimit rl = {RLIM_INFINITY,RLIM_INFINITY};
965     if (setrlimit(RLIMIT_CORE, &rl) < 0) {
966     log_perror("setrlimit(RLIMIT_CORE, RLIM_INFINITY)");
967     if ((i = getrlimit(RLIMIT_CORE, &rl)) < 0
968     || rl.rlim_cur >= rl.rlim_max
969     ) {
970     if (i < 0)
971     log_perror("getrlimit(RLIMIT_CORE)");
972     log("Unable to set core file size limit; core files %s.",
973     i < 0 || rl.rlim_cur == 0
974     ? "will not be generated" : "may be truncated");
975     } else {
976     rl.rlim_cur = rl.rlim_max;
977     if (setrlimit(RLIMIT_CORE, &rl) < 0) {
978     log_perror("setrlimit(RLIMIT_CORE, %ld)",
979     (long)rl.rlim_cur);
980     log("Unable to set core file size limit; core files may"
981     " be truncated.");
982     } else {
983     log("Core file size limited to %ldkB; core files may be"
984     " truncated.",
985     (long)(rl.rlim_cur<1024 ? 1 : rl.rlim_cur/1024));
986     }
987     }
988     } /* if (setrlimit(...) < 0) */
989     } /* setrlimit() block */
990     #endif
991    
992    
993     /* Initialize pseudo-random number generator. */
994     srand(time(NULL) ^ getppid() ^ getpid()<<16);
995    
996     /* Initialize socket system. */
997     sock_set_buflimits(NetBufferSize, TotalNetBufferSize);
998     sock_set_rto(ReadTimeout);
999    
1000     /* Initialize module system. This should be called before any
1001     * callbacks are registered. */
1002     if (!modules_init(ac, av))
1003     return -1;
1004    
1005     /* Register our (and main.c's) callbacks. */
1006     cb_cmdline = register_callback("command line");
1007     cb_introduce_user = register_callback("introduce_user");
1008     cb_connect = register_callback("connect");
1009     cb_save_complete = register_callback("save data complete");
1010     if (cb_cmdline < 0 || cb_introduce_user < 0 || cb_connect < 0
1011     || cb_save_complete < 0
1012     ) {
1013     log("init(): Unable to register callbacks");
1014     return -1;
1015     }
1016    
1017     /* Call other initialization routines. These are mainly (right now
1018     * only) for adding callbacks. */
1019     if (!user_init(ac,av) || !channel_init(ac,av) || !server_init(ac,av)
1020     || !process_init(ac,av) || !messages_init(ac,av)
1021     || !actions_init(ac,av) || !send_init(ac,av) || !database_init(ac,av)
1022     ) {
1023     return -1;
1024     }
1025    
1026     /* Initialize mode handling routines. */
1027     mode_setup();
1028    
1029     /* Initialize multi-language support. */
1030     if (!lang_init())
1031     return -1;
1032     log_debug(1, "Loaded languages");
1033    
1034     /* Load modules. */
1035     ARRAY_FOREACH (i, LoadModules) {
1036     if (!load_module(LoadModules[i])) {
1037     log("Error loading modules, aborting");
1038     return -1;
1039     }
1040     }
1041     log_debug(1, "Loaded modules");
1042    
1043     /* Load external language files (now that modules have had a chance to
1044     * add their own strings). */
1045     ARRAY_FOREACH (i, LoadLanguageText)
1046     load_ext_lang(LoadLanguageText[i]);
1047    
1048     /* Check command-line arguments in modules, and exit if a module directs
1049     * us to. */
1050     i = parse_options(ac, av, 1);
1051     if (i != 0) {
1052     if (i < 0) {
1053     cleanup();
1054     return -1;
1055     } else {
1056     save_all_dbtables();
1057     cleanup();
1058     exit(0);
1059     }
1060     }
1061    
1062     /* Make sure a protocol module was loaded. */
1063     if (protocol_features & PF_UNSET) {
1064     fprintf(stderr,
1065     "No protocol module has been loaded! Make sure to include a LoadModule\n"
1066     "directive for the appropriate module in the `%s' file.\n",
1067     IRCSERVICES_CONF);
1068     cleanup();
1069     return -1;
1070     }
1071    
1072    
1073     /* So far so good; let the user know everything is okay. */
1074     if (!nofork)
1075     fprintf(stderr, "Initialization successful, starting IRC Services.\n");
1076    
1077     /* Detach ourselves if requested. */
1078     if (!nofork) {
1079     if ((i = fork()) < 0) {
1080     perror("fork()");
1081     return -1;
1082     } else if (i != 0) {
1083     #if MEMCHECKS
1084     /* Avoid a bogus "XXX bytes leaked on exit" message for the
1085     * parent. */
1086     uninit_memory();
1087     #endif
1088     exit(0);
1089     }
1090     if (started_from_term) {
1091     close(0);
1092     close(1);
1093     close(2);
1094     }
1095     if (setpgid(0, 0) < 0) {
1096     perror("setpgid()");
1097     return -1;
1098     }
1099     }
1100    
1101     /*
1102     * Everything from here down needs to be done in the child process
1103     * (when forking).
1104     */
1105    
1106     /* Write our PID to the PID file. */
1107     if (!write_pidfile())
1108     log_perror("Warning: cannot write to PID file %s", PIDFilename);
1109    
1110     /* Set up signal handlers. */
1111     init_signals();
1112    
1113     /* Connect to the remote server. */
1114     servsock = sock_new();
1115     if (!servsock)
1116     fatal_perror("Can't create server socket");
1117     sock_setcb(servsock, SCB_CONNECT, connect_callback);
1118     sock_setcb(servsock, SCB_DISCONNECT, disconnect_callback);
1119     if (conn(servsock, RemoteServer, RemotePort, LocalHost, LocalPort) < 0)
1120     fatal_perror("Can't connect to server (%s:%d)",
1121     RemoteServer, RemotePort);
1122     log_debug(1, "Initiated connection to %s:%d", RemoteServer, RemotePort);
1123    
1124     /* Return success (connect_callback() will handle the rest). */
1125     return 0;
1126     }
1127    
1128     /*************************************************************************/
1129     /**************************** Reconfiguration ****************************/
1130     /*************************************************************************/
1131    
1132     int reconfigure(void)
1133     {
1134     char *old_RemoteServer, *old_RemotePassword, *old_LocalHost;
1135     int old_RemotePort, old_LocalPort;
1136     char *old_ServerName, *old_ServerDesc, *old_ServiceUser, *old_ServiceHost;
1137     char *old_LogFilename, *old_PIDFilename;
1138     char **old_LoadModules;
1139     int old_LoadModules_count;
1140     int LoadModules_insert; /* where to insert unloadable modules */
1141     int i, j;
1142     int retval = 1;
1143    
1144     /* First save any data that we need after re-reading the conf file */
1145     old_RemoteServer = sstrdup(RemoteServer);
1146     old_RemotePort = RemotePort;
1147     old_RemotePassword = sstrdup(RemotePassword);
1148     old_LocalHost = LocalHost ? sstrdup(LocalHost) : NULL;
1149     old_LocalPort = LocalPort;
1150     old_ServerName = sstrdup(ServerName);
1151     old_ServerDesc = sstrdup(ServerDesc);
1152     old_ServiceUser = sstrdup(ServiceUser);
1153     old_ServiceHost = sstrdup(ServiceHost);
1154     old_LogFilename = sstrdup(LogFilename);
1155     old_PIDFilename = sstrdup(PIDFilename);
1156     old_LoadModules = LoadModules;
1157     old_LoadModules_count = LoadModules_count;
1158    
1159     /* Re-read the configuration */
1160     if (!configure(NULL, main_directives, CONFIGURE_READ))
1161     return 0;
1162     /* Prevent current LoadModules (now old_LoadModules) from being freed */
1163     LoadModules = NULL;
1164     LoadModules_count = 0;
1165     /* Copy new values to configuration variables */
1166     configure(NULL, main_directives, CONFIGURE_SET);
1167    
1168     /* Deal with configuration changes */
1169     if (stricmp(RemoteServer, old_RemoteServer) != 0
1170     || RemotePort != old_RemotePort
1171     || strcmp(RemotePassword, old_RemotePassword) != 0)
1172     log("warning: reconfigure: new RemoteServer value will not take"
1173     " effect until restart");
1174     if ((!old_LocalHost && LocalHost) || (old_LocalHost && !LocalHost)
1175     || (LocalHost && stricmp(LocalHost, old_LocalHost) != 0)
1176     || LocalPort != old_LocalPort)
1177     log("warning: reconfigure: new LocalHost value will not take"
1178     " effect until restart");
1179     if (strcmp(ServerName, old_ServerName) != 0)
1180     log("warning: reconfigure: new ServerName value will not take"
1181     " effect until restart");
1182     if (strcmp(ServerDesc, old_ServerDesc) != 0)
1183     log("warning: reconfigure: new ServerDesc value will not take"
1184     " effect until restart");
1185     if ((!old_ServiceUser && ServiceUser) || (!old_ServiceHost && ServiceHost)
1186     || (ServiceUser && strcmp(ServiceUser, old_ServiceUser) != 0)
1187     || (ServiceHost && strcmp(ServiceHost, old_ServiceHost) != 0))
1188     log("warning: reconfigure: new ServiceUser value will not take"
1189     " effect until restart");
1190     if (strcmp(LogFilename, old_LogFilename) != 0) {
1191     log("reconfigure: LogFilename changed, closing log file");
1192     set_logfile(LogFilename);
1193     if (reopen_log()) {
1194     log("reconfigure: LogFilename changed, writing to new log file");
1195     } else {
1196     log("warning: reconfigure: unable to open new log file `%s',"
1197     " reverting to old file `%s'", LogFilename, old_LogFilename);
1198     free(LogFilename);
1199     LogFilename = old_LogFilename;
1200     old_LogFilename = NULL; /* don't free it below */
1201     }
1202     }
1203     if (strcmp(PIDFilename, old_PIDFilename) != 0) {
1204     if (write_pidfile()) {
1205     /* Successfully wrote the new PID file, so delete the old one */
1206     remove(old_PIDFilename);
1207     } else {
1208     log("warning: reconfigure: unable to write new PID file `%s',"
1209     " reverting to old file `%s'", PIDFilename, old_PIDFilename);
1210     strbcpy(PIDFilename, old_PIDFilename);
1211     }
1212     }
1213    
1214     /* Reset language data, then reload any new language files */
1215     reset_ext_lang();
1216     ARRAY_FOREACH (i, LoadLanguageText)
1217     load_ext_lang(LoadLanguageText[i]);
1218    
1219     /* For modules, we need to:
1220     * - first unload any modules which don't have LoadModule lines
1221     * anymore--this has to be done in reverse order to avoid
1222     * dependency problems;
1223     * - next reconfigure any still-loaded modules (because newly-loaded
1224     * modules in the next step may depend on the new settings);
1225     * - finally load any modules which weren't loaded before but have
1226     * LoadModule lines now.
1227     */
1228     LoadModules_insert = LoadModules_count;
1229     for (i = old_LoadModules_count - 1; i >= 0; i--) {
1230     ARRAY_SEARCH_PLAIN(LoadModules, old_LoadModules[i], strcmp, j);
1231     if (j >= LoadModules_count) {
1232     Module *mod = find_module(old_LoadModules[i]);
1233     if (!mod) {
1234     log("BUG: reconfigure: module `%s' not available",
1235     old_LoadModules[i]);
1236     retval = 0;
1237     } else if (!unload_module(mod)) {
1238     log("warning: reconfigure: module `%s' could not be unloaded",
1239     old_LoadModules[i]);
1240     ARRAY_INSERT(LoadModules, LoadModules_insert);
1241     LoadModules[LoadModules_insert] = sstrdup(old_LoadModules[i]);
1242     retval = 0;
1243     }
1244     }
1245     }
1246     if (retval && !reconfigure_modules()) {
1247     log("warning: reconfigure: module reconfiguration failed");
1248     retval = 0;
1249     }
1250     if (retval) {
1251     ARRAY_FOREACH (i, LoadModules) {
1252     ARRAY_SEARCH_PLAIN(old_LoadModules, LoadModules[i], strcmp, j);
1253     if (j >= old_LoadModules_count) {
1254     if (!load_module(LoadModules[i])) {
1255     log("warning: reconfigure: new module `%s' could not"
1256     " be loaded", LoadModules[i]);
1257     ARRAY_REMOVE(LoadModules, i);
1258     i--;
1259     retval = 0;
1260     }
1261     }
1262     }
1263     }
1264    
1265     /* Free old configuration data and return */
1266     free(old_RemoteServer);
1267     free(old_RemotePassword);
1268     free(old_LocalHost);
1269     free(old_ServerName);
1270     free(old_ServerDesc);
1271     free(old_ServiceUser);
1272     free(old_ServiceHost);
1273     free(old_LogFilename);
1274     free(old_PIDFilename);
1275     ARRAY_FOREACH (i, old_LoadModules)
1276     free(old_LoadModules[i]);
1277     free(old_LoadModules);
1278     return retval;
1279     }
1280    
1281     /*************************************************************************/
1282     /******************************** Cleanup ********************************/
1283     /*************************************************************************/
1284    
1285     void cleanup(void)
1286     {
1287     if (!*quitmsg)
1288     strbcpy(quitmsg, "Terminating, reason unknown");
1289     log("%s", quitmsg);
1290     set_cmode(NULL, NULL);
1291     unload_all_modules();
1292     if (servsock) {
1293     if (sock_isconn(servsock)) {
1294     send_cmd(ServerName, "SQUIT %s :%s", ServerName, quitmsg);
1295     disconn(servsock);
1296     }
1297     sock_free(servsock);
1298     }
1299     lang_cleanup();
1300     database_cleanup();
1301     send_cleanup();
1302     actions_cleanup();
1303     messages_cleanup();
1304     process_cleanup();
1305     server_cleanup();
1306     channel_cleanup();
1307     user_cleanup();
1308     unregister_callback(cb_save_complete);
1309     unregister_callback(cb_connect);
1310     unregister_callback(cb_introduce_user);
1311     unregister_callback(cb_cmdline);
1312     modules_cleanup();
1313     close_log();
1314     }
1315    
1316     /*************************************************************************/
1317    
1318     /*
1319     * Local variables:
1320     * c-file-style: "stroustrup"
1321     * c-file-offsets: ((case-label . *) (statement-case-intro . *))
1322     * indent-tabs-mode: nil
1323     * End:
1324     *
1325     * vim: expandtab shiftwidth=4:
1326     */

svnadmin@ircd-hybrid.org
ViewVC Help
Powered by ViewVC 1.1.28