/* Copyright (C) 2003 Frédéric Giudicelli (contact_nos@yahoo.com). All rights reserved. This product includes cryptographic software written by Eric Young (eay@cryptsoft.com) This program is released under the GPL with the additional exemption that compiling, linking, and/or using OpenSSL is allowed. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "Conf.h" #include #include #include #include #include #include "SockServerADMIN.h" #include "OcspServers.h" #include "svintl.h" #include #ifndef _WIN32 #include #include #include #include #include #include #define stricmp strcasecmp #ifndef LOCALEDIR #define LOCALEDIR "/usr/share/locale" #endif #endif #include #ifndef SIGUSR1 #define SIGUSR1 10 #endif SockServerADMIN * sockADMIN = NULL; PKIX_Central * central = NULL;; OcspServers ocspServers; void SigHandler(int code); #ifdef _WINNT #define MAIN ServiceInitialization #else #define MAIN main #endif int MAIN(int argc, char * argv[]); bool FullyStarted = false; bool Stopping = false; bool Stopped = false; #include void usage(char * progname) { #ifdef _WIN32 printf(_sv("Usage: %s -config config.conf -version\n"), progname); #else printf(_sv("Usage: %s -config config.conf [-user username] [-detach] [-pidfile file] [-version]\n"), progname); #endif } int MAIN(int argc, char * argv[]) { // Initialisation d'openssl /* MemCheck_start(); CRYPTO_malloc_debug_init(); */ #ifdef _WIN32 WSADATA StartupData; WSAStartup(0x101, &StartupData); #ifndef _DEBUG #ifndef NO_GETTEXT char path[MAX_PATH]; char * lastOcc; *path=0; GetModuleFileName(GetModuleHandle(NULL), path, sizeof(path)); lastOcc = strrchr(path, '\\'); if(lastOcc) { *lastOcc=0; } bindtextdomain("newpki-server", path); bindtextdomain("newpki-lib", path); #endif #endif #else #ifndef NO_GETTEXT bindtextdomain("newpki-server", LOCALEDIR); bindtextdomain("newpki-lib", LOCALEDIR); setlocale(LC_ALL,""); #endif #endif INIT_OPENSSL(); char * configfile; Config PkiConf; ServerConf conf; mString err; int argc_ctr; #ifndef _WIN32 bool Detach = false; char * user = NULL; char * pidfile = NULL; configfile = NULL; struct passwd * userinfo = NULL; pid_t pid; FILE * pidfp; #endif char * prog; prog = argv[0]; for(argc_ctr = 1; argc_ctr < argc; argc_ctr++) { if(strcmp(argv[argc_ctr], "-config") == 0) { if(argc_ctr+1 >= argc) { usage(prog); CLEAN_OPENSSL(); return 1; } argc_ctr++; configfile = argv[argc_ctr]; } else if(strcmp(argv[argc_ctr], "-version") == 0) { #ifndef _WIN32 printf("%s\n", NEWPKI_VERSION); #else MessageBox(NULL, NEWPKI_VERSION, _sv("Version"), MB_OK); #endif return 0; } #ifndef _WIN32 else if(strcmp(argv[argc_ctr], "-user") == 0) { if(argc_ctr+1 >= argc) { usage(prog); CLEAN_OPENSSL(); return 1; } argc_ctr++; user = argv[argc_ctr]; } else if(strcmp(argv[argc_ctr], "-pidfile") == 0) { if(argc_ctr+1 >= argc) { usage(prog); CLEAN_OPENSSL(); return 1; } argc_ctr++; pidfile = argv[argc_ctr]; } else if(strcmp(argv[argc_ctr], "-detach") == 0) { Detach = true; } #endif else { usage(prog); CLEAN_OPENSSL(); return 1; } } if(!configfile) { usage(prog); CLEAN_OPENSSL(); return 1; } if(!PkiConf.LoadConf(configfile)) { CLEAN_OPENSSL(); return 1; } InitFileLog(PkiConf.get_LogFile().c_str(), PkiConf.get_DebugLevel()); LogInsertDelimiter(""); LogInsertDelimiter(""); LogInsertDelimiter("******************************************************************************************************************************************************************"); LogInsertDelimiter("******************************************************************************************************************************************************************"); LogInsertDelimiter(""); LogInsertDelimiter(""); #ifndef _WIN32 if(user) { userinfo = getpwnam(user); if(!userinfo) { LogInFile(PKI_LOG, "Unknown user: %s", user); CLEAN_OPENSSL(); CleanFileLog(); return 1; } } #endif try { central = new PKIX_Central(PkiConf); } catch(ExceptionNewPKI e) { ERR_to_mstring(err); LogInFile(PKI_LOG, err.c_str()); CLEAN_OPENSSL(); CleanFileLog(); return 1; } if(!central) { NEWPKIerr(PKI_ERROR_TXT, ERROR_MALLOC); ERR_to_mstring(err); LogInFile(PKI_LOG, err.c_str()); CLEAN_OPENSSL(); CleanFileLog(); return 1; } sockADMIN = new SockServerADMIN(); if(!sockADMIN) { delete central; NEWPKIerr(PKI_ERROR_TXT, ERROR_MALLOC); ERR_to_mstring(err); LogInFile(PKI_LOG, err.c_str()); CLEAN_OPENSSL(); CleanFileLog(); return 1; } if(!sockADMIN->Load(central)) { delete sockADMIN; delete central; sockADMIN = NULL; NEWPKIerr(PKI_ERROR_TXT, ERROR_MALLOC); ERR_to_mstring(err); LogInFile(PKI_LOG, err.c_str()); CLEAN_OPENSSL(); CleanFileLog(); return 1; } signal(SIGABRT, SigHandler); signal(SIGINT, SigHandler); signal(SIGTERM, SigHandler); signal(SIGUSR1, SigHandler); conf.Load(PkiConf); conf.set_ServerName("ADMIN"); if(!sockADMIN->Start(conf)) { delete sockADMIN; delete central; sockADMIN = NULL; NEWPKIerr(PKI_ERROR_TXT, ERROR_ABORT); ERR_to_mstring(err); LogInFile(PKI_LOG, err.c_str()); CLEAN_OPENSSL(); CleanFileLog(); return 1; } // Yield the OCSP servers handler to // the Publication entities ocspServers.Load(central); central->SetOcspServersHandler(&ocspServers); FullyStarted = true; #ifndef _WIN32 // Shall we detach ? if(Detach) { pid = fork(); switch(pid) { case 0: break; case -1: LogInFile(PKI_LOG, _sv("Failed to fork: %s"), strerror(errno)); delete sockADMIN; delete central; sockADMIN = NULL; CLEAN_OPENSSL(); CleanFileLog(); return 1; break; default: exit(0); } } if(pidfile) { pidfp = fopen(pidfile, "w"); if(!pidfp) { LogInFile(PKI_LOG, _sv("Failed to create PID file: %s - %s"), pidfile, strerror(errno)); delete sockADMIN; delete central; sockADMIN = NULL; CLEAN_OPENSSL(); CleanFileLog(); return 1; } fprintf(pidfp, "%d", getpid()); fclose(pidfp); } // Shall we run as another user ? if(userinfo) { setuid(userinfo->pw_uid); setgid(userinfo->pw_gid); } #endif // Let the PKI know we're all set NewpkiThread::SignalStart(); while(!Stopped) NewpkiThread::Sleep(100); delete central; central = NULL; ocspServers.PrintStats(false); sockADMIN->PrintStats(false); delete sockADMIN; sockADMIN = NULL; CLEAN_OPENSSL(); #ifdef _WIN32 if(WSAIsBlocking()) WSACancelBlockingCall(); WSACleanup(); #endif CleanFileLog(); return 0; } void SigHandler(int code) { switch(code) { case SIGABRT: case SIGINT: case SIGTERM: if(Stopping) return; Stopping = true; PkiClient::CancelAllConnections(); NewpkiThread::SignalStop(); ocspServers.Stop(); if(sockADMIN) sockADMIN->Stop(); Stopped = true; break; case SIGUSR1: ocspServers.PrintStats(true); if(sockADMIN) sockADMIN->PrintStats(true); break; } } // Gestion du service NT #ifdef _WINNT #define SERVICE_NAME "NewPKIServer" #define SERVICE_DISPLAY "NewPKI Server Service" SERVICE_STATUS ServiceStatus; SERVICE_STATUS_HANDLE ServiceStatusHandle; void WINAPI ServiceStart (DWORD argc, LPTSTR *argv); void WINAPI ServiceCtrlHandler (DWORD opcode); HANDLE Threadhandle; DWORD WINAPI ThreadProcMain( LPVOID lpParameter // thread data ); int m_argc; char * * m_argv; DWORD ExitCode; void WINAPI ServiceCtrlHandler (DWORD Opcode) { switch(Opcode) { case SERVICE_CONTROL_PAUSE: ServiceStatus.dwWin32ExitCode = 0; ServiceStatus.dwCurrentState = SERVICE_PAUSED; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwWaitHint = 0; if(Threadhandle) SuspendThread(Threadhandle); break; case SERVICE_CONTROL_CONTINUE: ServiceStatus.dwWin32ExitCode = 0; ServiceStatus.dwCurrentState = SERVICE_RUNNING; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwWaitHint = 0; if(Threadhandle) ResumeThread(Threadhandle); break; case SERVICE_CONTROL_STOP: // Do whatever it takes to stop here. ServiceStatus.dwWin32ExitCode = 0; ServiceStatus.dwCurrentState = SERVICE_STOPPED; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwWaitHint = 0; PkiClient::CancelAllConnections(); NewpkiThread::SignalStop(); ocspServers.Stop(); if(sockADMIN) sockADMIN->Stop(); Stopped = true; if(Threadhandle) { WaitForSingleObject(Threadhandle, 10000); TerminateThread(Threadhandle, 0); CloseHandle(Threadhandle); Threadhandle = NULL; } break; case SERVICE_CONTROL_INTERROGATE: // Fall through to send current status. break; default: break; } // Send current status. SetServiceStatus (ServiceStatusHandle, &ServiceStatus); return; } void WINAPI ServiceStart (DWORD argc, LPTSTR *argv) { ServiceStatus.dwServiceType = SERVICE_WIN32; ServiceStatus.dwCurrentState = SERVICE_START_PENDING; ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE; ServiceStatus.dwWin32ExitCode = 0; ServiceStatus.dwServiceSpecificExitCode = 0; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwWaitHint = 0; ServiceStatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, ServiceCtrlHandler); if (ServiceStatusHandle == (SERVICE_STATUS_HANDLE)0) { return; } //On va d�arrer le connexion Threadhandle=CreateThread(NULL, 0, ThreadProcMain, NULL, 0, 0); if(!Threadhandle) { ServiceStatus.dwWin32ExitCode = 0; ServiceStatus.dwCurrentState = SERVICE_STOPPED; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwWaitHint = 0; ServiceStatus.dwWin32ExitCode = GetLastError(); SetServiceStatus (ServiceStatusHandle, &ServiceStatus); return; } //We wait for the servers to start before //setting our status to RUNNING while(1) { if(GetExitCodeThread(Threadhandle, &ExitCode)) { if(ExitCode == STILL_ACTIVE) { if(FullyStarted) { break; } else { Sleep(50); } } else { ServiceStatus.dwCurrentState = SERVICE_STOPPED; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwWaitHint = 0; ServiceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; ServiceStatus.dwServiceSpecificExitCode = 0; SetServiceStatus (ServiceStatusHandle, &ServiceStatus); return; } } else { ServiceStatus.dwCurrentState = SERVICE_STOPPED; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwWaitHint = 0; ServiceStatus.dwWin32ExitCode = GetLastError(); ServiceStatus.dwServiceSpecificExitCode = 0; SetServiceStatus (ServiceStatusHandle, &ServiceStatus); return; } } // Initialization complete - report running status. ServiceStatus.dwCurrentState = SERVICE_RUNNING; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwWaitHint = 0; if (!SetServiceStatus (ServiceStatusHandle, &ServiceStatus)) { return; } return; } int main(int argc, char * argv[]) { SC_HANDLE hSCManager; SC_HANDLE hService; m_argc = argc; m_argv = argv; if(argc >= 2) { //Maintenant on install le service if(strcmp(argv[1], "-install") == 0) { char AppPath[MAX_PATH]; char AppName[MAX_PATH * 2]; char * lastOcc; *AppPath=0; GetModuleFileName(NULL, AppName, sizeof(AppName)); GetModuleFileName(NULL, AppPath, sizeof(AppName)); lastOcc = strrchr(AppPath, '\\'); if(lastOcc) { *lastOcc=0; } strcat(AppName, " -config \""); strcat(AppName, AppPath); strcat(AppName, "\\config.conf\""); hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE); if(!hSCManager) { return 1; } hService = CreateService(hSCManager, SERVICE_NAME, SERVICE_DISPLAY, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, AppName, NULL, NULL, NULL, NULL, NULL); if(!hService) { CloseServiceHandle(hSCManager); return 1; } CloseServiceHandle(hSCManager); CloseServiceHandle(hService); return 0; } //Maintenant on desinstall le service else if(strcmp(argv[1], "-uninstall") == 0) { SERVICE_STATUS ServiceStatus; hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE); if(!hSCManager) { return 1; } hService = OpenService(hSCManager, SERVICE_NAME, SERVICE_ALL_ACCESS); if(!hService) { CloseServiceHandle(hSCManager); return 1; } // On le stoppe d'abord ControlService(hService, SERVICE_CONTROL_STOP, &ServiceStatus); if(!DeleteService(hService)) { CloseServiceHandle(hSCManager); CloseServiceHandle(hService); return 1; } CloseServiceHandle(hSCManager); CloseServiceHandle(hService); return 0; } else if(strcmp(argv[1], "-version") == 0) { MessageBox(NULL, NEWPKI_VERSION, _sv("Version"), MB_OK); return 0; } } SERVICE_TABLE_ENTRY DispatchTable[] = { { SERVICE_NAME, ServiceStart }, { NULL, NULL } }; StartServiceCtrlDispatcher( DispatchTable ); return 0; } DWORD WINAPI ThreadProcMain( LPVOID lpParameter // thread data ) { // Handle error condition if (MAIN(m_argc, m_argv) != NO_ERROR) { return 0; } return 1; } #endif