Annotation of ircnowd/src/ngircd/ngircd.c, Revision 1.1.1.1
1.1 tomglok 1: /*
2: * ngIRCd -- The Next Generation IRC Daemon
3: * Copyright (c)2001-2021 Alexander Barton (alex@barton.de) and Contributors.
4: *
5: * This program is free software; you can redistribute it and/or modify
6: * it under the terms of the GNU General Public License as published by
7: * the Free Software Foundation; either version 2 of the License, or
8: * (at your option) any later version.
9: * Please read the file COPYING, README and AUTHORS for more information.
10: */
11:
12: #define GLOBAL_INIT
13: #include "portab.h"
14:
15: /**
16: * @file
17: * The main program, including the C function main() which is called
18: * by the loader of the operating system.
19: */
20:
21: #include <assert.h>
22: #include <errno.h>
23: #include <stdio.h>
24: #include <stdlib.h>
25: #include <string.h>
26: #include <unistd.h>
27: #include <time.h>
28: #include <sys/types.h>
29: #include <sys/stat.h>
30: #include <fcntl.h>
31: #include <pwd.h>
32: #include <grp.h>
33:
34: #if defined(DEBUG) && defined(HAVE_MTRACE)
35: #include <mcheck.h>
36: #endif
37:
38: #include "conn.h"
39: #include "class.h"
40: #include "channel.h"
41: #include "conf.h"
42: #include "log.h"
43: #include "sighandlers.h"
44: #include "io.h"
45:
46: #include "ngircd.h"
47:
48: static void Show_Version PARAMS(( void ));
49: static void Show_Help PARAMS(( void ));
50:
51: static void Pidfile_Create PARAMS(( pid_t pid ));
52: static void Pidfile_Delete PARAMS(( void ));
53:
54: static void Fill_Version PARAMS(( void ));
55:
56: static void Random_Init PARAMS(( void ));
57:
58: static void Setup_FDStreams PARAMS(( int fd ));
59:
60: static bool NGIRCd_Init PARAMS(( bool ));
61:
62:
63: /**
64: * The main() function of ngIRCd.
65: *
66: * Here all starts: this function is called by the operating system loader,
67: * it is the first portion of code executed of ngIRCd.
68: *
69: * @param argc The number of arguments passed to ngIRCd on the command line.
70: * @param argv An array containing all the arguments passed to ngIRCd.
71: * @return Global exit code of ngIRCd, zero on success.
72: */
73: GLOBAL int
74: main(int argc, const char *argv[])
75: {
76: bool ok, configtest = false;
77: bool NGIRCd_NoDaemon = false;
78: int i;
79: size_t n;
80:
81: #if defined(DEBUG) && defined(HAVE_MTRACE)
82: /* enable GNU libc memory tracing when running in debug mode
83: * and functionality available */
84: mtrace();
85: #endif
86:
87: umask(0077);
88:
89: NGIRCd_SignalQuit = NGIRCd_SignalRestart = false;
90: NGIRCd_Passive = false;
91: #ifdef DEBUG
92: NGIRCd_Debug = false;
93: #endif
94: #ifdef SNIFFER
95: NGIRCd_Sniffer = false;
96: #endif
97: strlcpy(NGIRCd_ConfFile, SYSCONFDIR, sizeof(NGIRCd_ConfFile));
98: strlcat(NGIRCd_ConfFile, CONFIG_FILE, sizeof(NGIRCd_ConfFile));
99:
100: Fill_Version();
101:
102: /* parse conmmand line */
103: for (i = 1; i < argc; i++) {
104: ok = false;
105: if (argv[i][0] == '-' && argv[i][1] == '-') {
106: /* long option */
107: if (strcmp(argv[i], "--config") == 0) {
108: if (i + 1 < argc) {
109: /* Ok, there's an parameter left */
110: strlcpy(NGIRCd_ConfFile, argv[i+1],
111: sizeof(NGIRCd_ConfFile));
112: /* next parameter */
113: i++; ok = true;
114: }
115: }
116: if (strcmp(argv[i], "--configtest") == 0) {
117: configtest = true;
118: ok = true;
119: }
120: #ifdef DEBUG
121: if (strcmp(argv[i], "--debug") == 0) {
122: NGIRCd_Debug = true;
123: ok = true;
124: }
125: #endif
126: if (strcmp(argv[i], "--help") == 0) {
127: Show_Version();
128: puts(""); Show_Help( ); puts( "" );
129: exit(0);
130: }
131: if (strcmp(argv[i], "--nodaemon") == 0) {
132: NGIRCd_NoDaemon = true;
133: ok = true;
134: }
135: if (strcmp(argv[i], "--passive") == 0) {
136: NGIRCd_Passive = true;
137: ok = true;
138: }
139: #ifdef SNIFFER
140: if (strcmp(argv[i], "--sniffer") == 0) {
141: NGIRCd_Sniffer = true;
142: ok = true;
143: }
144: #endif
145: if (strcmp(argv[i], "--version") == 0) {
146: Show_Version();
147: exit(0);
148: }
149: }
150: else if(argv[i][0] == '-' && argv[i][1] != '-') {
151: /* short option */
152: for (n = 1; n < strlen(argv[i]); n++) {
153: ok = false;
154: #ifdef DEBUG
155: if (argv[i][n] == 'd') {
156: NGIRCd_Debug = true;
157: ok = true;
158: }
159: #endif
160: if (argv[i][n] == 'f') {
161: if (!argv[i][n+1] && i+1 < argc) {
162: /* Ok, next character is a blank */
163: strlcpy(NGIRCd_ConfFile, argv[i+1],
164: sizeof(NGIRCd_ConfFile));
165:
166: /* go to the following parameter */
167: i++;
168: n = strlen(argv[i]);
169: ok = true;
170: }
171: }
172:
173: if (argv[i][n] == 'h') {
174: Show_Version();
175: puts(""); Show_Help(); puts("");
176: exit(1);
177: }
178:
179: if (argv[i][n] == 'n') {
180: NGIRCd_NoDaemon = true;
181: ok = true;
182: }
183: if (argv[i][n] == 'p') {
184: NGIRCd_Passive = true;
185: ok = true;
186: }
187: #ifdef SNIFFER
188: if (argv[i][n] == 's') {
189: NGIRCd_Sniffer = true;
190: ok = true;
191: }
192: #endif
193: if (argv[i][n] == 't') {
194: configtest = true;
195: ok = true;
196: }
197:
198: if (argv[i][n] == 'V') {
199: Show_Version();
200: exit(1);
201: }
202:
203: if (!ok) {
204: fprintf(stderr,
205: "%s: invalid option \"-%c\"!\n",
206: PACKAGE_NAME, argv[i][n]);
207: fprintf(stderr,
208: "Try \"%s --help\" for more information.\n",
209: PACKAGE_NAME);
210: exit(2);
211: }
212: }
213:
214: }
215: if (!ok) {
216: fprintf(stderr, "%s: invalid option \"%s\"!\n",
217: PACKAGE_NAME, argv[i]);
218: fprintf(stderr, "Try \"%s --help\" for more information.\n",
219: PACKAGE_NAME);
220: exit(2);
221: }
222: }
223:
224: /* Debug level for "VERSION" command */
225: NGIRCd_DebugLevel[0] = '\0';
226: #ifdef DEBUG
227: if (NGIRCd_Debug)
228: strcpy(NGIRCd_DebugLevel, "1");
229: #endif
230: #ifdef SNIFFER
231: if (NGIRCd_Sniffer) {
232: NGIRCd_Debug = true;
233: strcpy(NGIRCd_DebugLevel, "2");
234: }
235: #endif
236:
237: if (configtest) {
238: Show_Version(); puts("");
239: exit(Conf_Test());
240: }
241:
242: while (!NGIRCd_SignalQuit) {
243: /* Initialize global variables */
244: NGIRCd_Start = time(NULL);
245: (void)strftime(NGIRCd_StartStr, 64,
246: "%a %b %d %Y at %H:%M:%S (%Z)",
247: localtime(&NGIRCd_Start));
248:
249: NGIRCd_SignalRestart = false;
250: NGIRCd_SignalQuit = false;
251:
252: Log_Init(!NGIRCd_NoDaemon);
253: Random_Init();
254: Conf_Init();
255: Log_ReInit();
256:
257: /* Initialize the "main program":
258: * chroot environment, user and group ID, ... */
259: if (!NGIRCd_Init(NGIRCd_NoDaemon)) {
260: Log(LOG_ALERT, "Fatal: Initialization failed, exiting!");
261: exit(1);
262: }
263:
264: if (!io_library_init(CONNECTION_POOL)) {
265: Log(LOG_ALERT,
266: "Fatal: Could not initialize IO routines: %s",
267: strerror(errno));
268: exit(1);
269: }
270:
271: if (!Signals_Init()) {
272: Log(LOG_ALERT,
273: "Fatal: Could not set up signal handlers: %s",
274: strerror(errno));
275: exit(1);
276: }
277:
278: Channel_Init();
279: Conn_Init();
280: Class_Init();
281: Client_Init();
282:
283: /* Create protocol and server identification. The syntax
284: * used by ngIRCd in PASS commands and the known "extended
285: * flags" are described in doc/Protocol.txt. */
286: #ifdef IRCPLUS
287: snprintf(NGIRCd_ProtoID, sizeof NGIRCd_ProtoID, "%s%s %s|%s:%s",
288: PROTOVER, PROTOIRCPLUS, PACKAGE_NAME, PACKAGE_VERSION,
289: IRCPLUSFLAGS);
290: #ifdef ZLIB
291: strlcat(NGIRCd_ProtoID, "Z", sizeof NGIRCd_ProtoID);
292: #endif
293: if (Conf_OperCanMode)
294: strlcat(NGIRCd_ProtoID, "o", sizeof NGIRCd_ProtoID);
295: #else /* IRCPLUS */
296: snprintf(NGIRCd_ProtoID, sizeof NGIRCd_ProtoID, "%s%s %s|%s",
297: PROTOVER, PROTOIRC, PACKAGE_NAME, PACKAGE_VERSION);
298: #endif /* IRCPLUS */
299: strlcat(NGIRCd_ProtoID, " P", sizeof NGIRCd_ProtoID);
300: #ifdef ZLIB
301: strlcat(NGIRCd_ProtoID, "Z", sizeof NGIRCd_ProtoID);
302: #endif
303: LogDebug("Protocol and server ID is \"%s\".", NGIRCd_ProtoID);
304:
305: Channel_InitPredefined();
306:
307: if (Conn_InitListeners() < 1) {
308: Log(LOG_ALERT,
309: "Server isn't listening on a single port!" );
310: Log(LOG_ALERT,
311: "%s exiting due to fatal errors!", PACKAGE_NAME);
312: Pidfile_Delete();
313: exit(1);
314: }
315:
316: /* Main Run Loop */
317: Conn_Handler();
318:
319: Conn_Exit();
320: Client_Exit();
321: Channel_Exit();
322: Class_Exit();
323: Log_Exit();
324: Signals_Exit();
325: }
326: Pidfile_Delete();
327:
328: return 0;
329: } /* main */
330:
331:
332: /**
333: * Generate ngIRCd "version strings".
334: *
335: * The ngIRCd version information is generated once and then stored in the
336: * NGIRCd_Version and NGIRCd_VersionAddition string variables for further
337: * usage, for example by the IRC command "VERSION" and the --version command
338: * line switch.
339: */
340: static void
341: Fill_Version(void)
342: {
343: NGIRCd_VersionAddition[0] = '\0';
344:
345: #ifdef ICONV
346: if (NGIRCd_VersionAddition[0])
347: strlcat(NGIRCd_VersionAddition, "+",
348: sizeof NGIRCd_VersionAddition);
349: strlcat(NGIRCd_VersionAddition, "CHARCONV",
350: sizeof NGIRCd_VersionAddition);
351: #endif
352: #ifdef DEBUG
353: if (NGIRCd_VersionAddition[0])
354: strlcat(NGIRCd_VersionAddition, "+",
355: sizeof NGIRCd_VersionAddition);
356: strlcat(NGIRCd_VersionAddition, "DEBUG",
357: sizeof NGIRCd_VersionAddition);
358: #endif
359: #ifdef IDENTAUTH
360: if (NGIRCd_VersionAddition[0])
361: strlcat(NGIRCd_VersionAddition, "+",
362: sizeof NGIRCd_VersionAddition);
363: strlcat(NGIRCd_VersionAddition, "IDENT",
364: sizeof NGIRCd_VersionAddition);
365: #endif
366: #ifdef WANT_IPV6
367: if (NGIRCd_VersionAddition[0])
368: strlcat(NGIRCd_VersionAddition, "+",
369: sizeof(NGIRCd_VersionAddition));
370: strlcat(NGIRCd_VersionAddition, "IPv6",
371: sizeof(NGIRCd_VersionAddition));
372: #endif
373: #ifdef IRCPLUS
374: if (NGIRCd_VersionAddition[0])
375: strlcat(NGIRCd_VersionAddition, "+",
376: sizeof NGIRCd_VersionAddition);
377: strlcat(NGIRCd_VersionAddition, "IRCPLUS",
378: sizeof NGIRCd_VersionAddition);
379: #endif
380: #ifdef PAM
381: if (NGIRCd_VersionAddition[0])
382: strlcat(NGIRCd_VersionAddition, "+",
383: sizeof NGIRCd_VersionAddition);
384: strlcat(NGIRCd_VersionAddition, "PAM",
385: sizeof NGIRCd_VersionAddition);
386: #endif
387: #ifdef STRICT_RFC
388: if (NGIRCd_VersionAddition[0])
389: strlcat(NGIRCd_VersionAddition, "+",
390: sizeof NGIRCd_VersionAddition);
391: strlcat(NGIRCd_VersionAddition, "RFC",
392: sizeof NGIRCd_VersionAddition);
393: #endif
394: #ifdef SNIFFER
395: if (NGIRCd_VersionAddition[0])
396: strlcat(NGIRCd_VersionAddition, "+",
397: sizeof NGIRCd_VersionAddition);
398: strlcat(NGIRCd_VersionAddition, "SNIFFER",
399: sizeof NGIRCd_VersionAddition);
400: #endif
401: #ifdef SSL_SUPPORT
402: if (NGIRCd_VersionAddition[0])
403: strlcat(NGIRCd_VersionAddition, "+",
404: sizeof NGIRCd_VersionAddition);
405: strlcat(NGIRCd_VersionAddition, "SSL",
406: sizeof NGIRCd_VersionAddition);
407: #endif
408: #ifdef SYSLOG
409: if (NGIRCd_VersionAddition[0])
410: strlcat(NGIRCd_VersionAddition, "+",
411: sizeof NGIRCd_VersionAddition);
412: strlcat(NGIRCd_VersionAddition, "SYSLOG",
413: sizeof NGIRCd_VersionAddition);
414: #endif
415: #ifdef TCPWRAP
416: if (NGIRCd_VersionAddition[0])
417: strlcat(NGIRCd_VersionAddition, "+",
418: sizeof NGIRCd_VersionAddition);
419: strlcat(NGIRCd_VersionAddition, "TCPWRAP",
420: sizeof NGIRCd_VersionAddition);
421: #endif
422: #ifdef ZLIB
423: if (NGIRCd_VersionAddition[0])
424: strlcat(NGIRCd_VersionAddition, "+",
425: sizeof NGIRCd_VersionAddition);
426: strlcat(NGIRCd_VersionAddition, "ZLIB",
427: sizeof NGIRCd_VersionAddition);
428: #endif
429: if (NGIRCd_VersionAddition[0])
430: strlcat(NGIRCd_VersionAddition, "-",
431: sizeof(NGIRCd_VersionAddition));
432:
433: strlcat(NGIRCd_VersionAddition, HOST_CPU,
434: sizeof(NGIRCd_VersionAddition));
435: strlcat(NGIRCd_VersionAddition, "/", sizeof(NGIRCd_VersionAddition));
436: strlcat(NGIRCd_VersionAddition, HOST_VENDOR,
437: sizeof(NGIRCd_VersionAddition));
438: strlcat(NGIRCd_VersionAddition, "/", sizeof(NGIRCd_VersionAddition));
439: strlcat(NGIRCd_VersionAddition, HOST_OS,
440: sizeof(NGIRCd_VersionAddition));
441:
442: snprintf(NGIRCd_Version, sizeof NGIRCd_Version, "%s %s-%s",
443: PACKAGE_NAME, PACKAGE_VERSION, NGIRCd_VersionAddition);
444: } /* Fill_Version */
445:
446:
447: /**
448: * Display copyright and version information of ngIRCd on the console.
449: */
450: static void
451: Show_Version( void )
452: {
453: puts( NGIRCd_Version );
454: puts( "Copyright (c)2001-2021 Alexander Barton (<alex@barton.de>) and Contributors." );
455: puts( "Homepage: <http://ngircd.barton.de/>\n" );
456: puts( "This is free software; see the source for copying conditions. There is NO" );
457: puts( "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." );
458: } /* Show_Version */
459:
460:
461: /**
462: * Display a short help text on the console.
463: * This help depends on the configuration of the executable and only shows
464: * options that are actually enabled.
465: */
466: static void
467: Show_Help( void )
468: {
469: #ifdef DEBUG
470: puts( " -d, --debug log extra debug messages" );
471: #endif
472: puts( " -f, --config <f> use file <f> as configuration file" );
473: puts( " -n, --nodaemon don't fork and don't detach from controlling terminal" );
474: puts( " -p, --passive disable automatic connections to other servers" );
475: #ifdef SNIFFER
476: puts( " -s, --sniffer enable network sniffer and display all IRC traffic" );
477: #endif
478: puts( " -t, --configtest read, validate and display configuration; then exit" );
479: puts( " -V, --version output version information and exit" );
480: puts( " -h, --help display this help and exit" );
481: } /* Show_Help */
482:
483:
484: /**
485: * Delete the file containing the process ID (PID).
486: */
487: static void
488: Pidfile_Delete( void )
489: {
490: /* Pidfile configured? */
491: if( ! Conf_PidFile[0] ) return;
492:
493: #ifdef DEBUG
494: Log( LOG_DEBUG, "Removing PID file (%s) ...", Conf_PidFile );
495: #endif
496:
497: if( unlink( Conf_PidFile ))
498: Log( LOG_ERR, "Error unlinking PID file (%s): %s", Conf_PidFile, strerror( errno ));
499: } /* Pidfile_Delete */
500:
501:
502: /**
503: * Create the file containing the process ID of ngIRCd ("PID file").
504: *
505: * @param pid The process ID to be stored in this file.
506: */
507: static void
508: Pidfile_Create(pid_t pid)
509: {
510: int pidfd;
511: char pidbuf[64];
512: int len;
513:
514: /* Pidfile configured? */
515: if( ! Conf_PidFile[0] ) return;
516:
517: #ifdef DEBUG
518: Log( LOG_DEBUG, "Creating PID file (%s) ...", Conf_PidFile );
519: #endif
520:
521: pidfd = open( Conf_PidFile, O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
522: if ( pidfd < 0 ) {
523: Log( LOG_ERR, "Error writing PID file (%s): %s", Conf_PidFile, strerror( errno ));
524: return;
525: }
526:
527: len = snprintf(pidbuf, sizeof pidbuf, "%ld\n", (long)pid);
528: if (len < 0 || len >= (int)sizeof pidbuf) {
529: Log(LOG_ERR, "Error converting process ID!");
530: close(pidfd);
531: return;
532: }
533:
534: if (write(pidfd, pidbuf, (size_t)len) != (ssize_t)len)
535: Log(LOG_ERR, "Can't write PID file (%s): %s!", Conf_PidFile,
536: strerror(errno));
537:
538: if (close(pidfd) != 0)
539: Log(LOG_ERR, "Error closing PID file (%s): %s!", Conf_PidFile,
540: strerror(errno));
541: } /* Pidfile_Create */
542:
543:
544: /**
545: * Redirect stdin, stdout and stderr to appropriate file handles.
546: *
547: * @param fd The file handle stdin, stdout and stderr should be redirected to.
548: */
549: static void
550: Setup_FDStreams(int fd)
551: {
552: if (fd < 0)
553: return;
554:
555: fflush(stdout);
556: fflush(stderr);
557:
558: /* Create new stdin(0), stdout(1) and stderr(2) descriptors */
559: dup2( fd, 0 ); dup2( fd, 1 ); dup2( fd, 2 );
560: } /* Setup_FDStreams */
561:
562:
563: #if !defined(SINGLE_USER_OS)
564:
565: /**
566: * Get user and group ID of unprivileged "nobody" user.
567: *
568: * @param uid User ID
569: * @param gid Group ID
570: * @return true on success.
571: */
572: static bool
573: NGIRCd_getNobodyID(uid_t *uid, gid_t *gid )
574: {
575: struct passwd *pwd;
576:
577: #ifdef __CYGWIN__
578: /* Cygwin kludge.
579: * It can return EINVAL instead of EPERM
580: * so, if we are already unprivileged,
581: * use id of current user.
582: */
583: if (geteuid() && getuid()) {
584: *uid = getuid();
585: *gid = getgid();
586: return true;
587: }
588: #endif
589:
590: pwd = getpwnam("nobody");
591: if (!pwd)
592: return false;
593:
594: if (!pwd->pw_uid || !pwd->pw_gid)
595: return false;
596:
597: *uid = pwd->pw_uid;
598: *gid = pwd->pw_gid;
599: endpwent();
600:
601: return true;
602: } /* NGIRCd_getNobodyID */
603:
604: #endif
605:
606:
607: #ifdef HAVE_ARC4RANDOM
608: static void
609: Random_Init(void)
610: {
611:
612: }
613: #else
614: static bool
615: Random_Init_Kern(const char *file)
616: {
617: unsigned int seed;
618: bool ret = false;
619: int fd = open(file, O_RDONLY);
620: if (fd >= 0) {
621: if (read(fd, &seed, sizeof(seed)) == sizeof(seed))
622: ret = true;
623: close(fd);
624: srand(seed);
625: }
626: return ret;
627: }
628:
629: /**
630: * Initialize libc rand(3) number generator
631: */
632: static void
633: Random_Init(void)
634: {
635: if (Random_Init_Kern("/dev/urandom"))
636: return;
637: if (Random_Init_Kern("/dev/random"))
638: return;
639: if (Random_Init_Kern("/dev/arandom"))
640: return;
641: srand(rand() ^ (unsigned)getpid() ^ (unsigned)time(NULL));
642: }
643: #endif
644:
645:
646: /**
647: * Initialize ngIRCd daemon.
648: *
649: * @param NGIRCd_NoDaemon Set to true if ngIRCd should run in the
650: * foreground (and not as a daemon).
651: * @return true on success.
652: */
653: static bool
654: NGIRCd_Init(bool NGIRCd_NoDaemon)
655: {
656: static bool initialized;
657: bool chrooted = false;
658: struct passwd *pwd;
659: struct group *grp;
660: int real_errno, fd = -1;
661: pid_t pid;
662:
663: if (initialized)
664: return true;
665:
666: if (!NGIRCd_NoDaemon) {
667: /* open /dev/null before chroot() */
668: fd = open( "/dev/null", O_RDWR);
669: if (fd < 0)
670: Log(LOG_WARNING, "Could not open /dev/null: %s",
671: strerror(errno));
672: }
673:
674: /* SSL initialization */
675: if (!ConnSSL_InitLibrary()) {
676: Log(LOG_ERR, "Error during SSL initialization!");
677: goto out;
678: }
679:
680: /* Change root */
681: if (Conf_Chroot[0]) {
682: if (chdir(Conf_Chroot) != 0) {
683: Log(LOG_ERR, "Can't chdir() in ChrootDir (%s): %s!",
684: Conf_Chroot, strerror(errno));
685: goto out;
686: }
687:
688: if (chroot(Conf_Chroot) != 0) {
689: Log(LOG_ERR,
690: "Can't change root directory to \"%s\": %s!",
691: Conf_Chroot, strerror(errno));
692: goto out;
693: } else {
694: chrooted = true;
695: Log(LOG_INFO,
696: "Changed root and working directory to \"%s\".",
697: Conf_Chroot);
698: }
699: }
700:
701: #if !defined(SINGLE_USER_OS)
702: /* Check user ID */
703: if (Conf_UID == 0) {
704: pwd = getpwuid(0);
705: Log(LOG_INFO,
706: "ServerUID must not be %s(0), using \"nobody\" instead.",
707: pwd ? pwd->pw_name : "?");
708: if (!NGIRCd_getNobodyID(&Conf_UID, &Conf_GID)) {
709: Log(LOG_WARNING,
710: "Could not get user/group ID of user \"nobody\": %s",
711: errno ? strerror(errno) : "not found" );
712: goto out;
713: }
714: }
715:
716: /* Change group ID */
717: if (getgid() != Conf_GID) {
718: if (setgid(Conf_GID) != 0) {
719: real_errno = errno;
720: grp = getgrgid(Conf_GID);
721: Log(LOG_ERR, "Can't change group ID to %s(%u): %s!",
722: grp ? grp->gr_name : "?", Conf_GID,
723: strerror(real_errno));
724: if (real_errno != EPERM)
725: goto out;
726: }
727: #ifdef HAVE_SETGROUPS
728: if (setgroups(0, NULL) != 0) {
729: real_errno = errno;
730: Log(LOG_ERR, "Can't drop supplementary group IDs: %s!",
731: strerror(errno));
732: if (real_errno != EPERM)
733: goto out;
734: }
735: #else
736: Log(LOG_WARNING,
737: "Can't drop supplementary group IDs: setgroups(3) missing!");
738: #endif
739: }
740: #endif
741:
742: /* Change user ID */
743: if (getuid() != Conf_UID) {
744: if (setuid(Conf_UID) != 0) {
745: real_errno = errno;
746: pwd = getpwuid(Conf_UID);
747: Log(LOG_ERR, "Can't change user ID to %s(%u): %s!",
748: pwd ? pwd->pw_name : "?", Conf_UID,
749: strerror(real_errno));
750: if (real_errno != EPERM)
751: goto out;
752: }
753: }
754:
755: initialized = true;
756:
757: /* Normally a child process is forked which isn't any longer
758: * connected to ther controlling terminal. Use "--nodaemon"
759: * to disable this "daemon mode" (useful for debugging). */
760: if (!NGIRCd_NoDaemon) {
761: pid = fork();
762: if (pid > 0) {
763: /* "Old" process: exit. */
764: exit(0);
765: }
766: if (pid < 0) {
767: /* Error!? */
768: fprintf(stderr,
769: "%s: Can't fork: %s!\nFatal error, exiting now ...\n",
770: PACKAGE_NAME, strerror(errno));
771: exit(1);
772: }
773:
774: /* New child process */
775: #ifdef HAVE_SETSID
776: (void)setsid();
777: #else
778: setpgrp(0, getpid());
779: #endif
780: if (chdir("/") != 0)
781: Log(LOG_ERR, "Can't change directory to '/': %s!",
782: strerror(errno));
783:
784: /* Detach stdin, stdout and stderr */
785: Setup_FDStreams(fd);
786: if (fd > 2)
787: close(fd);
788: }
789: pid = getpid();
790:
791: Pidfile_Create(pid);
792:
793: /* Check UID/GID we are running as, can be different from values
794: * configured (e. g. if we were already started with a UID>0. */
795: Conf_UID = getuid();
796: Conf_GID = getgid();
797:
798: pwd = getpwuid(Conf_UID);
799: grp = getgrgid(Conf_GID);
800:
801: Log(LOG_INFO, "Running as user %s(%ld), group %s(%ld), with PID %ld.",
802: pwd ? pwd->pw_name : "unknown", (long)Conf_UID,
803: grp ? grp->gr_name : "unknown", (long)Conf_GID, (long)pid);
804:
805: if (chrooted) {
806: Log(LOG_INFO, "Running with root directory \"%s\".",
807: Conf_Chroot );
808: return true;
809: } else
810: Log(LOG_INFO, "Not running with changed root directory.");
811:
812: /* Change working directory to home directory of the user we are
813: * running as (only when running in daemon mode and not in chroot) */
814:
815: if (NGIRCd_NoDaemon)
816: return true;
817:
818: if (pwd) {
819: if (chdir(pwd->pw_dir) == 0)
820: Log(LOG_DEBUG,
821: "Changed working directory to \"%s\" ...",
822: pwd->pw_dir);
823: else
824: Log(LOG_ERR,
825: "Can't change working directory to \"%s\": %s!",
826: pwd->pw_dir, strerror(errno));
827: } else
828: Log(LOG_ERR, "Can't get user informaton for UID %d!?", Conf_UID);
829:
830: return true;
831: out:
832: if (fd > 2)
833: close(fd);
834: return false;
835: } /* NGIRCd_Init */
836:
837:
838: /* -eof- */
CVSweb