/* * $Id: main.c,v 5.201 2007/04/02 17:59:16 bryan Exp $ * * Copyright conserver.com, 2000 * * Maintainer/Enhancer: Bryan Stansell (bryan@conserver.com) * * Copyright GNAC, Inc., 1998 */ /* * Copyright (c) 1990 The Ohio State University. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that: (1) source distributions retain this entire copyright * notice and comment, and (2) distributions including binaries display * the following acknowledgement: ``This product includes software * developed by The Ohio State University and its contributors'' * in the documentation or other materials provided with the distribution * and in all advertising materials mentioning features or use of this * software. Neither the name of the University nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #include #include #include #include #include #include #include #include #include #include #include #if HAVE_OPENSSL # include #endif int fAll = 0, fNoinit = 0, fVersion = 0, fStrip = 0, fReopen = 0, fNoautoreup = 0, fSyntaxOnly = 0; char *pcConfig = CONFIGFILE; int cMaxMemb = MAXMEMB; in_addr_t bindAddr = INADDR_ANY; unsigned short bindPort; unsigned short bindBasePort; static STRING *startedMsg = (STRING *)0; CONFIG *optConf = (CONFIG *)0; CONFIG *config = (CONFIG *)0; char *interface = (char *)0; CONFIG defConfig = { (STRING *)0, FLAGTRUE, 'r', FLAGFALSE, LOGFILEPATH, PASSWDFILE, DEFPORT, FLAGTRUE, FLAGTRUE, 0, DEFBASEPORT, (char *)0, 0 #if HAVE_SETPROCTITLE , FLAGFALSE #endif #if HAVE_OPENSSL , (char *)0, FLAGTRUE #endif }; struct sockaddr_in in_port; CONSFILE *unifiedlog = (CONSFILE *)0; #if HAVE_DMALLOC && DMALLOC_MARK_MAIN unsigned long dmallocMarkMain = 0; #endif #if HAVE_OPENSSL SSL_CTX *ctx = (SSL_CTX *)0; DH *dh512 = (DH *)0; DH *dh1024 = (DH *)0; DH *dh2048 = (DH *)0; DH *dh4096 = (DH *)0; DH * #if PROTOTYPES GetDH512(void) #else GetDH512() #endif { static unsigned char dh512_p[] = { 0xF5, 0x2A, 0xFF, 0x3C, 0xE1, 0xB1, 0x29, 0x40, 0x18, 0x11, 0x8D, 0x7C, 0x84, 0xA7, 0x0A, 0x72, 0xD6, 0x86, 0xC4, 0x03, 0x19, 0xC8, 0x07, 0x29, 0x7A, 0xCA, 0x95, 0x0C, 0xD9, 0x96, 0x9F, 0xAB, 0xD0, 0x0A, 0x50, 0x9B, 0x02, 0x46, 0xD3, 0x08, 0x3D, 0x66, 0xA4, 0x5D, 0x41, 0x9F, 0x9C, 0x7C, 0xBD, 0x89, 0x4B, 0x22, 0x19, 0x26, 0xBA, 0xAB, 0xA2, 0x5E, 0xC3, 0x55, 0xE9, 0x2A, 0x05, 0x5F, }; static unsigned char dh512_g[] = { 0x02, }; DH *dh; if ((dh = DH_new()) == NULL) return (NULL); dh->p = BN_bin2bn(dh512_p, sizeof(dh512_p), NULL); dh->g = BN_bin2bn(dh512_g, sizeof(dh512_g), NULL); if ((dh->p == NULL) || (dh->g == NULL)) { DH_free(dh); return (NULL); } return (dh); } DH * #if PROTOTYPES GetDH1024(void) #else GetDH1024() #endif { static unsigned char dh1024_p[] = { 0xF4, 0x88, 0xFD, 0x58, 0x4E, 0x49, 0xDB, 0xCD, 0x20, 0xB4, 0x9D, 0xE4, 0x91, 0x07, 0x36, 0x6B, 0x33, 0x6C, 0x38, 0x0D, 0x45, 0x1D, 0x0F, 0x7C, 0x88, 0xB3, 0x1C, 0x7C, 0x5B, 0x2D, 0x8E, 0xF6, 0xF3, 0xC9, 0x23, 0xC0, 0x43, 0xF0, 0xA5, 0x5B, 0x18, 0x8D, 0x8E, 0xBB, 0x55, 0x8C, 0xB8, 0x5D, 0x38, 0xD3, 0x34, 0xFD, 0x7C, 0x17, 0x57, 0x43, 0xA3, 0x1D, 0x18, 0x6C, 0xDE, 0x33, 0x21, 0x2C, 0xB5, 0x2A, 0xFF, 0x3C, 0xE1, 0xB1, 0x29, 0x40, 0x18, 0x11, 0x8D, 0x7C, 0x84, 0xA7, 0x0A, 0x72, 0xD6, 0x86, 0xC4, 0x03, 0x19, 0xC8, 0x07, 0x29, 0x7A, 0xCA, 0x95, 0x0C, 0xD9, 0x96, 0x9F, 0xAB, 0xD0, 0x0A, 0x50, 0x9B, 0x02, 0x46, 0xD3, 0x08, 0x3D, 0x66, 0xA4, 0x5D, 0x41, 0x9F, 0x9C, 0x7C, 0xBD, 0x89, 0x4B, 0x22, 0x19, 0x26, 0xBA, 0xAB, 0xA2, 0x5E, 0xC3, 0x55, 0xE9, 0x2F, 0x78, 0xC7, }; static unsigned char dh1024_g[] = { 0x02, }; DH *dh; if ((dh = DH_new()) == NULL) return (NULL); dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL); dh->g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL); if ((dh->p == NULL) || (dh->g == NULL)) { DH_free(dh); return (NULL); } return (dh); } DH * #if PROTOTYPES GetDH2048(void) #else GetDH2048() #endif { static unsigned char dh2048_p[] = { 0xF6, 0x42, 0x57, 0xB7, 0x08, 0x7F, 0x08, 0x17, 0x72, 0xA2, 0xBA, 0xD6, 0xA9, 0x42, 0xF3, 0x05, 0xE8, 0xF9, 0x53, 0x11, 0x39, 0x4F, 0xB6, 0xF1, 0x6E, 0xB9, 0x4B, 0x38, 0x20, 0xDA, 0x01, 0xA7, 0x56, 0xA3, 0x14, 0xE9, 0x8F, 0x40, 0x55, 0xF3, 0xD0, 0x07, 0xC6, 0xCB, 0x43, 0xA9, 0x94, 0xAD, 0xF7, 0x4C, 0x64, 0x86, 0x49, 0xF8, 0x0C, 0x83, 0xBD, 0x65, 0xE9, 0x17, 0xD4, 0xA1, 0xD3, 0x50, 0xF8, 0xF5, 0x59, 0x5F, 0xDC, 0x76, 0x52, 0x4F, 0x3D, 0x3D, 0x8D, 0xDB, 0xCE, 0x99, 0xE1, 0x57, 0x92, 0x59, 0xCD, 0xFD, 0xB8, 0xAE, 0x74, 0x4F, 0xC5, 0xFC, 0x76, 0xBC, 0x83, 0xC5, 0x47, 0x30, 0x61, 0xCE, 0x7C, 0xC9, 0x66, 0xFF, 0x15, 0xF9, 0xBB, 0xFD, 0x91, 0x5E, 0xC7, 0x01, 0xAA, 0xD3, 0x5B, 0x9E, 0x8D, 0xA0, 0xA5, 0x72, 0x3A, 0xD4, 0x1A, 0xF0, 0xBF, 0x46, 0x00, 0x58, 0x2B, 0xE5, 0xF4, 0x88, 0xFD, 0x58, 0x4E, 0x49, 0xDB, 0xCD, 0x20, 0xB4, 0x9D, 0xE4, 0x91, 0x07, 0x36, 0x6B, 0x33, 0x6C, 0x38, 0x0D, 0x45, 0x1D, 0x0F, 0x7C, 0x88, 0xB3, 0x1C, 0x7C, 0x5B, 0x2D, 0x8E, 0xF6, 0xF3, 0xC9, 0x23, 0xC0, 0x43, 0xF0, 0xA5, 0x5B, 0x18, 0x8D, 0x8E, 0xBB, 0x55, 0x8C, 0xB8, 0x5D, 0x38, 0xD3, 0x34, 0xFD, 0x7C, 0x17, 0x57, 0x43, 0xA3, 0x1D, 0x18, 0x6C, 0xDE, 0x33, 0x21, 0x2C, 0xB5, 0x2A, 0xFF, 0x3C, 0xE1, 0xB1, 0x29, 0x40, 0x18, 0x11, 0x8D, 0x7C, 0x84, 0xA7, 0x0A, 0x72, 0xD6, 0x86, 0xC4, 0x03, 0x19, 0xC8, 0x07, 0x29, 0x7A, 0xCA, 0x95, 0x0C, 0xD9, 0x96, 0x9F, 0xAB, 0xD0, 0x0A, 0x50, 0x9B, 0x02, 0x46, 0xD3, 0x08, 0x3D, 0x66, 0xA4, 0x5D, 0x41, 0x9F, 0x9C, 0x7C, 0xBD, 0x89, 0x4B, 0x22, 0x19, 0x26, 0xBA, 0xAB, 0xA2, 0x5E, 0xC3, 0x55, 0xE9, 0x32, 0x0B, 0x3B, }; static unsigned char dh2048_g[] = { 0x02, }; DH *dh; if ((dh = DH_new()) == NULL) return (NULL); dh->p = BN_bin2bn(dh2048_p, sizeof(dh2048_p), NULL); dh->g = BN_bin2bn(dh2048_g, sizeof(dh2048_g), NULL); if ((dh->p == NULL) || (dh->g == NULL)) { DH_free(dh); return (NULL); } return (dh); } DH * #if PROTOTYPES GetDH4096(void) #else GetDH4096() #endif { static unsigned char dh4096_p[] = { 0xFA, 0x14, 0x72, 0x52, 0xC1, 0x4D, 0xE1, 0x5A, 0x49, 0xD4, 0xEF, 0x09, 0x2D, 0xC0, 0xA8, 0xFD, 0x55, 0xAB, 0xD7, 0xD9, 0x37, 0x04, 0x28, 0x09, 0xE2, 0xE9, 0x3E, 0x77, 0xE2, 0xA1, 0x7A, 0x18, 0xDD, 0x46, 0xA3, 0x43, 0x37, 0x23, 0x90, 0x97, 0xF3, 0x0E, 0xC9, 0x03, 0x50, 0x7D, 0x65, 0xCF, 0x78, 0x62, 0xA6, 0x3A, 0x62, 0x22, 0x83, 0xA1, 0x2F, 0xFE, 0x79, 0xBA, 0x35, 0xFF, 0x59, 0xD8, 0x1D, 0x61, 0xDD, 0x1E, 0x21, 0x13, 0x17, 0xFE, 0xCD, 0x38, 0x87, 0x9E, 0xF5, 0x4F, 0x79, 0x10, 0x61, 0x8D, 0xD4, 0x22, 0xF3, 0x5A, 0xED, 0x5D, 0xEA, 0x21, 0xE9, 0x33, 0x6B, 0x48, 0x12, 0x0A, 0x20, 0x77, 0xD4, 0x25, 0x60, 0x61, 0xDE, 0xF6, 0xB4, 0x4F, 0x1C, 0x63, 0x40, 0x8B, 0x3A, 0x21, 0x93, 0x8B, 0x79, 0x53, 0x51, 0x2C, 0xCA, 0xB3, 0x7B, 0x29, 0x56, 0xA8, 0xC7, 0xF8, 0xF4, 0x7B, 0x08, 0x5E, 0xA6, 0xDC, 0xA2, 0x45, 0x12, 0x56, 0xDD, 0x41, 0x92, 0xF2, 0xDD, 0x5B, 0x8F, 0x23, 0xF0, 0xF3, 0xEF, 0xE4, 0x3B, 0x0A, 0x44, 0xDD, 0xED, 0x96, 0x84, 0xF1, 0xA8, 0x32, 0x46, 0xA3, 0xDB, 0x4A, 0xBE, 0x3D, 0x45, 0xBA, 0x4E, 0xF8, 0x03, 0xE5, 0xDD, 0x6B, 0x59, 0x0D, 0x84, 0x1E, 0xCA, 0x16, 0x5A, 0x8C, 0xC8, 0xDF, 0x7C, 0x54, 0x44, 0xC4, 0x27, 0xA7, 0x3B, 0x2A, 0x97, 0xCE, 0xA3, 0x7D, 0x26, 0x9C, 0xAD, 0xF4, 0xC2, 0xAC, 0x37, 0x4B, 0xC3, 0xAD, 0x68, 0x84, 0x7F, 0x99, 0xA6, 0x17, 0xEF, 0x6B, 0x46, 0x3A, 0x7A, 0x36, 0x7A, 0x11, 0x43, 0x92, 0xAD, 0xE9, 0x9C, 0xFB, 0x44, 0x6C, 0x3D, 0x82, 0x49, 0xCC, 0x5C, 0x6A, 0x52, 0x42, 0xF8, 0x42, 0xFB, 0x44, 0xF9, 0x39, 0x73, 0xFB, 0x60, 0x79, 0x3B, 0xC2, 0x9E, 0x0B, 0xDC, 0xD4, 0xA6, 0x67, 0xF7, 0x66, 0x3F, 0xFC, 0x42, 0x3B, 0x1B, 0xDB, 0x4F, 0x66, 0xDC, 0xA5, 0x8F, 0x66, 0xF9, 0xEA, 0xC1, 0xED, 0x31, 0xFB, 0x48, 0xA1, 0x82, 0x7D, 0xF8, 0xE0, 0xCC, 0xB1, 0xC7, 0x03, 0xE4, 0xF8, 0xB3, 0xFE, 0xB7, 0xA3, 0x13, 0x73, 0xA6, 0x7B, 0xC1, 0x0E, 0x39, 0xC7, 0x94, 0x48, 0x26, 0x00, 0x85, 0x79, 0xFC, 0x6F, 0x7A, 0xAF, 0xC5, 0x52, 0x35, 0x75, 0xD7, 0x75, 0xA4, 0x40, 0xFA, 0x14, 0x74, 0x61, 0x16, 0xF2, 0xEB, 0x67, 0x11, 0x6F, 0x04, 0x43, 0x3D, 0x11, 0x14, 0x4C, 0xA7, 0x94, 0x2A, 0x39, 0xA1, 0xC9, 0x90, 0xCF, 0x83, 0xC6, 0xFF, 0x02, 0x8F, 0xA3, 0x2A, 0xAC, 0x26, 0xDF, 0x0B, 0x8B, 0xBE, 0x64, 0x4A, 0xF1, 0xA1, 0xDC, 0xEE, 0xBA, 0xC8, 0x03, 0x82, 0xF6, 0x62, 0x2C, 0x5D, 0xB6, 0xBB, 0x13, 0x19, 0x6E, 0x86, 0xC5, 0x5B, 0x2B, 0x5E, 0x3A, 0xF3, 0xB3, 0x28, 0x6B, 0x70, 0x71, 0x3A, 0x8E, 0xFF, 0x5C, 0x15, 0xE6, 0x02, 0xA4, 0xCE, 0xED, 0x59, 0x56, 0xCC, 0x15, 0x51, 0x07, 0x79, 0x1A, 0x0F, 0x25, 0x26, 0x27, 0x30, 0xA9, 0x15, 0xB2, 0xC8, 0xD4, 0x5C, 0xCC, 0x30, 0xE8, 0x1B, 0xD8, 0xD5, 0x0F, 0x19, 0xA8, 0x80, 0xA4, 0xC7, 0x01, 0xAA, 0x8B, 0xBA, 0x53, 0xBB, 0x47, 0xC2, 0x1F, 0x6B, 0x54, 0xB0, 0x17, 0x60, 0xED, 0x79, 0x21, 0x95, 0xB6, 0x05, 0x84, 0x37, 0xC8, 0x03, 0xA4, 0xDD, 0xD1, 0x06, 0x69, 0x8F, 0x4C, 0x39, 0xE0, 0xC8, 0x5D, 0x83, 0x1D, 0xBE, 0x6A, 0x9A, 0x99, 0xF3, 0x9F, 0x0B, 0x45, 0x29, 0xD4, 0xCB, 0x29, 0x66, 0xEE, 0x1E, 0x7E, 0x3D, 0xD7, 0x13, 0x4E, 0xDB, 0x90, 0x90, 0x58, 0xCB, 0x5E, 0x9B, 0xCD, 0x2E, 0x2B, 0x0F, 0xA9, 0x4E, 0x78, 0xAC, 0x05, 0x11, 0x7F, 0xE3, 0x9E, 0x27, 0xD4, 0x99, 0xE1, 0xB9, 0xBD, 0x78, 0xE1, 0x84, 0x41, 0xA0, 0xDF, }; static unsigned char dh4096_g[] = { 0x02, }; DH *dh; if ((dh = DH_new()) == NULL) return (NULL); dh->p = BN_bin2bn(dh4096_p, sizeof(dh4096_p), NULL); dh->g = BN_bin2bn(dh4096_g, sizeof(dh4096_g), NULL); if ((dh->p == NULL) || (dh->g == NULL)) { DH_free(dh); return (NULL); } return (dh); } DH * #if PROTOTYPES TmpDHCallback(SSL *ssl, int is_export, int keylength) #else TmpDHCallback(ssl, is_export, keylength) SSL *ssl; int is_export; int keylength; #endif { CONDDEBUG((1, "TmpDHCallback(): asked for a DH key length %u", keylength)); switch (keylength) { case 512: if (dh512 == (DH *)0) dh512 = GetDH512(); return dh512; case 1024: if (dh1024 == (DH *)0) dh1024 = GetDH1024(); return dh1024; case 2048: if (dh2048 == (DH *)0) dh2048 = GetDH2048(); return dh2048; default: if (dh4096 == (DH *)0) dh4096 = GetDH4096(); return dh4096; } } void #if PROTOTYPES SetupSSL(void) #else SetupSSL() #endif { if (ctx == (SSL_CTX *)0) { char *ciphers; SSL_load_error_strings(); if (!SSL_library_init()) { Error("SetupSSL(): SSL_library_init() failed"); Bye(EX_SOFTWARE); } if ((ctx = SSL_CTX_new(SSLv23_method())) == (SSL_CTX *)0) { Error("SetupSSL(): SSL_CTX_new() failed"); Bye(EX_SOFTWARE); } if (SSL_CTX_set_default_verify_paths(ctx) != 1) { Error ("SetupSSL(): could not load SSL default CA file and/or directory"); Bye(EX_SOFTWARE); } if (config->sslcredentials != (char *)0) { if (SSL_CTX_use_certificate_chain_file (ctx, config->sslcredentials) != 1) { Error ("SetupSSL(): could not load SSL certificate from `%s'", config->sslcredentials); Bye(EX_SOFTWARE); } if (SSL_CTX_use_PrivateKey_file (ctx, config->sslcredentials, SSL_FILETYPE_PEM) != 1) { Error ("SetupSSL(): could not load SSL private key from `%s'", config->sslcredentials); Bye(EX_SOFTWARE); } ciphers = "ALL:!LOW:!EXP:!MD5:!aNULL:@STRENGTH"; } else { ciphers = "ALL:!LOW:!EXP:!MD5:@STRENGTH"; } SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, SSLVerifyCallback); SSL_CTX_set_options(ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_SINGLE_DH_USE); SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_AUTO_RETRY); SSL_CTX_set_tmp_dh_callback(ctx, TmpDHCallback); if (SSL_CTX_set_cipher_list(ctx, ciphers) != 1) { Error("SetupSSL(): setting SSL cipher list failed"); Bye(EX_SOFTWARE); } /* might want to turn this back on at some point, but i can't * see why right now. */ SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); } } #endif void #if PROTOTYPES ReopenLogfile(void) #else ReopenLogfile() #endif { static int tag = 1; /* redirect stdout and stderr to the logfile. * * first time through any problems will show up (stderr still there). * after that, all bets are off...probably not see the errors (well, * aside from the tail of the old logfile, if it was rolled). */ if (config->daemonmode != FLAGTRUE) return; close(1); /* so, if we aren't in daemon mode, we just return before closing * anything. if we are, there are two possibilities. first, if * logfile is set, we close fd 1, open a file, etc. all should be * well. if logfile isn't set, we end up closing fd 1 and 2 and * returning (in case the logfile was set and then unset [config * file change]). */ if (config->logfile == (char *)0) { close(2); return; } if (1 != open(config->logfile, O_WRONLY | O_CREAT | O_APPEND, 0644)) { tag = 0; Error("ReopenLogfile(): open(%s): %s", config->logfile, strerror(errno)); Bye(EX_TEMPFAIL); } close(2); dup(1); if (isMaster && tag) { Msg(MyVersion()); Msg(startedMsg->string); } tag = 0; } void #if PROTOTYPES ReopenUnifiedlog(void) #else ReopenUnifiedlog() #endif { /* close any existing */ if (unifiedlog != (CONSFILE *)0) FileClose(&unifiedlog); /* return if we aren't opening again */ if (config->unifiedlog == (char *)0) return; /* open a new one */ if ((unifiedlog = FileOpen(config->unifiedlog, O_WRONLY | O_CREAT | O_APPEND, 0644)) == (CONSFILE *)0) { Error("ReopenUnifiedlog(): open(%s): %s", config->unifiedlog, strerror(errno)); return; } } /* become a daemon (ksb) */ static void #if PROTOTYPES Daemonize() #else Daemonize() #endif { int res; #if !HAVE_SETSID int td; #endif Msg("daemonizing"); SimpleSignal(SIGQUIT, SIG_IGN); SimpleSignal(SIGINT, SIG_IGN); #if defined(SIGTTOU) SimpleSignal(SIGTTOU, SIG_IGN); #endif #if defined(SIGTTIN) SimpleSignal(SIGTTIN, SIG_IGN); #endif #if defined(SIGTSTP) SimpleSignal(SIGTSTP, SIG_IGN); #endif #if defined(SIGXFSZ) SimpleSignal(SIGXFSZ, SIG_IGN); #endif fflush(stdout); fflush(stderr); switch (res = fork()) { case -1: Error("Daemonize(): fork(): %s", strerror(errno)); Bye(EX_TEMPFAIL); case 0: thepid = getpid(); break; default: Bye(EX_OK); } ReopenLogfile(); /* Further disassociate this process from the terminal * Maybe this will allow you to start a daemon from rsh, * i.e. with no controlling terminal. */ #if HAVE_SETSID setsid(); #else tcsetpgrp(0, getpid()); /* lose our controlling terminal */ if (-1 != (td = open("/dev/tty", O_RDWR, 0600))) { ioctl(td, TIOCNOTTY, (char *)0); close(td); } #endif } /* output a long message to the user (ksb) */ static void #if PROTOTYPES Usage(int wantfull) #else Usage(wantfull) int wantfull; #endif { static char u_terse[] = "[-7dDEFhinoRSuvV] [-a type] [-m max] [-M master] [-p port] [-b port] [-c cred] [-C config] [-P passwd] [-L logfile] [-O min] [-U logfile]"; static char *full[] = { "7 strip the high bit off all console data", "a type set the default access type", "b port base port for secondary channel (any by default)", #if HAVE_OPENSSL "c cred load an SSL certificate and key from the PEM encoded file", #else "c cred ignored - encryption not compiled into code", #endif "C config give a new config file to the server process", "d become a daemon, redirecting stdout/stderr to logfile", "D enable debug output, sent to stderr", #if HAVE_OPENSSL "E don't require encrypted client connections", #else "E ignored - encryption not compiled into code", #endif "F do not automatically reinitialize failed consoles", "h output this message", "i initialize console connections on demand", "L logfile give a new logfile path to the server process", "m max maximum consoles managed per process", #if USE_UNIX_DOMAIN_SOCKETS "M master directory that holds the Unix domain sockets", #else "M master address to listen on (all addresses by default)", #endif "n obsolete - see -u", "o reopen downed console on client connect", "O min reopen all downed consoles every minutes", #if USE_UNIX_DOMAIN_SOCKETS "p port ignored - Unix domain sockets compiled into code", #else "p port port to listen on", #endif "P passwd give a new passwd file to the server process", "R disable automatic client redirection", "S syntax check of configuration file", "u copy \"unloved\" console data to stdout", "U logfile copy all console data to the \"unified\" logfile", "v be verbose on startup", "V output version info", (char *)0 }; fprintf(stderr, "usage: %s %s\n", progname, u_terse); if (wantfull) { int i; for (i = 0; full[i] != (char *)0; i++) fprintf(stderr, "\t%s\n", full[i]); } } /* show the user our version info (ksb) */ static void #if PROTOTYPES Version() #else Version() #endif { static STRING *acA1 = (STRING *)0; static STRING *acA2 = (STRING *)0; int i; char *optionlist[] = { #if HAVE_DMALLOC "dmalloc", #endif #if USE_LIBWRAP "libwrap", #endif #if HAVE_OPENSSL "openssl", #endif #if HAVE_PAM "pam", #endif #if TRUST_REVERSE_DNS "trustrevdns", #endif #if USE_UNIX_DOMAIN_SOCKETS "uds", #endif (char *)0 }; if (acA1 == (STRING *)0) acA1 = AllocString(); if (acA2 == (STRING *)0) acA2 = AllocString(); isMultiProc = 0; Msg(MyVersion()); Msg("default access type `%c'", defConfig.defaultaccess); Msg("default escape sequence `%s%s'", FmtCtl(DEFATTN, acA1), FmtCtl(DEFESC, acA2)); Msg("default configuration in `%s'", CONFIGFILE); Msg("default password in `%s'", defConfig.passwdfile); Msg("default logfile is `%s'", defConfig.logfile); Msg("default pidfile is `%s'", PIDFILE); Msg("default limit is %d member%s per group", MAXMEMB, MAXMEMB == 1 ? "" : "s"); #if USE_UNIX_DOMAIN_SOCKETS Msg("default socket directory `%s'", UDSDIR); #else Msg("default primary port referenced as `%s'", defConfig.primaryport); Msg("default secondary base port referenced as `%s'", defConfig.secondaryport); #endif BuildString((char *)0, acA1); if (optionlist[0] == (char *)0) BuildString("none", acA1); for (i = 0; optionlist[i] != (char *)0; i++) { if (i == 0) BuildString(optionlist[i], acA1); else { BuildString(", ", acA1); BuildString(optionlist[i], acA1); } } Msg("options: %s", acA1->string); #if HAVE_DMALLOC BuildString((char *)0, acA1); BuildStringChar('0' + DMALLOC_VERSION_MAJOR, acA1); BuildStringChar('.', acA1); BuildStringChar('0' + DMALLOC_VERSION_MINOR, acA1); BuildStringChar('.', acA1); BuildStringChar('0' + DMALLOC_VERSION_PATCH, acA1); #if defined(DMALLOC_VERSION_BETA) if (DMALLOC_VERSION_BETA != 0) { BuildString("-b", acA1); BuildStringChar('0' + DMALLOC_VERSION_BETA, acA1); } #endif Msg("dmalloc version: %s", acA1->string); #endif #if HAVE_OPENSSL Msg("openssl version: %s", OPENSSL_VERSION_TEXT); #endif Msg("built with `%s'", CONFIGINVOCATION); if (fVerbose) printf(COPYRIGHT); Bye(EX_OK); } void #if PROTOTYPES DestroyDataStructures(void) #else DestroyDataStructures() #endif { GRPENT *pGE; REMOTE *pRC; ACCESS *pAC; while (pGroups != (GRPENT *)0) { pGE = pGroups->pGEnext; DestroyGroup(pGroups); pGroups = pGE; } while (pRCList != (REMOTE *)0) { pRC = pRCList->pRCnext; DestroyRemoteConsole(pRCList); pRCList = pRC; } while (pACList != (ACCESS *)0) { pAC = pACList->pACnext; DestroyAccessList(pACList); pACList = pAC; } DestroyConsentUsers(&pADList); DestroyConsentUsers(&pLUList); DestroyConfig(pConfig); DestroyConfig(optConf); DestroyConfig(config); #if HAVE_OPENSSL if (ctx != (SSL_CTX *)0) SSL_CTX_free(ctx); if (dh512 != (DH *)0) DH_free(dh512); if (dh1024 != (DH *)0) DH_free(dh1024); if (dh2048 != (DH *)0) DH_free(dh2048); if (dh4096 != (DH *)0) DH_free(dh4096); #endif if (myAddrs != (struct in_addr *)0) free(myAddrs); DestroyBreakList(); DestroyStrings(); DestroyUserList(); if (substData != (SUBST *)0) free(substData); } void #if PROTOTYPES SummarizeDataStructures(void) #else SummarizeDataStructures() #endif { GRPENT *pGE; REMOTE *pRC; ACCESS *pAC; STRING *str; CONSENT *pCE; NAMES *usr; int count; long size; long total = 0; extern STRING *allStrings; if (!fDebug) return; for (size = 0, count = 0, pGE = pGroups; pGE != (GRPENT *)0; pGE = pGE->pGEnext, count++) { size += sizeof(GRPENT); } CONDDEBUG((1, "Memory Usage (GRPENT objects): %ld (%d)", size, count)); total += size; for (size = 0, count = 0, pGE = pGroups; pGE != (GRPENT *)0; pGE = pGE->pGEnext) { for (pCE = pGE->pCElist; pCE != (CONSENT *)0; pCE = pCE->pCEnext, count++) { size += strlen(pCE->server) + sizeof(CONSENT); if (pCE->host != (char *)0) size += strlen(pCE->server); if (pCE->device != (char *)0) size += strlen(pCE->device); if (pCE->exec != (char *)0) size += strlen(pCE->exec); if (pCE->master != (char *)0) size += strlen(pCE->master); if (pCE->logfile != (char *)0) size += strlen(pCE->logfile); if (pCE->initcmd != (char *)0) size += strlen(pCE->initcmd); if (pCE->execSlave != (char *)0) size += strlen(pCE->execSlave); if (pCE->motd != (char *)0) size += strlen(pCE->motd); if (pCE->idlestring != (char *)0) size += strlen(pCE->idlestring); if (pCE->replstring != (char *)0) size += strlen(pCE->replstring); if (pCE->fdlog != (CONSFILE *)0) size += sizeof(CONSFILE); if (pCE->cofile != (CONSFILE *)0) size += sizeof(CONSFILE); if (pCE->initfile != (CONSFILE *)0) size += sizeof(CONSFILE); if (pCE->aliases != (NAMES *)0) { NAMES *n; for (n = pCE->aliases; n != (NAMES *)0; n = n->next) { size += sizeof(NAMES) + strlen(n->name); } } if (pCE->ro) { CONSENTUSERS *u; for (u = pCE->ro; u != (CONSENTUSERS *)0; u = u->next) { size += sizeof(CONSENTUSERS) + strlen(u->user->name); } } if (pCE->rw) { CONSENTUSERS *u; for (u = pCE->rw; u != (CONSENTUSERS *)0; u = u->next) { size += sizeof(CONSENTUSERS) + strlen(u->user->name); } } } } CONDDEBUG((1, "Memory Usage (CONSENT objects): %ld (%d)", size, count)); total += size; for (size = 0, count = 0, pRC = pRCList; pRC != (REMOTE *)0; pRC = pRC->pRCnext, count++) { size += strlen(pRC->rserver) + strlen(pRC->rhost) + sizeof(REMOTE); if (pRC->aliases != (NAMES *)0) { NAMES *n; for (n = pRC->aliases; n != (NAMES *)0; n = n->next) { size += sizeof(NAMES) + strlen(n->name); } } } CONDDEBUG((1, "Memory Usage (REMOTE objects): %ld (%d)", size, count)); total += size; for (size = 0, count = 0, pAC = pACList; pAC != (ACCESS *)0; pAC = pAC->pACnext, count++) { size += strlen(pAC->pcwho) + sizeof(ACCESS); } CONDDEBUG((1, "Memory Usage (ACCESS objects): %ld (%d)", size, count)); total += size; for (size = 0, count = 0, str = allStrings; str != (STRING *)0; str = str->next, count++) { size += str->allocated + sizeof(STRING); } CONDDEBUG((1, "Memory Usage (STRING objects): %ld (%d)", size, count)); total += size; for (size = 0, count = 0, usr = userList; usr != (NAMES *)0; usr = usr->next, count++) { size += strlen(usr->name) + sizeof(NAMES); } CONDDEBUG((1, "Memory Usage (userList objects): %ld (%d)", size, count)); total += size; CONDDEBUG((1, "Memory Usage (total): %ld", total)); } void #if PROTOTYPES DumpDataStructures(void) #else DumpDataStructures() #endif { GRPENT *pGE; CONSENT *pCE; REMOTE *pRC; #if HAVE_DMALLOC && DMALLOC_MARK_MAIN CONDDEBUG((1, "DumpDataStructures(): dmalloc / MarkMain")); dmalloc_log_changed(dmallocMarkMain, 1, 0, 1); #endif #define EMPTYSTR(x) x == (char *)0 ? "(null)" : x #define FLAGSTR(x) x == FLAGTRUE ? "true" : (x == FLAGFALSE ? "false" : "unset") if (!fDebug) return; SummarizeDataStructures(); for (pGE = pGroups; pGE != (GRPENT *)0; pGE = pGE->pGEnext) { CONDDEBUG((1, "DumpDataStructures(): group: id=%u port=%hu, pid=%lu, imembers=%d", pGE->id, pGE->port, (unsigned long)pGE->pid, pGE->imembers)); for (pCE = pGE->pCElist; pCE != (CONSENT *)0; pCE = pCE->pCEnext) { switch (pCE->type) { case DEVICE: CONDDEBUG((1, "DumpDataStructures(): server=%s, type=DEVICE", EMPTYSTR(pCE->server))); CONDDEBUG((1, "DumpDataStructures(): baud=%s, parity=%s, device=%s", pCE->baud->acrate, pCE->parity->key, EMPTYSTR(pCE->device))); break; case EXEC: CONDDEBUG((1, "DumpDataStructures(): server=%s, type=EXEC", EMPTYSTR(pCE->server))); CONDDEBUG((1, "DumpDataStructures(): execSlave=%s, exec=%s, ipid=%lu", EMPTYSTR(pCE->execSlave), EMPTYSTR(pCE->exec), (unsigned long)pCE->ipid)); CONDDEBUG((1, "DumpDataStructures(): execuid=%d, execgid=%d", pCE->execuid, pCE->execgid)); break; case HOST: CONDDEBUG((1, "DumpDataStructures(): server=%s, type=HOST", EMPTYSTR(pCE->server))); CONDDEBUG((1, "DumpDataStructures(): host=%s, raw=%s, netport=%hu, port=%hu, telnetState=%d", EMPTYSTR(pCE->host), FLAGSTR(pCE->raw), pCE->netport, pCE->port, pCE->telnetState)); break; case NOOP: CONDDEBUG((1, "DumpDataStructures(): server=%s, type=NOOP", EMPTYSTR(pCE->server))); break; case UDS: CONDDEBUG((1, "DumpDataStructures(): server=%s, type=UDS", EMPTYSTR(pCE->server))); CONDDEBUG((1, "DumpDataStructures(): uds=%s", EMPTYSTR(pCE->uds))); break; case UNKNOWNTYPE: CONDDEBUG((1, "DumpDataStructures(): server=%s, type=UNKNOWNTYPE", EMPTYSTR(pCE->server))); break; } if (pCE->aliases != (NAMES *)0) { NAMES *n; for (n = pCE->aliases; n != (NAMES *)0; n = n->next) { CONDDEBUG((1, "DumpDataStructures(): alias=%s", n->name)); } } CONDDEBUG((1, "DumpDataStructures(): fup=%d, fronly=%d, logfile=%s, breakNum=%d", pCE->fup, pCE->fronly, EMPTYSTR(pCE->logfile), pCE->breakNum)); CONDDEBUG((1, "DumpDataStructures(): mark=%d, nextMark=%ld, autoReup=%hu, downHard=%s", pCE->mark, pCE->nextMark, pCE->autoReUp, FLAGSTR(pCE->downHard))); CONDDEBUG((1, "DumpDataStructures(): nolog=%d, cofile=%d, activitylog=%s, breaklog=%s", pCE->nolog, FileFDNum(pCE->cofile), FLAGSTR(pCE->activitylog), FLAGSTR(pCE->breaklog))); CONDDEBUG((1, "DumpDataStructures(): ixon=%s, ixany=%s, ixoff=%s", FLAGSTR(pCE->ixon), FLAGSTR(pCE->ixany), FLAGSTR(pCE->ixoff))); CONDDEBUG((1, "DumpDataStructures(): autoreinit=%s, hupcl=%s, cstopb=%s, ondemand=%s", FLAGSTR(pCE->autoreinit), FLAGSTR(pCE->hupcl), FLAGSTR(pCE->cstopb), FLAGSTR(pCE->ondemand))); #if defined(CRTSCTS) CONDDEBUG((1, "DumpDataStructures(): crtscts=%s", FLAGSTR(pCE->crtscts))); #endif CONDDEBUG((1, "DumpDataStructures(): reinitoncc=%s, striphigh=%s", FLAGSTR(pCE->reinitoncc), FLAGSTR(pCE->striphigh))); CONDDEBUG((1, "DumpDataStructures(): unloved=%s, login=%s", FLAGSTR(pCE->unloved), FLAGSTR(pCE->login))); CONDDEBUG((1, "DumpDataStructures(): initpid=%lu, initcmd=%s, initfile=%d", (unsigned long)pCE->initpid, EMPTYSTR(pCE->initcmd), FileFDNum(pCE->initfile))); CONDDEBUG((1, "DumpDataStructures(): inituid=%d, initgid=%d", pCE->inituid, pCE->initgid)); CONDDEBUG((1, "DumpDataStructures(): motd=%s, idletimeout=%d, idlestring=%s, replstring=%s", EMPTYSTR(pCE->motd), pCE->idletimeout, EMPTYSTR(pCE->idlestring), EMPTYSTR(pCE->replstring))); if (pCE->ro) { CONSENTUSERS *u; for (u = pCE->ro; u != (CONSENTUSERS *)0; u = u->next) { CONDDEBUG((1, "DumpDataStructures(): ro=%s%s", (u->not ? "!" : ""), u->user->name)); } } if (pCE->rw) { CONSENTUSERS *u; for (u = pCE->rw; u != (CONSENTUSERS *)0; u = u->next) { CONDDEBUG((1, "DumpDataStructures(): rw=%s%s", (u->not ? "!" : ""), u->user->name)); } } CONDDEBUG((1, "DumpDataStructures(): ------")); } } for (pRC = pRCList; (REMOTE *)0 != pRC; pRC = pRC->pRCnext) { CONDDEBUG((1, "DumpDataStructures(): remote: rserver=%s, rhost=%s", EMPTYSTR(pRC->rserver), EMPTYSTR(pRC->rhost))); if (pRC->aliases != (NAMES *)0) { NAMES *n; for (n = pRC->aliases; n != (NAMES *)0; n = n->next) { CONDDEBUG((1, "DumpDataStructures(): alias=%s", n->name)); } } } } /* This makes sure a directory exists and tries to create it if it * doesn't. returns 0 for success, -1 for error */ #if USE_UNIX_DOMAIN_SOCKETS int #if PROTOTYPES VerifyEmptyDirectory(char *d) #else VerifyEmptyDirectory(d) char *d; #endif { struct stat dstat; DIR *dir; struct dirent *de; STRING *path = (STRING *)0; int retval = 0; while (1) { if (stat(d, &dstat) == -1) { if (errno == ENOENT) { if (mkdir(d, 0755) == -1) { Error("mkdir(%s): %s", d, strerror(errno)); return -1; } CONDDEBUG((1, "VerifyEmptyDirectory: created `%s'", d)); continue; } else { Error("stat(%s): %s", d, strerror(errno)); return -1; } } if (S_ISDIR(dstat.st_mode)) break; return -1; } /* now make sure it's empty...erase anything you see, etc */ if ((dir = opendir(d)) == (DIR *) 0) { Error("opendir(%s): %s", d, strerror(errno)); return -1; } while ((de = readdir(dir)) != (struct dirent *)0) { if ((strcmp(de->d_name, ".") == 0) || (strcmp(de->d_name, "..") == 0)) continue; /* we're going to just let the user deal with non-empty directories */ Error("non-empty directory `%s'", d); retval = -1; break; /* this is probably too extreme. if someone happens to point conserver * at /etc, for example, it could (if running as root) nuke the password * database, config files, etc. too many important files could be * shredded with a small typo. */ #if 0 if (path == (STRING *)0) path = AllocString(); BuildStringPrint(path, "%s/%s", d, de->d_name); if (stat(path->string, &dstat) == -1) { Error("stat(%s): %s", path->string, strerror(errno)); retval = -1; break; } if (S_ISDIR(dstat.st_mode)) { if (rmdir(path->string) != 0) { Error("rmdir(%s): %s", path->string, strerror(errno)); retval = -1; break; } } else { if (unlink(path->string) != 0) { Error("unlink(%s): %s", path->string, strerror(errno)); retval = -1; break; } } #endif } if (path != (STRING *)0) DestroyString(path); return retval; } #endif /* find out where/who we are (ksb) * parse optons * read in the config file, open the log file * spawn the kids to drive the console groups * become the master server * shutdown with grace * exit happy */ int #if PROTOTYPES main(int argc, char **argv) #else main(argc, argv) int argc; char **argv; #endif { int i; FILE *fpConfig = (FILE *)0; static char acOpts[] = "7a:b:c:C:dDEFhiL:m:M:noO:p:P:RSuU:Vv"; extern int optopt; extern char *optarg; struct passwd *pwd; char *origuser = (char *)0; char *curuser = (char *)0; int curuid = 0; GRPENT *pGE = (GRPENT *)0; #if !USE_UNIX_DOMAIN_SOCKETS #if HAVE_INET_ATON struct in_addr inetaddr; #endif #endif isMultiProc = 1; /* make sure stuff has the pid */ thepid = getpid(); if ((char *)0 == (progname = strrchr(argv[0], '/'))) { progname = argv[0]; } else { ++progname; } setpwent(); /* if we read from stdin (by accident) we don't wanna block. * we just don't want any more input at this point. */ close(0); if (0 != open("/dev/null", O_RDWR, 0644)) { Error("open(/dev/null): %s", strerror(errno)); Bye(EX_OSFILE); } #if HAVE_SETLINEBUF setlinebuf(stdout); setlinebuf(stderr); #endif #if HAVE_SETVBUF setvbuf(stdout, NULL, _IOLBF, BUFSIZ); setvbuf(stderr, NULL, _IOLBF, BUFSIZ); #endif /* prep the config options */ if ((optConf = (CONFIG *)calloc(1, sizeof(CONFIG))) == (CONFIG *)0) OutOfMem(); if ((config = (CONFIG *)calloc(1, sizeof(CONFIG))) == (CONFIG *)0) OutOfMem(); while (EOF != (i = getopt(argc, argv, acOpts))) { switch (i) { case '7': fStrip = 1; break; case 'a': optConf->defaultaccess = *optarg; if (isupper((int)(optConf->defaultaccess))) optConf->defaultaccess = tolower(optConf->defaultaccess); switch (optConf->defaultaccess) { case 'r': case 'a': case 't': break; default: Error("unknown access type `%s'", optarg); Bye(EX_USAGE); } break; case 'b': if ((optConf->secondaryport = StrDup(optarg)) == (char *)0) OutOfMem(); break; case 'c': #if HAVE_OPENSSL if ((optConf->sslcredentials = StrDup(optarg)) == (char *)0) OutOfMem(); #endif break; case 'C': pcConfig = optarg; break; case 'd': optConf->daemonmode = FLAGTRUE; break; case 'D': fDebug++; break; case 'E': #if HAVE_OPENSSL optConf->sslrequired = FLAGFALSE; #endif break; case 'F': fNoautoreup = 1; break; case 'h': Usage(1); Bye(EX_OK); case 'i': fNoinit = 1; break; case 'L': if ((optConf->logfile = StrDup(optarg)) == (char *)0) OutOfMem(); break; case 'm': cMaxMemb = atoi(optarg); if (cMaxMemb <= 0) { Error("ignoring invalid -m option (%d <= 0)", cMaxMemb); cMaxMemb = MAXMEMB; } break; case 'M': interface = StrDup(optarg); break; case 'n': /* noop now */ break; case 'o': /* try reopening downed consoles on connect */ fReopen = 1; break; case 'O': /* How often to try opening all down consoles, in minutes */ optConf->reinitcheck = atoi(optarg); break; case 'p': if ((optConf->primaryport = StrDup(optarg)) == (char *)0) OutOfMem(); break; case 'P': if ((optConf->passwdfile = StrDup(optarg)) == (char *)0) OutOfMem(); break; case 'R': optConf->redirect = FLAGFALSE; break; case 'S': fSyntaxOnly++; break; case 'u': fAll = 1; break; case 'U': if ((optConf->unifiedlog = StrDup(optarg)) == (char *)0) OutOfMem(); break; case 'V': fVersion = 1; break; case 'v': fVerbose = 1; break; case '\?': Usage(0); Bye(EX_USAGE); default: Error("option %c needs a parameter", optopt); Bye(EX_USAGE); } } if (fVersion) { Version(); Bye(EX_OK); } Msg(MyVersion()); #if HAVE_GETLOGIN origuser = getlogin(); #endif curuid = getuid(); if ((struct passwd *)0 != (pwd = getpwuid(curuid))) curuser = pwd->pw_name; /* chuck any empty username */ if (curuser != (char *)0 && curuser[0] == '\000') curuser = (char *)0; if (startedMsg == (STRING *)0) startedMsg = AllocString(); if (curuser == (char *)0) if (origuser == (char *)0) BuildStringPrint(startedMsg, "started as uid %d by uid %d", curuid, curuid); else BuildStringPrint(startedMsg, "started as uid %d by `%s'", curuid, origuser); else BuildStringPrint(startedMsg, "started as `%s' by `%s'", curuser, (origuser == (char *)0) ? curuser : origuser); endpwent(); Msg("%s", startedMsg->string); #if HAVE_GETSPNAM && !HAVE_PAM if (!fSyntaxOnly && (geteuid() != 0)) { Msg("warning: running as a non-root user - any shadow password usage will most likely fail!"); } #endif if (fSyntaxOnly) Msg("performing configuration file syntax check"); #if USE_UNIX_DOMAIN_SOCKETS /* Don't do any redirects if we're purely local * (but it allows them to see where remote consoles are) */ optConf->redirect = FLAGFALSE; if (interface == (char *)0) interface = UDSDIR; #else /* set up the address to bind to */ if (interface == (char *)0 || (interface[0] == '*' && interface[1] == '\000')) bindAddr = INADDR_ANY; else { # if HAVE_INET_ATON if (inet_aton(interface, &inetaddr) == 0) { Error("inet_aton(%s): %s", interface, "invalid IP address"); Bye(EX_OSERR); } bindAddr = inetaddr.s_addr; # else bindAddr = inet_addr(interface); if (bindAddr == (in_addr_t) (-1)) { Error("inet_addr(%s): %s", interface, "invalid IP address"); Bye(EX_OSERR); } # endif } if (fDebug) { struct in_addr ba; ba.s_addr = bindAddr; CONDDEBUG((1, "main(): bind address set to `%s'", inet_ntoa(ba))); } #endif /* must do all this so IsMe() works right */ if (gethostname(myHostname, MAXHOSTNAME) != 0) { Error("gethostname(): %s", strerror(errno)); Bye(EX_OSERR); } ProbeInterfaces(bindAddr); /* initialize the timers */ for (i = 0; i < T_MAX; i++) timers[i] = (time_t)0; /* read the config file */ if ((FILE *)0 == (fpConfig = fopen(pcConfig, "r"))) { Error("fopen(%s): %s", pcConfig, strerror(errno)); Bye(EX_NOINPUT); } ReadCfg(pcConfig, fpConfig); fclose(fpConfig); #if !USE_UNIX_DOMAIN_SOCKETS /* set up the port to bind to */ if (optConf->primaryport != (char *)0) config->primaryport = StrDup(optConf->primaryport); else if (pConfig->primaryport != (char *)0) config->primaryport = StrDup(pConfig->primaryport); else config->primaryport = StrDup(defConfig.primaryport); if (config->primaryport == (char *)0) OutOfMem(); /* Look for non-numeric characters */ for (i = 0; config->primaryport[i] != '\000'; i++) if (!isdigit((int)config->primaryport[i])) break; if (config->primaryport[i] == '\000') { /* numeric only */ bindPort = atoi(config->primaryport); } else { /* non-numeric only */ struct servent *pSE; if ((struct servent *)0 == (pSE = getservbyname(config->primaryport, "tcp"))) { Error("getservbyname(%s) failed", config->primaryport); Bye(EX_OSERR); } else { bindPort = ntohs((unsigned short)pSE->s_port); } } /* set up the secondary port to bind to */ if (optConf->secondaryport != (char *)0) config->secondaryport = StrDup(optConf->secondaryport); else if (pConfig->secondaryport != (char *)0) config->secondaryport = StrDup(pConfig->secondaryport); else config->secondaryport = StrDup(defConfig.secondaryport); if (config->secondaryport == (char *)0) OutOfMem(); /* Look for non-numeric characters */ for (i = 0; config->secondaryport[i] != '\000'; i++) if (!isdigit((int)config->secondaryport[i])) break; if (config->secondaryport[i] == '\000') { /* numeric only */ bindBasePort = atoi(config->secondaryport); } else { /* non-numeric only */ struct servent *pSE; if ((struct servent *)0 == (pSE = getservbyname(config->secondaryport, "tcp"))) { Error("getservbyname(%s) failed", config->secondaryport); Bye(EX_OSERR); } else { bindBasePort = ntohs((unsigned short)pSE->s_port); } } #endif if (optConf->passwdfile != (char *)0) config->passwdfile = StrDup(optConf->passwdfile); else if (pConfig->passwdfile != (char *)0) config->passwdfile = StrDup(pConfig->passwdfile); else config->passwdfile = StrDup(defConfig.passwdfile); if (config->passwdfile == (char *)0) OutOfMem(); if (optConf->logfile != (char *)0) config->logfile = StrDup(optConf->logfile); else if (pConfig->logfile != (char *)0) config->logfile = StrDup(pConfig->logfile); else config->logfile = StrDup(defConfig.logfile); if (config->logfile == (char *)0) OutOfMem(); if (optConf->reinitcheck != 0) config->reinitcheck = optConf->reinitcheck; else if (pConfig->reinitcheck != 0) config->reinitcheck = pConfig->reinitcheck; else config->reinitcheck = defConfig.reinitcheck; if (optConf->defaultaccess != '\000') config->defaultaccess = optConf->defaultaccess; else if (pConfig->defaultaccess != '\000') config->defaultaccess = pConfig->defaultaccess; else config->defaultaccess = defConfig.defaultaccess; if (optConf->daemonmode != FLAGUNKNOWN) config->daemonmode = optConf->daemonmode; else if (pConfig->daemonmode != FLAGUNKNOWN) config->daemonmode = pConfig->daemonmode; else config->daemonmode = defConfig.daemonmode; if (optConf->redirect != FLAGUNKNOWN) config->redirect = optConf->redirect; else if (pConfig->redirect != FLAGUNKNOWN) config->redirect = pConfig->redirect; else config->redirect = defConfig.redirect; if (optConf->autocomplete != FLAGUNKNOWN) config->autocomplete = optConf->autocomplete; else if (pConfig->autocomplete != FLAGUNKNOWN) config->autocomplete = pConfig->autocomplete; else config->autocomplete = defConfig.autocomplete; if (optConf->loghostnames != FLAGUNKNOWN) config->loghostnames = optConf->loghostnames; else if (pConfig->loghostnames != FLAGUNKNOWN) config->loghostnames = pConfig->loghostnames; else config->loghostnames = defConfig.loghostnames; if (optConf->unifiedlog != (char *)0) { config->unifiedlog = StrDup(optConf->unifiedlog); if (config->unifiedlog == (char *)0) OutOfMem(); } else if (pConfig->unifiedlog != (char *)0) { config->unifiedlog = StrDup(pConfig->unifiedlog); if (config->unifiedlog == (char *)0) OutOfMem(); } else if (defConfig.unifiedlog != (char *)0) { config->unifiedlog = StrDup(defConfig.unifiedlog); if (config->unifiedlog == (char *)0) OutOfMem(); } if (optConf->initdelay != 0) config->initdelay = optConf->initdelay; else if (pConfig->initdelay != 0) config->initdelay = pConfig->initdelay; else config->initdelay = defConfig.initdelay; #if HAVE_OPENSSL if (optConf->sslrequired != FLAGUNKNOWN) config->sslrequired = optConf->sslrequired; else if (pConfig->sslrequired != FLAGUNKNOWN) config->sslrequired = pConfig->sslrequired; else config->sslrequired = defConfig.sslrequired; if (optConf->sslcredentials != (char *)0) config->sslcredentials = StrDup(optConf->sslcredentials); else if (pConfig->sslcredentials != (char *)0) config->sslcredentials = StrDup(pConfig->sslcredentials); else config->sslcredentials = StrDup(defConfig.sslcredentials); #endif #if HAVE_SETPROCTITLE if (optConf->setproctitle != FLAGUNKNOWN) config->setproctitle = optConf->setproctitle; else if (pConfig->setproctitle != FLAGUNKNOWN) config->setproctitle = pConfig->setproctitle; else config->setproctitle = defConfig.setproctitle; #endif #if HAVE_DMALLOC && DMALLOC_MARK_MAIN dmallocMarkMain = dmalloc_mark(); #endif if (pGroups == (GRPENT *)0 && pRCList == (REMOTE *)0) { Error("no consoles found in configuration file"); } else if (fSyntaxOnly) { /* short-circuit */ #if USE_UNIX_DOMAIN_SOCKETS } else if (VerifyEmptyDirectory(interface) == -1) { Error("Master(): %s: unusable socket directory", interface); #endif } else { #if HAVE_OPENSSL /* Prep the SSL layer */ SetupSSL(); #endif if (config->daemonmode == FLAGTRUE) Daemonize(); ReopenUnifiedlog(); /* if no one can use us we need to come up with a default */ if (pACList == (ACCESS *)0) SetDefAccess(myAddrs, myHostname); /* spawn all the children, so fix kids has an initial pid */ for (pGE = pGroups; pGE != (GRPENT *)0; pGE = pGE->pGEnext) { if (pGE->imembers == 0) continue; Spawn(pGE, -1); Verbose("group #%d pid %lu on port %hu", pGE->id, (unsigned long)pGE->pid, pGE->port); } #if HAVE_SETPROCTITLE if (config->setproctitle == FLAGTRUE) { REMOTE *pRC; GRPENT *pGE; int local = 0, remote = 0; for (pGE = pGroups; pGE != (GRPENT *)0; pGE = pGE->pGEnext) local += pGE->imembers; for (pRC = pRCList; (REMOTE *)0 != pRC; pRC = pRC->pRCnext) remote++; # if USE_UNIX_DOMAIN_SOCKETS setproctitle("master: port 0, %d local, %d remote", local, remote); #else setproctitle("master: port %hu, %d local, %d remote", bindPort, local, remote); #endif } #endif if (fVerbose) { ACCESS *pACtmp; for (pACtmp = pACList; pACtmp != (ACCESS *)0; pACtmp = pACtmp->pACnext) { Verbose("access type `%c' for `%s'", pACtmp->ctrust, pACtmp->pcwho); } } pRCUniq = FindUniq(pRCList); /* output unique console server peers? */ if (fVerbose) { REMOTE *pRC; for (pRC = pRCUniq; (REMOTE *)0 != pRC; pRC = pRC->pRCuniq) { Verbose("peer server on `%s'", pRC->rhost); } } fflush(stdout); fflush(stderr); Master(); /* stop putting kids back, and shoot them */ SimpleSignal(SIGCHLD, SIG_DFL); SignalKids(SIGTERM); } if (unifiedlog != (CONSFILE *)0) FileClose(&unifiedlog); DumpDataStructures(); Msg("terminated"); endpwent(); if (fSyntaxOnly && fErrorPrinted) Bye(EX_DATAERR); else Bye(EX_OK); return EX_OK; /* never gets here clears the compiler warning */ }