[BACK]Return to ngircd.c CVS log [TXT][DIR] Up to [local] / ircnowd / src / ngircd

Annotation of ircnowd/src/ngircd/ngircd.c, Revision 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