bool PathUtils::isSymLink(const Firebird::PathName& path) { struct stat st, lst; if (stat(path.c_str(), &st) != 0) return false; if (lstat(path.c_str(), &lst) != 0) return false; return st.st_ino != lst.st_ino; }
pid_t UTIL_start_process(const char* process, const char* process2, char** argv, const char* prog_name) { /************************************** * * U T I L _ s t a r t _ p r o c e s s * ************************************** * * Functional description * * This function is used to create the specified process, * * Returns Codes: * -1 Process spawn failed. * pid Successful creation. PID is returned. * * Note: Make sure that the argument list ends with a null * and the first argument is large enough to hold the complete * expanded process name. (MAXPATHLEN recommended) * **************************************/ fb_assert(process != NULL); fb_assert(argv != NULL); // prepend Firebird home directory to the program name // choose correct (super/superclassic) image - to be removed in 3.0 Firebird::PathName string = fb_utils::getPrefix(fb_utils::FB_DIR_SBIN, process); if (access(string.c_str(), X_OK) < 0) { string = fb_utils::getPrefix(fb_utils::FB_DIR_SBIN, process2); } if (prog_name) { gds__log("%s: guardian starting %s\n", prog_name, string.c_str()); } // add place in argv for visibility to "ps" strcpy(argv[0], string.c_str()); #if (defined SOLARIS) pid_t pid = fork1(); if (!pid) { if (execv(string.c_str(), argv) == -1) { //ib_fprintf(ib_stderr, "Could not create child process %s with args %s\n", string, argv); } exit(FINI_ERROR); } #else pid_t pid = vfork(); if (!pid) { execv(string.c_str(), argv); _exit(FINI_ERROR); } #endif return (pid); }
bool ModuleLoader::isLoadableModule(const Firebird::PathName& module) { struct stat sb; if (-1 == stat(module.c_str(), &sb)) return false; if ( ! (sb.st_mode & S_IFREG) ) // Make sure it is a plain file return false; if ( -1 == access(module.c_str(), R_OK | X_OK)) return false; return true; }
// Probably file arrived on the disk bool notifyDatabaseName(const Firebird::PathName& file) { #ifdef HAVE_ID_BY_NAME // notifyDatabaseName typically causes changes in aliasesConf() // cause it's called only from Config created for missing database. // Therefore always take write lock at once. WriteLockGuard guard(aliasesConf().rwLock, "notifyDatabaseName"); DbName* db = aliasesConf().dbHash.lookup(file); if (!db) return true; if (db->id) return true; UCharBuffer id; os_utils::getUniqueFileId(file.c_str(), id); if (id.hasData()) { aliasesConf().linkId(db, id); return true; } #endif return false; }
void LEX_init( void *file) { /************************************** * * L E X _ i n i t * ************************************** * * Functional description * Initialize for lexical scanning. While we're at it, open a * scratch trace file to keep all input. * **************************************/ const Firebird::PathName filename = Firebird::TempFile::create(SCRATCH); strcpy(trace_file_name, filename.c_str()); trace_file = fopen(trace_file_name, "w+b"); if (!trace_file) { DDL_err(276); /* msg 276: couldn't open scratch file */ } input_file = (FILE*) file; DDL_char = DDL_buffer; dudleyGlob.DDL_token.tok_position = 0; dudleyGlob.DDL_description = false; dudleyGlob.DDL_line = 1; }
// moves DB path information (from limbo transaction) to another buffer void getDbPathInfo(unsigned int& itemsLength, const unsigned char*& items, unsigned int& bufferLength, unsigned char*& buffer, Firebird::Array<unsigned char>& newItemsBuffer, const Firebird::PathName& dbpath) { if (itemsLength && items) { const unsigned char* ptr = (const unsigned char*) memchr(items, fb_info_tra_dbpath, itemsLength); if (ptr) { newItemsBuffer.add(items, itemsLength); newItemsBuffer.remove(ptr - items); items = newItemsBuffer.begin(); --itemsLength; unsigned int len = dbpath.length(); if (len + 3 > bufferLength) { len = bufferLength - 3; } bufferLength -= (len + 3); *buffer++ = fb_info_tra_dbpath; *buffer++ = len; *buffer++ = len >> 8; memcpy(buffer, dbpath.c_str(), len); buffer += len; } } }
bool FileObject::renameFile(const Firebird::PathName new_filename) { if (append_mutex != INVALID_HANDLE_VALUE) { if (WaitForSingleObject(append_mutex, INFINITE) != WAIT_OBJECT_0) system_call_failed::raise("WaitForSingleObject"); } if (!MoveFile(filename.c_str(), new_filename.c_str())) { DWORD rename_err = GetLastError(); if (rename_err == ERROR_ALREADY_EXISTS || rename_err == ERROR_FILE_NOT_FOUND) { // Another process renames our file just now. Open it again. reopen(); return false; } if (append_mutex != INVALID_HANDLE_VALUE) ReleaseMutex(append_mutex); fatal_exception::raiseFmt("IO error (%d) renaming file: %s", rename_err, filename.c_str()); } else reopen(); return true; }
void LEX_init() { /************************************** * * L E X _ i n i t * ************************************** * * Functional description * Initialize for lexical scanning. While we're at it, open a * scratch trace file to keep all input. * **************************************/ const Firebird::PathName filename = TempFile::create(SCRATCH); strcpy(trace_file_name, filename.c_str()); trace_file = fopen(trace_file_name, "w+b"); #ifdef UNIX unlink(trace_file_name); #endif if (!trace_file) IBERROR(61); // Msg 61 couldn't open scratch file QLI_token = (qli_tok*) ALLOCPV(type_tok, MAXSYMLEN); QLI_line = (qli_line*) ALLOCPV(type_line, 0); QLI_line->line_size = sizeof(QLI_line->line_data); QLI_line->line_ptr = QLI_line->line_data; QLI_line->line_type = line_stdin; QLI_line->line_source_file = stdin; QLI_semi = false; input_file = stdin; HSH_init(); }
void ClntAuthBlock::extractDataFromPluginTo(Firebird::ClumpletWriter& user_id) { // Add user login name if (cliOrigUserName.hasData()) { HANDSHAKE_DEBUG(fprintf(stderr, "Cli: extractDataFromPluginTo: cliOrigUserName=%s\n", cliOrigUserName.c_str())); user_id.insertString(CNCT_login, cliOrigUserName); } // Add plugin name Firebird::PathName pluginName = getPluginName(); if (pluginName.hasData()) { HANDSHAKE_DEBUG(fprintf(stderr, "Cli: extractDataFromPluginTo: pluginName=%s\n", pluginName.c_str())); user_id.insertPath(CNCT_plugin_name, pluginName); } // Add plugin list if (pluginList.hasData()) { user_id.insertPath(CNCT_plugin_list, pluginList); } // This is specially tricky field - user_id is limited to 255 bytes per entry, // and we have no ways to override this limit cause it can be sent to any version server. // Therefore divide data into 254-byte parts, leaving first byte for the number of that part. // This appears more reliable than put them in strict order. addMultiPartConnectParameter(dataFromPlugin, user_id, CNCT_specific_data); // Client's wirecrypt requested level user_id.insertInt(CNCT_client_crypt, clntConfig->getWireCrypt(WC_CLIENT)); }
void LEX_edit(SLONG start, SLONG stop) { /************************************** * * L E X _ e d i t * ************************************** * * Functional description * Dump the last full statement into a scratch file, then * push the scratch file on the input stack. * **************************************/ const Firebird::PathName filename = TempFile::create(SCRATCH); FILE* scratch = fopen(filename.c_str(), "w+b"); if (!scratch) IBERROR(61); // Msg 61 couldn't open scratch file #ifdef WIN_NT stop--; #endif if (fseek(trace_file, start, 0)) { fseek(trace_file, 0, 2); IBERROR(59); // Msg 59 fseek failed } while (++start <= stop) { const SSHORT c = getc(trace_file); if (c == EOF) break; putc(c, scratch); } fclose(scratch); if (gds__edit(filename.c_str(), TRUE)) LEX_push_file(filename.c_str(), true); unlink(filename.c_str()); fseek(trace_file, 0, 2); }
ConfigFile::ConfigFile(MemoryPool& p, const Firebird::PathName& file, USHORT fl, ConfigCache* cache) : AutoStorage(p), parameters(getPool()), flags(fl), includeLimit(0), filesCache(cache) { MainStream s(file.c_str(), flags & ERROR_WHEN_MISS); parse(&s); }
inline void setPrefixIfNotEmpty(const Firebird::PathName& prefix, SSHORT arg_type) { /************************************** * * s e t P r e f i x I f N o t E m p t y * ************************************** * * Functional description * Helper for ISC_set_prefix * **************************************/ if (prefix.hasData()) { // ignore here return value of gds__get_prefix(): // it will never fail with our good arguments gds__get_prefix(arg_type, prefix.c_str()); } }
// Build full file name in specified directory Firebird::PathName getPrefix(unsigned int prefType, const char* name) { Firebird::PathName s; char tmp[MAXPATHLEN]; const char* configDir[] = { FB_BINDIR, FB_SBINDIR, FB_CONFDIR, FB_LIBDIR, FB_INCDIR, FB_DOCDIR, FB_UDFDIR, FB_SAMPLEDIR, FB_SAMPLEDBDIR, FB_HELPDIR, FB_INTLDIR, FB_MISCDIR, FB_SECDBDIR, FB_MSGDIR, FB_LOGDIR, FB_GUARDDIR, FB_PLUGDIR }; fb_assert(FB_NELEM(configDir) == Firebird::IConfigManager::DIR_COUNT); fb_assert(prefType < Firebird::IConfigManager::DIR_COUNT); if (! bootBuild()) { if (prefType != Firebird::IConfigManager::DIR_CONF && prefType != Firebird::IConfigManager::DIR_MSG && configDir[prefType][0]) { // Value is set explicitly and is not environment overridable PathUtils::concatPath(s, configDir[prefType], name); return s; } } switch(prefType) { case Firebird::IConfigManager::DIR_BIN: case Firebird::IConfigManager::DIR_SBIN: #ifdef WIN_NT s = ""; #else s = "bin"; #endif break; case Firebird::IConfigManager::DIR_CONF: case Firebird::IConfigManager::DIR_LOG: case Firebird::IConfigManager::DIR_GUARD: case Firebird::IConfigManager::DIR_SECDB: s = ""; break; case Firebird::IConfigManager::DIR_LIB: #ifdef WIN_NT s = ""; #else s = "lib"; #endif break; case Firebird::IConfigManager::DIR_PLUGINS: s = "plugins"; break; case Firebird::IConfigManager::DIR_INC: s = "include"; break; case Firebird::IConfigManager::DIR_DOC: s = "doc"; break; case Firebird::IConfigManager::DIR_UDF: s = "UDF"; break; case Firebird::IConfigManager::DIR_SAMPLE: s = "examples"; break; case Firebird::IConfigManager::DIR_SAMPLEDB: s = "examples/empbuild"; break; case Firebird::IConfigManager::DIR_HELP: s = "help"; break; case Firebird::IConfigManager::DIR_INTL: s = "intl"; break; case Firebird::IConfigManager::DIR_MISC: s = "misc"; break; case Firebird::IConfigManager::DIR_MSG: gds__prefix_msg(tmp, name); return tmp; default: fb_assert(false); break; } if (s.hasData() && name[0]) { s += '/'; } s += name; gds__prefix(tmp, s.c_str()); return tmp; }
THREAD_ENTRY_DECLARE start_and_watch_server(THREAD_ENTRY_PARAM) { /************************************** * * s t a r t _ a n d _ w a t c h _ s e r v e r * ************************************** * * Functional description * * This function is where the server process is created and * the thread waits for this process to exit. * **************************************/ Firebird::ContextPoolHolder threadContext(getDefaultMemoryPool()); HANDLE procHandle = NULL; bool done = true; const UINT error_mode = SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX | SEM_NOALIGNMENTFAULTEXCEPT; SC_HANDLE hScManager = 0, hService = 0; // get the guardian startup information const short option = Config::getGuardianOption(); char prefix_buffer[MAXPATHLEN]; GetModuleFileName(NULL, prefix_buffer, sizeof(prefix_buffer)); Firebird::PathName path = prefix_buffer; path = path.substr(0, path.rfind(PathUtils::dir_sep) + 1) + FBSERVER; path = "\"" + path + "\""; Firebird::PathName prog_name = path + " -a -n"; // if the guardian is set to FOREVER then set the error mode UINT old_error_mode = 0; if (option == START_FOREVER) old_error_mode = SetErrorMode(error_mode); // Spawn the new process do { SERVICE_STATUS ServiceStatus; char out_buf[1024]; BOOL success; int error = 0; if (service_flag) { if (hService) { while ((QueryServiceStatus(hService, &ServiceStatus) == TRUE) && (ServiceStatus.dwCurrentState != SERVICE_STOPPED)) { Sleep(500); } } procHandle = CreateMutex(NULL, FALSE, mutex_name->c_str()); // start as a service. If the service can not be found or // fails to start, close the handle to the mutex and set // success = FALSE if (!hScManager) hScManager = OpenSCManager(NULL, NULL, GENERIC_READ); if (!hService) { hService = OpenService(hScManager, remote_name->c_str(), GENERIC_READ | GENERIC_EXECUTE); } success = StartService(hService, 0, NULL); if (success != TRUE) error = GetLastError(); // if the server is already running, then inform it that it should // open the guardian mutex so that it may be governed. if (!error || error == ERROR_SERVICE_ALREADY_RUNNING) { // Make sure that it is actually ready to receive commands. // If we were the one who started it, then it will need a few // seconds to get ready. while ((QueryServiceStatus(hService, &ServiceStatus) == TRUE) && (ServiceStatus.dwCurrentState != SERVICE_RUNNING)) { Sleep(500); } ControlService(hService, SERVICE_CREATE_GUARDIAN_MUTEX, &ServiceStatus); success = TRUE; } } else { HWND hTmpWnd = FindWindow(szClassName, szWindowName); if (hTmpWnd == NULL) { STARTUPINFO si; SECURITY_ATTRIBUTES sa; PROCESS_INFORMATION pi; ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; success = CreateProcess(NULL, const_cast<char*>(prog_name.c_str()), &sa, NULL, FALSE, 0, NULL, NULL, &si, &pi); if (success != TRUE) error = GetLastError(); procHandle = pi.hProcess; // TMN: 04 Aug 2000 - closed the handle that previously leaked. CloseHandle(pi.hThread); } else { SendMessage(hTmpWnd, WM_COMMAND, (WPARAM) IDM_GUARDED, 0); DWORD server_pid; GetWindowThreadProcessId(hTmpWnd, &server_pid); procHandle = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, server_pid); if (procHandle == NULL) { error = GetLastError(); success = FALSE; } else { success = TRUE; } } } if (success != TRUE) { // error creating new process char szMsgString[256]; LoadString(hInstance_gbl, IDS_CANT_START_THREAD, szMsgString, 256); sprintf(out_buf, "%s : %s errno : %d", path.c_str(), szMsgString, error); write_log(IDS_CANT_START_THREAD, out_buf); if (service_flag) { SERVICE_STATUS status_info; // wait a second to get the mutex handle (just in case) and // then close it WaitForSingleObject(procHandle, 1000); CloseHandle(procHandle); hService = OpenService(hScManager, remote_name->c_str(), GENERIC_READ | GENERIC_EXECUTE); ControlService(hService, SERVICE_CONTROL_STOP, &status_info); CloseServiceHandle(hScManager); CloseServiceHandle(hService); CNTL_stop_service(); //service_name->c_str()); } else { MessageBox(NULL, out_buf, NULL, MB_OK | MB_ICONSTOP); PostMessage(hWndGbl, WM_CLOSE, 0, 0); } return 0; } else { char szMsgString[256]; LoadString(hInstance_gbl, IDS_STARTING_GUARD, szMsgString, 256); sprintf(out_buf, "%s: %s\n", szMsgString, path.c_str()); write_log(IDS_LOG_START, out_buf); } // wait for process to terminate DWORD exit_status; if (service_flag) { while (WaitForSingleObject(procHandle, 500) == WAIT_OBJECT_0) { ReleaseMutex(procHandle); Sleep(100); } const int ret_val = WaitForSingleObject(procHandle, INFINITE); if (ret_val == WAIT_ABANDONED) exit_status = CRASHED; else if (ret_val == WAIT_OBJECT_0) exit_status = NORMAL_EXIT; CloseHandle(procHandle); } else { while (WaitForSingleObject(procHandle, INFINITE) == WAIT_FAILED) ; GetExitCodeProcess(procHandle, &exit_status); CloseHandle(procHandle); } if (exit_status != NORMAL_EXIT) { // check for startup error if (exit_status == STARTUP_ERROR) { char szMsgString[256]; LoadString(hInstance_gbl, IDS_STARTUP_ERROR, szMsgString, 256); sprintf(out_buf, "%s: %s (%lu)\n", path.c_str(), szMsgString, exit_status); write_log(IDS_STARTUP_ERROR, out_buf); done = true; } else { char szMsgString[256]; LoadString(hInstance_gbl, IDS_ABNORMAL_TERM, szMsgString, 256); sprintf(out_buf, "%s: %s (%lu)\n", path.c_str(), szMsgString, exit_status); write_log(IDS_LOG_TERM, out_buf); // switch the icons if the server restarted if (!service_flag) PostMessage(hWndGbl, WM_SWITCHICONS, 0, 0); if (option == START_FOREVER) done = false; } } else { // Normal shutdown - ie: via ibmgr - don't restart the server char szMsgString[256]; LoadString(hInstance_gbl, IDS_NORMAL_TERM, szMsgString, 256); sprintf(out_buf, "%s: %s\n", path.c_str(), szMsgString); write_log(IDS_LOG_STOP, out_buf); done = true; } if (option == START_ONCE) done = true; } while (!done); // If on WINNT if (service_flag) { CloseServiceHandle(hScManager); CloseServiceHandle(hService); CNTL_stop_service(); //(service_name->c_str()); } else PostMessage(hWndGbl, WM_CLOSE, 0, 0); return 0; }
int WINAPI WinMain(HINSTANCE hThisInst, HINSTANCE /*hPrevInst*/, LPSTR lpszArgs, int nWndMode) { /************************************** * * W i n M a i n * ************************************** * * Functional description * Run the server with NT named * pipes and/or TCP/IP sockets. * **************************************/ hInst = hThisInst; // We want server to crash without waiting for feedback from the user try { if (!Config::getBugcheckAbort()) SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); } catch (Firebird::fatal_exception& e) { MessageBox(NULL, e.what(), "Firebird server failure", MB_OK | MB_ICONHAND | MB_SYSTEMMODAL | MB_DEFAULT_DESKTOP_ONLY); return STARTUP_ERROR; // see /jrd/common.h } catch (Firebird::status_exception& e) { TEXT buffer[BUFFER_LARGE]; const ISC_STATUS* vector = e.value(); if (! (vector && fb_interpret(buffer, sizeof(buffer), &vector))) { strcpy(buffer, "Unknown internal failure"); } MessageBox(NULL, buffer, "Firebird server failure", MB_OK | MB_ICONHAND | MB_SYSTEMMODAL | MB_DEFAULT_DESKTOP_ONLY); return STARTUP_ERROR; // see /jrd/common.h } #ifdef SUPERSERVER server_flag = SRVR_multi_client; #else server_flag = 0; #endif #ifdef SUPERSERVER SetProcessAffinityMask(GetCurrentProcess(), static_cast<DWORD>(Config::getCpuAffinityMask())); #endif protocol_inet[0] = 0; protocol_wnet[0] = 0; strcpy(instance, FB_DEFAULT_INSTANCE); const HANDLE connection_handle = parse_args(lpszArgs, &server_flag); #ifdef SUPERSERVER // get priority class from the config file int priority = Config::getProcessPriorityLevel(); // override it, if necessary if (server_flag & SRVR_high_priority) { priority = 1; } // set priority class if (priority > 0) { SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); } else if (priority < 0) { SetPriorityClass(GetCurrentProcess(), IDLE_PRIORITY_CLASS); } #endif TEXT mutex_name[MAXPATHLEN]; fb_utils::snprintf(mutex_name, sizeof(mutex_name), SERVER_MUTEX, instance); fb_utils::prefix_kernel_object_name(mutex_name, sizeof(mutex_name)); CreateMutex(ISC_get_security_desc(), FALSE, mutex_name); // Initialize the service ISC_signal_init(); Firebird::FpeControl::maskAll(); int nReturnValue = 0; ISC_STATUS_ARRAY status_vector; fb_utils::init_status(status_vector); fb_shutdown_callback(0, wait_threads, fb_shut_finish, NULL); if (connection_handle != INVALID_HANDLE_VALUE) { rem_port* port = 0; if (server_flag & SRVR_inet) { port = INET_reconnect((SOCKET) connection_handle, status_vector); if (port) { SRVR_multi_thread(port, server_flag); port = NULL; } } else if (server_flag & SRVR_wnet) port = WNET_reconnect(connection_handle, status_vector); else if (server_flag & SRVR_xnet) port = XNET_reconnect((ULONG) connection_handle, status_vector); if (port) { service_connection(port); } else if (status_vector[1]) gds__log_status(0, status_vector); fb_shutdown(5 * 1000 /*5 seconds*/, fb_shutrsn_no_connection); } else if (!(server_flag & SRVR_non_service)) { Firebird::string service_name; service_name.printf(REMOTE_SERVICE, instance); CNTL_init(start_connections_thread, instance); const SERVICE_TABLE_ENTRY service_table[] = { {const_cast<char*>(service_name.c_str()), CNTL_main_thread}, {NULL, NULL} }; // BRS There is a error in MinGW (3.1.0) headers // the parameter of StartServiceCtrlDispatcher is declared const in msvc headers #if defined(MINGW) if (!StartServiceCtrlDispatcher(const_cast<SERVICE_TABLE_ENTRY*>(service_table))) { #else if (!StartServiceCtrlDispatcher(service_table)) { #endif if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) { CNTL_shutdown_service("StartServiceCtrlDispatcher failed"); } server_flag |= SRVR_non_service; } } else { start_connections_thread(0); nReturnValue = WINDOW_main(hThisInst, nWndMode, server_flag); } #ifdef DEBUG_GDS_ALLOC // In Debug mode - this will report all server-side memory leaks // due to remote access //gds_alloc_report(0, __FILE__, __LINE__); Firebird::PathName name = fb_utils::getPrefix(fb_utils::FB_DIR_LOG, "memdebug.log"); FILE* file = fopen(name.c_str(), "w+t"); if (file) { fprintf(file, "Global memory pool allocated objects\n"); getDefaultMemoryPool()->print_contents(file); fclose(file); } #endif return nReturnValue; } THREAD_ENTRY_DECLARE process_connection_thread(THREAD_ENTRY_PARAM arg) { /************************************** * * p r o c e s s _ c o n n e c t i o n _ t h r e a d * ************************************** * * Functional description * **************************************/ ThreadCounter counter; service_connection((rem_port*) arg); return 0; }
int gsec(Firebird::UtilSvc* uSvc) { /************************************** * * c o m m o n _ m a i n * ************************************** * * Functional description * If there is no command line, prompt for one, read it * and make an artificial argv. Otherwise, pass * the specified argv to SECURITY_exec_line (see below). * **************************************/ int exit_code = FINI_OK; Firebird::UtilSvc::ArgvType& argv = uSvc->argv; TEXT stuff[MAXSTUFF]; // a place to put stuff in interactive mode tsec tsecInstance(uSvc); tsec* tdsec = &tsecInstance; tsec::putSpecific(tdsec); StackUserData u; tdsec->tsec_user_data = &u; const unsigned char* block; unsigned int bs = uSvc->getAuthBlock(&block); if (bs) { u.authenticationBlock.add(block, bs); } try { // Perform some special handling when run as a Firebird service. tdsec->tsec_throw = true; tdsec->tsec_interactive = !uSvc->isService(); UserData* user_data = tdsec->tsec_user_data; //if (!uSvc->isService() && argv.getCount() == 1) // GSEC_error(GsecMsg101); // use gsec -? to get help int ret = parse_cmd_line(argv, tdsec); if (!uSvc->isService() && ret == -2) // user asked for help GSEC_exit(); Firebird::PathName databaseName; const bool databaseNameEntered = user_data->database.entered(); if (databaseNameEntered) { databaseName = user_data->database.get(); } else { const Firebird::RefPtr<Config> defConf(Config::getDefaultConfig()); databaseName = defConf->getSecurityDatabase(); } const Firebird::string sqlRoleName(user_data->role.entered() ? user_data->role.get() : ""); Firebird::PathName serverName; const bool useServices = !uSvc->isService(); switch (ISC_extract_host(databaseName, serverName, true)) { case ISC_PROTOCOL_TCPIP: serverName += ":"; break; case ISC_PROTOCOL_WLAN: serverName = "\\\\" + serverName + "\\"; break; } if (!useServices) { serverName = ""; } Firebird::LocalStatus s; user_data->database.set(&s, databaseName.c_str()); check(&s); Firebird::RefPtr<IManagement> manager; ISC_STATUS_ARRAY status; if (!useServices) { // Get remote address info for management plugin Firebird::string network_protocol, remote_address; Firebird::ClumpletWriter tmp(Firebird::ClumpletReader::Tagged, MAX_DPB_SIZE, isc_dpb_version1); uSvc->fillDpb(tmp); if (tmp.find(isc_dpb_address_path)) { Firebird::ClumpletReader address_stack(Firebird::ClumpletReader::UnTagged, tmp.getBytes(), tmp.getClumpLength()); while (!address_stack.isEof()) { if (address_stack.getClumpTag() != isc_dpb_address) { address_stack.moveNext(); continue; } Firebird::ClumpletReader address(Firebird::ClumpletReader::UnTagged, address_stack.getBytes(), address_stack.getClumpLength()); while (!address.isEof()) { switch (address.getClumpTag()) { case isc_dpb_addr_protocol: address.getString(network_protocol); break; case isc_dpb_addr_endpoint: address.getString(remote_address); break; default: break; } address.moveNext(); } break; } } // Create config to pass -DATABASE parameter value to plugin Firebird::string databaseText; databaseText.printf("SecurityDatabase = %s\n", databaseName.c_str()); ConfigFile gsecDatabase(ConfigFile::USE_TEXT, databaseText.c_str()); Firebird::RefPtr<Config> defaultConfig(Config::getDefaultConfig()); Firebird::RefPtr<Config> pseudoConfig(new Config(gsecDatabase, *defaultConfig)); uSvc->checkService(); fb_assert(user_data->dba.entered() || user_data->authenticationBlock.hasData()); if (user_data->dba.entered() || user_data->authenticationBlock.hasData()) { class GsecInfo : public Firebird::AutoIface<ILogonInfo, FB_AUTH_LOGON_INFO_VERSION> { public: GsecInfo(const char* pDba, const char* pRole, const char* pProtocol, const char* pAddress, const UserData::AuthenticationBlock* pAuthBlock) : dba(pDba), sqlRole(pRole), protocol(pProtocol), address(pAddress), authBytes(pAuthBlock->getCount() ? pAuthBlock->begin() : NULL), authLength(pAuthBlock->getCount()) { } // ILogonInfo implementation const char* FB_CARG name() { return dba; } const char* FB_CARG role() { return sqlRole; } const char* FB_CARG networkProtocol() { return protocol; } const char* FB_CARG remoteAddress() { return address; } const unsigned char* FB_CARG authBlock(unsigned* length) { *length = authLength; return authBytes; } private: const char* dba; const char* sqlRole; const char* protocol; const char* address; const unsigned char* authBytes; unsigned int authLength; };
// Full processing of database name // Returns true if alias was found in databases.conf bool expandDatabaseName(Firebird::PathName alias, Firebird::PathName& file, Firebird::RefPtr<Config>* config) { try { aliasesConf().checkLoadConfig(); } catch (const fatal_exception& ex) { gds__log("File databases.conf contains bad data: %s", ex.what()); Arg::Gds(isc_server_misconfigured).raise(); } // remove whitespaces from database name alias.trim(); ReadLockGuard guard(aliasesConf().rwLock, "expandDatabaseName"); // First of all check in databases.conf if (resolveAlias(alias, file, config)) { return true; } // Now try ISC_PATH environment variable if (!setPath(alias, file)) { // At this step check DatabaseAccess paths in firebird.conf if (!resolveDatabaseAccess(alias, file)) { // Last chance - regular filename expansion file = alias; ISC_systemToUtf8(file); ISC_unescape(file); ISC_utf8ToSystem(file); ISC_expand_filename(file, true); ISC_systemToUtf8(file); ISC_escape(file); ISC_utf8ToSystem(file); } } // Search for correct config in databases.conf if (config) { DbName* db = aliasesConf().dbHash.lookup(file); #ifdef HAVE_ID_BY_NAME if (!db) { UCharBuffer id; os_utils::getUniqueFileId(file.c_str(), id); if (id.hasData()) { Id* i = aliasesConf().idHash.lookup(id); if (i) db = i->db; } } #endif *config = (db && db->config.hasData()) ? db->config : Config::getDefaultConfig(); } return false; }
int CLIB_ROUTINE main( int argc, char** argv) { /************************************** * * m a i n * ************************************** * * Functional description * Run the server with apollo mailboxes. * **************************************/ try { RemPortPtr port; // We should support 3 modes: // 1. Standalone single-process listener (like SS). // 2. Standalone listener, forking on each packet accepted (look -s switch in CS). // 3. Process spawned by (x)inetd (like CS). bool classic = false; bool standaloneClassic = false; bool super = false; // It's very easy to detect that we are spawned - just check fd 0 to be a socket. const int channel = 0; struct stat stat0; if (fstat(channel, &stat0) == 0 && S_ISSOCK(stat0.st_mode)) { // classic server mode classic = true; } const TEXT* const* const end = argc + argv; argv++; bool debug = false; USHORT INET_SERVER_flag = 0; protocol[0] = 0; bool done = false; while (argv < end) { TEXT c; const TEXT* p = *argv++; if (*p++ == '-') { while (c = *p++) { switch (UPPER(c)) { case 'D': debug = true; break; case 'E': if (argv < end) { if (ISC_set_prefix(p, *argv) == -1) printf("Invalid argument Ignored\n"); else argv++; // do not skip next argument if this one is invalid } else { printf("Missing argument, switch -E ignored\n"); } done = true; break; case 'P': if (argv < end) { if (!classic) { fb_utils::snprintf(protocol, sizeof(protocol), "/%s", *argv++); } else { gds__log("Switch -P ignored in CS mode\n"); } } else { printf("Missing argument, switch -P ignored\n"); } break; case 'H': case '?': printf("Firebird TCP/IP server options are:\n"); printf(" -d : debug on\n"); printf(" -p <port> : specify port to listen on\n"); printf(" -z : print version and exit\n"); printf(" -h|? : print this help\n"); printf("\n"); printf(" (The following -e options used to be -h options)\n"); printf(" -e <firebird_root_dir> : set firebird_root path\n"); printf(" -el <firebird_lock_dir> : set runtime firebird_lock dir\n"); printf(" -em <firebird_msg_dir> : set firebird_msg dir path\n"); exit(FINI_OK); case 'Z': printf("Firebird TCP/IP server version %s\n", FB_VERSION); exit(FINI_OK); default: printf("Unknown switch '%c', ignored\n", c); break; } if (done) break; } } } if (Config::getServerMode() == MODE_CLASSIC) { if (!classic) standaloneClassic = true; } else { if (classic) { gds__log("Server misconfigured - to start it from (x)inetd add ServerMode=Classic to firebird.conf"); Firebird::Syslog::Record(Firebird::Syslog::Error, "Server misconfigured - add ServerMode=Classic to firebird.conf"); exit(STARTUP_ERROR); } INET_SERVER_flag |= SRVR_multi_client; super = true; } { // scope Firebird::MasterInterfacePtr master; master->serverMode(super ? 1 : 0); } if (debug) { INET_SERVER_flag |= SRVR_debug; } // activate paths set with -e family of switches ISC_set_prefix(0, 0); // ignore some signals set_signal(SIGPIPE, signal_handler); set_signal(SIGUSR1, signal_handler); set_signal(SIGUSR2, signal_handler); // First of all change directory to tmp if (chdir(TEMP_DIR)) { // error on changing the directory gds__log("Could not change directory to %s due to errno %d", TEMP_DIR, errno); } #ifdef FB_RAISE_LIMITS #ifdef RLIMIT_NPROC raiseLimit(RLIMIT_NPROC); #endif #if !(defined(DEV_BUILD)) if (Config::getBugcheckAbort()) #endif { // try to force core files creation raiseLimit(RLIMIT_CORE); } #if (defined SOLARIS || defined HPUX || defined LINUX) if (super) { // Increase max open files to hard limit for Unix // platforms which are known to have low soft limits. raiseLimit(RLIMIT_NOFILE); } #endif // Unix platforms #endif // FB_RAISE_LIMITS #ifdef HAVE_LOCALE_H // Pick up the system locale to allow SYSTEM<->UTF8 conversions inside the engine setlocale(LC_CTYPE, ""); #endif if (!(debug || classic)) { int mask = 0; // FD_ZERO(&mask); mask |= 1 << 2; // FD_SET(2, &mask); divorce_terminal(mask); } // check firebird.conf presence - must be for server if (Config::missFirebirdConf()) { Firebird::Syslog::Record(Firebird::Syslog::Error, "Missing master config file firebird.conf"); exit(STARTUP_ERROR); } if (super || standaloneClassic) { try { port = INET_connect(protocol, 0, INET_SERVER_flag, 0, NULL); } catch (const Firebird::Exception& ex) { iscLogException("startup:INET_connect:", ex); Firebird::StaticStatusVector st; ex.stuffException(st); gds__print_status(st.begin()); exit(STARTUP_ERROR); } } if (classic) { port = INET_server(channel); if (!port) { gds__log("Unable to start INET_server"); Firebird::Syslog::Record(Firebird::Syslog::Error, "Unable to start INET_server"); exit(STARTUP_ERROR); } } { // scope for interface ptr Firebird::PluginManagerInterfacePtr pi; Auth::registerSrpServer(pi); } if (super) { // Server tries to attach to security2.fdb to make sure everything is OK // This code fixes bug# 8429 + all other bug of that kind - from // now on the server exits if it cannot attach to the database // (wrong or no license, not enough memory, etc. ISC_STATUS_ARRAY status; isc_db_handle db_handle = 0L; const Firebird::RefPtr<Config> defConf(Config::getDefaultConfig()); const char* path = defConf->getSecurityDatabase(); const char dpb[] = {isc_dpb_version1, isc_dpb_sec_attach, 1, 1, isc_dpb_address_path, 0}; isc_attach_database(status, strlen(path), path, &db_handle, sizeof dpb, dpb); if (status[0] == 1 && status[1] > 0) { logSecurityDatabaseError(path, status); } isc_detach_database(status, &db_handle); if (status[0] == 1 && status[1] > 0) { logSecurityDatabaseError(path, status); } } // end scope fb_shutdown_callback(NULL, closePort, fb_shut_exit, port); SRVR_multi_thread(port, INET_SERVER_flag); #ifdef DEBUG_GDS_ALLOC // In Debug mode - this will report all server-side memory leaks due to remote access Firebird::PathName name = fb_utils::getPrefix( Firebird::IConfigManager::DIR_LOG, "memdebug.log"); FILE* file = os_utils::fopen(name.c_str(), "w+t"); if (file) { fprintf(file, "Global memory pool allocated objects\n"); getDefaultMemoryPool()->print_contents(file); fclose(file); } #endif // perform atexit shutdown here when all globals in embedded library are active // also sync with possibly already running shutdown in dedicated thread fb_shutdown(10000, fb_shutrsn_exit_called); return FINI_OK; } catch (const Firebird::Exception& ex) { Firebird::StaticStatusVector st; ex.stuffException(st); char s[100]; const ISC_STATUS* status = st.begin(); fb_interpret(s, sizeof(s), &status); iscLogException("Firebird startup error:", ex); Firebird::Syslog::Record(Firebird::Syslog::Error, "Firebird startup error"); Firebird::Syslog::Record(Firebird::Syslog::Error, s); exit(STARTUP_ERROR); } }
bool PathUtils::canAccess(const Firebird::PathName& path, int mode) { return access(path.c_str(), mode) == 0; }
int FB_EXPORTED server_main( int argc, char** argv) { /************************************** * * m a i n * ************************************** * * Functional description * Run the server with apollo mailboxes. * **************************************/ RemPortPtr port; // 01 Sept 2003, Nickolay Samofatov // In GCC version 3.1-3.3 we need to install special error handler // in order to get meaningful terminate() error message on stderr. // In GCC 3.4 or later this is the default. //#if __GNUC__ == 3 && __GNUC_MINOR__ >= 1 && __GNUC_MINOR__ < 4 // std::set_terminate (__gnu_cxx::__verbose_terminate_handler); //#endif const TEXT* const* const end = argc + argv; argv++; bool debug = false, standalone = false; INET_SERVER_flag = 0; int channel = 0; protocol[0] = 0; bool multi_client = false, multi_threaded = false; #ifdef SUPERSERVER INET_SERVER_flag |= SRVR_multi_client; multi_client = multi_threaded = standalone = true; #endif int clients = 0; bool done = false; while (argv < end) { TEXT c; const TEXT* p = *argv++; if (*p++ == '-') while (c = *p++) { switch (UPPER(c)) { case 'D': INET_SERVER_flag |= SRVR_debug; debug = true; break; #ifndef SUPERSERVER case 'M': INET_SERVER_flag |= SRVR_multi_client; if (argv < end) { if (clients = atoi(*argv)) argv++; } multi_client = standalone = true; break; case 'S': standalone = true; break; case 'I': standalone = false; break; case 'T': multi_threaded = true; break; case 'U': multi_threaded = false; break; #endif // SUPERSERVER case 'E': if (ISC_set_prefix(p, *argv) == -1) printf("Invalid argument Ignored\n"); else argv++; // do not skip next argument if this one is invalid done = true; break; case 'P': fb_utils::snprintf(protocol, sizeof(protocol), "/%s", *argv++); break; case 'H': case '?': printf("Firebird TCP/IP server options are:\n"); printf(" -d : debug on\n"); #ifndef SUPERSERVER // These options are not applicable to super server printf(" -m : multiclient - on\n"); printf(" -s : standalone - true\n"); printf(" -i : standalone - false\n"); printf(" -t : multithread - true (non pc only)\n"); printf(" -u : multithread - false (pc only)\n"); #endif printf(" -p<protocol> : specify protocol\n"); printf(" -h|? : print this help\n"); printf("\n"); printf(" (The following -e options used to be -h options)\n"); printf(" -e <firebird_root_dir> : set firebird_root path\n"); printf(" -el <firebird_lock_dir> : set runtime firebird_lock dir\n"); printf(" -em <firebird_msg_dir> : set firebird_msg dir path\n"); printf(" -z : print version\n"); exit(FINI_OK); case 'Z': printf("Firebird TCP/IP server version %s\n", GDS_VERSION); exit(FINI_OK); } if (done) break; } } // activate paths set with -e family of switches ISC_set_prefix(0, 0); #ifdef UNIX set_signal(SIGPIPE, signal_handler); set_signal(SIGUSR1, signal_handler); set_signal(SIGUSR2, signal_handler); #endif #if defined(UNIX) && defined(HAVE_SETRLIMIT) && defined(HAVE_GETRLIMIT) #ifdef RLIMIT_NPROC raiseLimit(RLIMIT_NPROC); #endif #if !(defined(DEV_BUILD)) if (Config::getBugcheckAbort()) #endif { // try to force core files creation raiseLimit(RLIMIT_CORE); // we need some writable directory for core file // on any unix /tmp seems to be the best place if (CHANGE_DIR(TEMP_DIR)) { // error on changing the directory gds__log("Could not change directory to %s due to errno %d", TEMP_DIR, errno); } } #if defined(SUPERSERVER) && (defined SOLARIS || defined HPUX || defined LINUX) // Increase max open files to hard limit for Unix // platforms which are known to have low soft limits. raiseLimit(RLIMIT_NOFILE); #endif #endif // Fork off a server, wait for it to die, then fork off another, // but give up after 100 tries #ifndef SUPERSERVER if (multi_client && !debug) { #ifdef UNIX set_signal(SIGUSR1, signal_handler); #endif int child; for (int n = 0; n < 100; n++) { INET_SERVER_start = 0; if (!(child = fork())) break; while (wait(0) != child) if (INET_SERVER_start) { n = 0; // reset error counter on "real" signal break; } gds__log("INET_SERVER/main: gds_inet_server restarted"); } #ifdef UNIX set_signal(SIGUSR1, SIG_DFL); #endif } #endif if (standalone) { if (multi_client) { #ifdef SUPERSERVER // Remove restriction on username, for DEV builds // restrict only for production builds. MOD 21-July-2002 #ifndef DEV_BUILD Firebird::string user_name; // holds the user name // check user id ISC_get_user(&user_name, NULL, NULL, NULL); if (user_name != "root" && user_name != FIREBIRD_USER_NAME && user_name != INTERBASE_USER_NAME && user_name != INTERBASE_USER_SHORT) { // invalid user -- bail out fprintf(stderr, "%s: Invalid user (must be %s, %s, %s or root).\n", "fbserver", FIREBIRD_USER_NAME, INTERBASE_USER_NAME, INTERBASE_USER_SHORT); exit(STARTUP_ERROR); } #endif #else if (setreuid(0, 0) < 0) printf("Inet_server: couldn't set uid to superuser.\n"); #endif INET_set_clients(clients); } if (!debug) { int mask = 0; // FD_ZERO(&mask); mask |= 1 << 2; // FD_SET(2, &mask); divorce_terminal(mask); } { // scope block ISC_STATUS_ARRAY status_vector; port = INET_connect(protocol, 0, status_vector, INET_SERVER_flag, 0); if (!port) { gds__print_status(status_vector); exit(STARTUP_ERROR); } } // end scope block } else { port = INET_server(channel); if (!port) { fprintf(stderr, "fbserver: Unable to start INET_server\n"); exit(STARTUP_ERROR); } } #ifdef SUPERSERVER // before starting the superserver stuff change directory to tmp if (CHANGE_DIR(TEMP_DIR)) { // error on changing the directory gds__log("Could not change directory to %s due to errno %d", TEMP_DIR, errno); } // Server tries to attach to security2.fdb to make sure everything is OK // This code fixes bug# 8429 + all other bug of that kind - from // now on the server exits if it cannot attach to the database // (wrong or no license, not enough memory, etc. { // scope TEXT path[MAXPATHLEN]; ISC_STATUS_ARRAY status; isc_db_handle db_handle = 0L; Jrd::SecurityDatabase::getPath(path); const char dpb[] = {isc_dpb_version1, isc_dpb_gsec_attach, 1, 1}; isc_attach_database(status, strlen(path), path, &db_handle, sizeof dpb, dpb); if (status[0] == 1 && status[1] > 0) { gds__log_status(path, status); isc_print_status(status); exit(STARTUP_ERROR); } isc_detach_database(status, &db_handle); if (status[0] == 1 && status[1] > 0) { gds__log_status(path, status); isc_print_status(status); exit(STARTUP_ERROR); } } // end scope shutdownInit(); #endif SRVR_multi_thread(port, INET_SERVER_flag); #ifdef DEBUG_GDS_ALLOC // In Debug mode - this will report all server-side memory leaks due to remote access //gds_alloc_report(0, __FILE__, __LINE__); Firebird::PathName name = fb_utils::getPrefix(fb_utils::FB_DIR_LOG, "memdebug.log"); FILE* file = fopen(name.c_str(), "w+t"); if (file) { fprintf(file, "Global memory pool allocated objects\n"); getDefaultMemoryPool()->print_contents(file); fclose(file); } #endif // perform atexit shutdown here when all globals in embedded library are active // also sync with possibly already running shutdown in dedicated thread fb_shutdown(10000, fb_shutrsn_exit_called); return FINI_OK; }