[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

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