void grantRevokeAdmin(Firebird::IUser* user, bool ignoreRevoke = false) { if (!user->admin()->entered()) { return; } Firebird::LocalStatus s; Firebird::CheckStatusWrapper statusWrapper(&s); Firebird::string userName(user->userName()->get()); prepareName(userName, '"'); Firebird::string sql; if (user->admin()->get() == 0) { Firebird::string userName2(user->userName()->get()); prepareName(userName2, '\''); Firebird::string selGrantor; selGrantor.printf("SELECT RDB$GRANTOR FROM RDB$USER_PRIVILEGES " "WHERE RDB$USER = '******' AND RDB$RELATION_NAME = '%s' AND RDB$PRIVILEGE = 'M'", userName2.c_str(), ADMIN_ROLE); Message out; Field<Varying> grantor(out, MAX_SQL_IDENTIFIER_SIZE); Firebird::IResultSet* curs = att->openCursor(&statusWrapper, tra, selGrantor.length(), selGrantor.c_str(), SQL_DIALECT_V6, NULL, NULL, out.getMetadata(), NULL, 0); check(&statusWrapper); bool hasGrant = curs->fetchNext(&statusWrapper, out.getBuffer()) == Firebird::IStatus::RESULT_OK; curs->close(&statusWrapper); check(&statusWrapper); if (hasGrant) { selGrantor = grantor; prepareName(selGrantor, '"'); sql.printf("REVOKE %s FROM \"%s\" GRANTED BY \"%s\"", ADMIN_ROLE, userName.c_str(), selGrantor.c_str()); } else { if (ignoreRevoke) return; // no grant - let engine produce correct error message sql.printf("REVOKE %s FROM \"%s\"", ADMIN_ROLE, userName.c_str()); } } else { sql.printf("GRANT %s TO \"%s\"", ADMIN_ROLE, userName.c_str()); } att->execute(&statusWrapper, tra, sql.length(), sql.c_str(), SQL_DIALECT_V6, NULL, NULL, NULL, NULL); check(&statusWrapper); }
static void alice_output(bool error, const SCHAR* format, ...) { AliceGlobals* tdgbl = AliceGlobals::getSpecific(); va_list arglist; va_start(arglist, format); Firebird::string buf; buf.vprintf(format, arglist); va_end(arglist); if (error) tdgbl->uSvc->outputError(buf.c_str()); else tdgbl->uSvc->outputVerbose(buf.c_str()); }
ModuleLoader::Module* ModuleLoader::loadModule(ISC_STATUS* status, const Firebird::PathName& modPath) { void* module = dlopen(modPath.nullStr(), FB_RTLD_MODE); if (module == NULL) { if (status) { status[0] = isc_arg_gds; status[1] = isc_random; status[2] = isc_arg_string; status[3] = (ISC_STATUS) dlerror(); status[4] = isc_arg_end; } return 0; } #ifdef DEBUG_THREAD_IN_UNLOADED_LIBRARY Firebird::string command; command.printf("echo +++ %s +++ >>/tmp/fbmaps;date >> /tmp/fbmaps;cat /proc/%d/maps >>/tmp/fbmaps", modPath.c_str(), getpid()); system(command.c_str()); #endif return FB_NEW_POOL(*getDefaultMemoryPool()) DlfcnModule(*getDefaultMemoryPool(), modPath, module); }
void PreparedStatement::init(thread_db* tdbb, Attachment* attachment, jrd_tra* transaction, const Firebird::string& text, bool isInternalRequest) { AutoSetRestore<SSHORT> autoAttCharset(&attachment->att_charset, (isInternalRequest ? CS_METADATA : attachment->att_charset)); request = NULL; try { const Database& dbb = *tdbb->getDatabase(); const int dialect = isInternalRequest || (dbb.dbb_flags & DBB_DB_SQL_dialect_3) ? SQL_DIALECT_V6 : SQL_DIALECT_V5; request = DSQL_prepare(tdbb, attachment, transaction, text.length(), text.c_str(), dialect, NULL, NULL, isInternalRequest); const DsqlCompiledStatement* statement = request->getStatement(); if (statement->getSendMsg()) parseDsqlMessage(statement->getSendMsg(), inValues, inMetadata, inMessage); if (statement->getReceiveMsg()) parseDsqlMessage(statement->getReceiveMsg(), outValues, outMetadata, outMessage); } catch (const Exception&) { if (request) { DSQL_free_statement(tdbb, request, DSQL_drop); } throw; } }
bool readenv(const char* env_name, Firebird::PathName& env_value) { Firebird::string result; bool rc = readenv(env_name, result); env_value.assign(result.c_str(), result.length()); return rc; }
TracePlugin* FB_CARG TraceFactoryImpl::trace_create(Firebird::IStatus* status, TraceInitInfo* initInfo) { Firebird::MasterInterfacePtr master; const char* dbname = NULL; try { master->upgradeInterface(initInfo, FB_TRACE_INIT_INFO_VERSION, upInfo); dbname = initInfo->getDatabaseName(); if (!dbname) dbname = ""; TracePluginConfig config; TraceCfgReader::readTraceConfiguration(initInfo->getConfigText(), dbname, config); TraceDatabaseConnection* connection = initInfo->getConnection(); if (connection) master->upgradeInterface(connection, FB_TRACE_CONNECTION_VERSION, upInfo); if (!config.enabled || (config.connection_id && connection && (connection->getConnectionID() != SLONG(config.connection_id)))) { return NULL; // Plugin is not needed, no error happened. } Firebird::AutoPtr<TraceLogWriter, Firebird::SimpleRelease<TraceLogWriter> > logWriter(initInfo->getLogWriter()); if (logWriter) config.log_filename = ""; return new TracePluginImpl(config, initInfo); // Everything is ok, we created a plugin } catch (Firebird::Exception& ex) { // put error into trace log TraceLogWriter* logWriter = initInfo->getLogWriter(); if (logWriter) { master->upgradeInterface(logWriter, FB_TRACE_LOG_WRITER_VERSION, upInfo); const char* strEx = TracePluginImpl::marshal_exception(ex); Firebird::string err; if (dbname) err.printf("Error creating trace session for database \"%s\":\n%s\n", dbname, strEx); else err.printf("Error creating trace session for service manager attachment:\n%s\n", strEx); logWriter->write(err.c_str(), err.length()); logWriter->release(); } else ex.stuffException(status); } return NULL; }
void ExecuteStatement::open(thread_db* tdbb, jrd_nod* sql, SSHORT nVars, bool singleton) { SET_TDBB(tdbb); Attachment* const attachment = tdbb->getAttachment(); jrd_tra* transaction = tdbb->getTransaction(); if (transaction->tra_callback_count >= MAX_CALLBACKS) { ERR_post(Arg::Gds(isc_exec_sql_max_call_exceeded)); } varCount = nVars; singleMode = singleton; Firebird::string sqlText; getString(tdbb, sqlText, EVL_expr(tdbb, sql), tdbb->getRequest()); memcpy(startOfSqlOperator, sqlText.c_str(), sizeof(startOfSqlOperator) - 1); startOfSqlOperator[sizeof(startOfSqlOperator) - 1] = 0; transaction->tra_callback_count++; try { stmt = attachment->prepareStatement(tdbb, *tdbb->getDefaultPool(), transaction, sqlText); if (stmt->getResultCount() == 0) { delete stmt; stmt = NULL; ERR_post(Arg::Gds(isc_exec_sql_invalid_req) << Arg::Str(startOfSqlOperator)); } if (stmt->getResultCount() != varCount) { delete stmt; stmt = NULL; ERR_post(Arg::Gds(isc_wronumarg)); } resultSet = stmt->executeQuery(tdbb, transaction); fb_assert(transaction == tdbb->getTransaction()); } catch (const Firebird::Exception&) { transaction->tra_callback_count--; throw; } transaction->tra_callback_count--; }
void Stream::format(const char *pattern, ...) { Firebird::string temp; va_list args; va_start (args, pattern); temp.vprintf(pattern, args); va_end(args); putSegment (temp.c_str()); }
void* DlfcnModule::findSymbol(const Firebird::string& symName) { void* result = dlsym(module, symName.c_str()); if (result == NULL) { Firebird::string newSym ='_' + symName; result = dlsym(module, newSym.c_str()); } return result; }
void iscDbLogStatus(const TEXT* text, Firebird::IStatus* status) { const TEXT* hdr = NULL; Firebird::string buf; if (text) { buf = "Database: "; buf += text; hdr = buf.c_str(); } iscLogStatus(hdr, status); }
// create directory for lock files and set appropriate access rights void createLockDirectory(const char* pathname) { static bool errorLogged = false; DWORD attr = GetFileAttributes(pathname); DWORD errcode = 0; if (attr == INVALID_FILE_ATTRIBUTES) { errcode = GetLastError(); if (errcode == ERROR_FILE_NOT_FOUND) { if (!CreateDirectory(pathname, NULL)) { errcode = GetLastError(); } else { adjustLockDirectoryAccess(pathname); attr = GetFileAttributes(pathname); if (attr == INVALID_FILE_ATTRIBUTES) { errcode = GetLastError(); } } } } Firebird::string err; if (attr == INVALID_FILE_ATTRIBUTES) { err.printf("Can't create directory \"%s\". OS errno is %d", pathname, errcode); if (!errorLogged) { errorLogged = true; gds__log(err.c_str()); } Firebird::fatal_exception::raise(err.c_str()); } if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) { err.printf("Can't create directory \"%s\". File with same name already exists", pathname); if (!errorLogged) { errorLogged = true; gds__log(err.c_str()); } Firebird::fatal_exception::raise(err.c_str()); } if (attr & FILE_ATTRIBUTE_READONLY) { err.printf("Can't create directory \"%s\". Readonly directory with same name already exists", pathname); if (!errorLogged) { errorLogged = true; gds__log(err.c_str()); } Firebird::fatal_exception::raise(err.c_str()); } }
ISC_STATUS API_ROUTINE isc_delete_user(ISC_STATUS* status, const USER_SEC_DATA* input_user_data) { /************************************** * * i s c _ d e l e t e _ u s e r * ************************************** * * Functional description * Deletes a user from the server's security * database. * Return 0 if the user was deleted * * Return > 0 if any error occurs. * **************************************/ Auth::StackUserData userInfo; userInfo.op = Auth::DEL_OPER; Firebird::LocalStatus s; Firebird::CheckStatusWrapper statusWrapper(&s); if (input_user_data->user_name) { Firebird::string work = input_user_data->user_name; if (work.length() > USERNAME_LENGTH) { return user_error(status, isc_usrname_too_long); } Firebird::string::size_type l = work.find(' '); if (l != Firebird::string::npos) { work.resize(l); } userInfo.user.set(&statusWrapper, work.c_str()); Firebird::check(&statusWrapper); userInfo.user.setEntered(&statusWrapper, 1); Firebird::check(&statusWrapper); } else { return user_error(status, isc_usrname_required); } return executeSecurityCommand(status, input_user_data, userInfo); }
// static function bool Switches::matchSwitch(const Firebird::string& sw, const char* target, size_t n) { /************************************** * * m a t c h S w i t c h * ************************************** * * Functional description * Returns true if switch matches target * **************************************/ if (n < sw.length()) { return false; } n = sw.length(); return memcmp(sw.c_str(), target, n) == 0; }
ModuleLoader::Module* ModuleLoader::loadModule(const Firebird::PathName& modPath) { void* module = dlopen(modPath.nullStr(), FB_RTLD_MODE); if (module == NULL) { #ifdef DEV_BUILD // gds__log("loadModule failed loading %s: %s", modPath.c_str(), dlerror()); #endif return 0; } #ifdef DEBUG_THREAD_IN_UNLOADED_LIBRARY Firebird::string command; command.printf("echo +++ %s +++ >>/tmp/fbmaps;date >> /tmp/fbmaps;cat /proc/%d/maps >>/tmp/fbmaps", modPath.c_str(), getpid()); system(command.c_str()); #endif return FB_NEW_POOL(*getDefaultMemoryPool()) DlfcnModule(module); }
void* DlfcnModule::findSymbol(const Firebird::string& symName) { void* result = dlsym(module, symName.c_str()); if (!result) { Firebird::string newSym = '_' + symName; result = dlsym(module, newSym.c_str()); } #ifdef HAVE_DLADDR if (!PathUtils::isRelative(fileName)) { Dl_info info; if (!dladdr(result, &info)) return NULL; if (fileName != info.dli_fname) return NULL; } #endif return result; }
int CLIB_ROUTINE main( int argc, char **argv) { /************************************** * * m a i n * ************************************** * * Functional description * Install or remove a Firebird service. * **************************************/ USHORT sw_command = COMMAND_NONE; bool sw_version = false; USHORT sw_startup = STARTUP_AUTO; USHORT sw_mode = DEFAULT_PRIORITY; USHORT sw_guardian = NO_GUARDIAN; USHORT sw_arch = ARCH_SS; bool sw_interactive = false; const TEXT* instance = FB_DEFAULT_INSTANCE; const TEXT* username = NULL; const TEXT* password = NULL; // Let's get the root directory from the instance path of this program. // argv[0] is only _mostly_ guaranteed to give this info, // so we GetModuleFileName() TEXT directory[MAXPATHLEN]; const USHORT len = GetModuleFileName(NULL, directory, sizeof(directory)); if (len == 0) return svc_error(GetLastError(), "GetModuleFileName", NULL); fb_assert(len <= sizeof(directory)); // Get to the last '\' (this one precedes the filename part). There is // always one after a call to GetModuleFileName(). TEXT* p = directory + len; while (p != directory) { --p; if ((*p) == '\\') break; } *p = '\0'; TEXT full_username[128]; TEXT oem_username[128]; TEXT keyb_password[64]; const TEXT* const* const end = argv + argc; while (++argv < end) { if (**argv != '-') { int i; const TEXT* cmd; for (i = 0; cmd = commands[i].name; i++) { const TEXT* q; for (p = *argv, q = cmd; *p && UPPER(*p) == *q; p++, q++) ; if (!*p && commands[i].abbrev <= (USHORT) (q - cmd)) break; } if (!cmd) { printf("Unknown command \"%s\"\n", *argv); usage_exit(); } sw_command = commands[i].code; } else { p = *argv + 1; switch (UPPER(*p)) { case 'A': sw_startup = STARTUP_AUTO; break; case 'D': sw_startup = STARTUP_DEMAND; break; /* case 'R': sw_mode = NORMAL_PRIORITY; break; */ case 'B': sw_mode = HIGH_PRIORITY; break; case 'Z': sw_version = true; break; case 'G': sw_guardian = USE_GUARDIAN; break; case 'L': if (++argv < end) username = *argv; if (++argv < end) { if (**argv == '-') // Next switch --argv; else password = *argv; } break; case 'I': sw_interactive = true; break; case 'N': if (++argv < end) instance = *argv; break; case '?': usage_exit(); default: printf("Unknown switch \"%s\"\n", p); usage_exit(); } } } if (sw_version) printf("instsvc version %s\n", FB_VERSION); if (sw_command == COMMAND_NONE || (username && sw_command != COMMAND_INSTALL)) { usage_exit(); } if (sw_command == COMMAND_INSTALL && username != 0) { if (sw_interactive) { printf("\"Interact with desktop\" mode can be set for LocalSystem account only"); exit(FINI_ERROR); } const char* limit = username; while (*limit != '\0' && *limit != '\\') ++limit; if (!*limit) { DWORD cnlen = sizeof(full_username) - 1; GetComputerName(full_username, &cnlen); strcat(full_username, "\\"); strncat(full_username, username, sizeof(full_username) - (cnlen + 1)); } else { strncpy(full_username, username, sizeof(full_username)); } full_username[sizeof(full_username) - 1] = '\0'; CharToOem(full_username, oem_username); username = full_username; if (password == 0) { printf("Enter %s user password : "******"\n"); OemToChar(keyb_password, keyb_password); password = keyb_password; } // Let's grant "Logon as a Service" right to the -login user switch (SERVICES_grant_privilege(full_username, svc_error, L"SeServiceLogonRight")) { case FB_PRIVILEGE_ALREADY_GRANTED: /* // OM - I think it is better not to bother the admin with this message. printf("The 'Logon as a Service' right was already granted to %s\n", oem_username); */ break; case FB_SUCCESS: printf("The 'Logon as a Service' right has been granted to %s\n", oem_username); break; case FB_FAILURE: default: printf("Failed granting the 'Logon as a Service' right to %s\n", oem_username); exit(FINI_ERROR); break; } // Let's grant "Adjust memory quotas for a process" right to the -login user switch (SERVICES_grant_privilege(full_username, svc_error, L"SeIncreaseQuotaPrivilege")) { case FB_PRIVILEGE_ALREADY_GRANTED: break; case FB_SUCCESS: printf("The 'Adjust memory quotas for a process' right has been granted to %s\n", oem_username); break; case FB_FAILURE: default: printf("Failed granting the 'Adjust memory quotas for a process' right to %s\n", oem_username); exit(FINI_ERROR); break; } } DWORD dwScmManagerAccess = SC_MANAGER_ALL_ACCESS; switch (sw_command) { case COMMAND_INSTALL: case COMMAND_REMOVE: dwScmManagerAccess = SC_MANAGER_CREATE_SERVICE; break; case COMMAND_START: case COMMAND_STOP: dwScmManagerAccess = SC_MANAGER_CONNECT; break; case COMMAND_QUERY: dwScmManagerAccess = SC_MANAGER_ENUMERATE_SERVICE; break; } const SC_HANDLE manager = OpenSCManager(NULL, NULL, dwScmManagerAccess); if (manager == NULL) { svc_error(GetLastError(), "OpenSCManager", NULL); exit(FINI_ERROR); } USHORT status, status2; SC_HANDLE service; Firebird::string guard_service_name, guard_display_name; guard_service_name.printf(ISCGUARD_SERVICE, instance); guard_display_name.printf(ISCGUARD_DISPLAY_NAME, instance); Firebird::string remote_service_name, remote_display_name; remote_service_name.printf(REMOTE_SERVICE, instance); remote_display_name.printf(REMOTE_DISPLAY_NAME, instance); Firebird::string switches; if (strchr(instance, ' ')) switches.printf("-s \"%s\"", instance); else switches.printf("-s %s", instance); switch (sw_command) { case COMMAND_INSTALL: // First, lets do the guardian, if it has been specified if (sw_guardian) { status = SERVICES_install(manager, guard_service_name.c_str(), guard_display_name.c_str(), ISCGUARD_DISPLAY_DESCR, ISCGUARD_EXECUTABLE, directory, switches.c_str(), NULL, sw_startup, username, password, false, // interactive_mode true, // auto_restart svc_error); status2 = FB_SUCCESS; if (username != 0) { status2 = SERVICES_grant_access_rights(guard_service_name.c_str(), username, svc_error); } if (status == FB_SUCCESS && status2 == FB_SUCCESS) { printf("Service \"%s\" successfully created.\n", guard_display_name.c_str()); } // Set sw_startup to manual in preparation for install the service sw_startup = STARTUP_DEMAND; } // do the install of the server status = SERVICES_install(manager, remote_service_name.c_str(), remote_display_name.c_str(), REMOTE_DISPLAY_DESCR, REMOTE_EXECUTABLE, directory, switches.c_str(), NULL, sw_startup, username, password, sw_interactive, !sw_guardian, svc_error); status2 = FB_SUCCESS; if (username != 0) { status2 = SERVICES_grant_access_rights(remote_service_name.c_str(), username, svc_error); } if (status == FB_SUCCESS && status2 == FB_SUCCESS) { printf("Service \"%s\" successfully created.\n", remote_display_name.c_str()); } break; case COMMAND_REMOVE: service = OpenService(manager, guard_service_name.c_str(), SERVICE_ALL_ACCESS); if (service) { CloseServiceHandle(service); status = SERVICES_remove(manager, guard_service_name.c_str(), /*guard_display_name.c_str(),*/ svc_error); if (status == FB_SUCCESS) { printf("Service \"%s\" successfully deleted.\n", guard_display_name.c_str()); } else if (status == IB_SERVICE_RUNNING) { printf("Service \"%s\" not deleted.\n", guard_display_name.c_str()); printf("You must stop it before attempting to delete it.\n\n"); } } else { status = (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST) ? FB_SUCCESS : FB_FAILURE; } service = OpenService(manager, remote_service_name.c_str(), SERVICE_ALL_ACCESS); if (service) { CloseServiceHandle(service); status2 = SERVICES_remove(manager, remote_service_name.c_str(), /*remote_display_name.c_str(),*/ svc_error); if (status2 == FB_SUCCESS) { printf("Service \"%s\" successfully deleted.\n", remote_display_name.c_str()); } else if (status2 == IB_SERVICE_RUNNING) { printf("Service \"%s\" not deleted.\n", remote_display_name.c_str()); printf("You must stop it before attempting to delete it.\n\n"); } } else { status2 = (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST) ? FB_SUCCESS : FB_FAILURE; } if (status != FB_SUCCESS && status2 != FB_SUCCESS) status = FB_FAILURE; break; case COMMAND_START: // Test for use of the guardian. If so, start the guardian else start the server service = OpenService(manager, guard_service_name.c_str(), SERVICE_START); if (service) { CloseServiceHandle(service); status = SERVICES_start(manager, guard_service_name.c_str(), /*guard_display_name.c_str(),*/ sw_mode, svc_error); if (status == FB_SUCCESS) { printf("Service \"%s\" successfully started.\n", guard_display_name.c_str()); } } else { CloseServiceHandle(service); status = SERVICES_start(manager, remote_service_name.c_str(), /*remote_display_name.c_str(),*/ sw_mode, svc_error); if (status == FB_SUCCESS) { printf("Service \"%s\" successfully started.\n", remote_display_name.c_str()); } } break; case COMMAND_STOP: // Test for use of the guardian. If so, stop the guardian else stop the server service = OpenService(manager, guard_service_name.c_str(), SERVICE_STOP); if (service) { CloseServiceHandle(service); status = SERVICES_stop(manager, guard_service_name.c_str(), /*guard_display_name.c_str(),*/ svc_error); if (status == FB_SUCCESS) { printf("Service \"%s\" successfully stopped.\n", guard_display_name.c_str()); } } else { CloseServiceHandle(service); status = SERVICES_stop(manager, remote_service_name.c_str(), /*remote_display_name.c_str(),*/ svc_error); if (status == FB_SUCCESS) { printf("Service \"%s\" successfully stopped.\n", remote_display_name.c_str()); } } break; case COMMAND_QUERY: if (svc_query_ex(manager) == FB_FAILURE) { svc_query(guard_service_name.c_str(), guard_display_name.c_str(), manager); svc_query(remote_service_name.c_str(), remote_display_name.c_str(), manager); } status = FB_SUCCESS; break; default: status = FB_SUCCESS; } CloseServiceHandle(manager); return (status == FB_SUCCESS) ? FINI_OK : FINI_ERROR; }
int CLIB_ROUTINE main( int argc, char **argv) { /************************************** * * m a i n * ************************************** * * Functional description * If there is no command line, prompt for one, read it * and make an artificial argc/argv. Otherwise, pass * the specified argc/argv to IBMGR_exec_line (see below). * **************************************/ fprintf(stderr, "*** fbmgr is deprecated, will be removed soon ***\n"); gds__log("*** fbmgr is deprecated, will be removed soon ***"); // Let's see if we have something in environment variables Firebird::string user, password; fb_utils::readenv(ISC_USER, user); fb_utils::readenv(ISC_PASSWORD, password); Firebird::string host; // MMM - do not allow to change host now //fb_utils::readenv("ISC_HOST", host); TEXT msg[MSG_LEN]; // Let's get a real user name. This info is used by // START server command. Because server is not running // we can not check the password, thus we require a // real user to be root or FIREBIRD_USER_NAME or // INTERBASE_USER_NAME or INTERBASE_USER_SHORT const struct passwd* pw = getpwuid(getuid()); if (pw == NULL) { perror("getpwuid"); SRVRMGR_msg_get(MSG_GETPWFAIL, msg); fprintf(OUTFILE, "%s\n", msg); exit(FINI_ERROR); } strcpy(ibmgr_data.real_user, pw->pw_name); if (!strcmp(pw->pw_name, "root") || !strcmp(pw->pw_name, FIREBIRD_USER_NAME) || !strcmp(pw->pw_name, INTERBASE_USER_NAME) || !strcmp(pw->pw_name, INTERBASE_USER_SHORT)) { strcpy(ibmgr_data.user, SYSDBA_USER_NAME); } else copy_str_upper(ibmgr_data.user, pw->pw_name); if (user.length()) copy_str_upper(ibmgr_data.user, user.c_str()); if (password.length()) strcpy(ibmgr_data.password, password.c_str()); else ibmgr_data.password[0] = '\0'; if (host.length()) strcpy(ibmgr_data.host, host.c_str()); else strcpy(ibmgr_data.host, "localhost"); // Shutdown is not in progress and we are not attached to service yet. // But obviously we will need attachment. ibmgr_data.shutdown = false; ibmgr_data.attached = 0; ibmgr_data.reattach |= (REA_HOST | REA_USER | REA_PASSWORD); // No pidfile by default ibmgr_data.pidfile[0] = 0; // Special case a solitary -z switch. // Print the version and then drop into prompt mode. if (argc == 2 && *argv[1] == '-' && (argv[1][1] == 'Z' || argv[1][1] == 'z')) { parse_cmd_line(argc, argv, false); argc--; } SSHORT ret; if (argc > 1) { ret = parse_cmd_line(argc, argv, true); if (ret == FB_SUCCESS) { ret = SRVRMGR_exec_line(&ibmgr_data); if (ret) { SRVRMGR_msg_get(ret, msg); fprintf(OUTFILE, "%s\n", msg); } // We also need to check the shutdown flag here (if operation was // -shut -[noat|notr]) and, depending on what we want to do, either // wait here on some sort of a shutdown event, or go to the prompt mode SRVRMGR_cleanup(&ibmgr_data); exit(FINI_OK); } else if (ret != ACT_PROMPT) exit(FINI_OK); } int local_argc; SCHAR* local_argv[MAXARGS]; TEXT stuff[MAXSTUFF]; for (;;) { if (get_line(&local_argc, local_argv, stuff)) break; if (local_argc > 1) { ret = parse_cmd_line(local_argc, local_argv, false); if (ret == ACT_QUIT) break; if (ret == FB_SUCCESS) { ret = SRVRMGR_exec_line(&ibmgr_data); if (ret) { SRVRMGR_msg_get(ret, msg); fprintf(OUTFILE, "%s\n", msg); } } } } SRVRMGR_cleanup(&ibmgr_data); exit(FINI_OK); }
qli_tok* LEX_token() { /************************************** * * L E X _ t o k e n * ************************************** * * Functional description * Parse and return the next token. * **************************************/ qli_tok* token = QLI_token; TEXT* p = token->tok_string; // Get next significant byte. If it's the last EOL of a blob, throw it away SSHORT c; for (;;) { c = skip_white(); if (c != '\n' || QLI_line->line_type != line_blob) break; qli_line* prior = QLI_line; next_line(true); if (prior == QLI_line) break; } // If we hit end of file, make up a phoney token if (!QLI_line) { const TEXT* q = eof_string; while (*p++ = *q++); token->tok_type = tok_eof; token->tok_keyword = KW_none; return NULL; } *p++ = c; QLI_token->tok_position = QLI_line->line_position + QLI_line->line_ptr - QLI_line->line_data - 1; // On end of file, generate furious but phone end of line tokens char char_class = classes(c); if (char_class & CHR_letter) { for (c = nextchar(true); classes(c) & CHR_ident; c = nextchar(true)) *p++ = c; retchar(); token->tok_type = tok_ident; } else if (((char_class & CHR_digit) || c == '.') && scan_number(c, &p)) token->tok_type = tok_number; else if (char_class & CHR_quote) { token->tok_type = tok_quoted; while (true) { const SSHORT next = nextchar(false); if (!next || next == '\n') { retchar(); IBERROR(63); // Msg 63 unterminated quoted string break; } *p++ = next; if ((p - token->tok_string) >= MAXSYMLEN) ERRQ_msg_put(470, SafeArg() << MAXSYMLEN); // Msg 470 literal too long // If there are 2 quotes in a row, interpret 2nd as a literal if (next == c) { const SSHORT peek = nextchar(false); retchar(); if (peek != c) break; nextchar(false); } } } else if (c == '\n') { // end of line, signal it properly with a phoney token. token->tok_type = tok_eol; --p; const TEXT* q = eol_string; while (*q) *p++ = *q++; } else { token->tok_type = tok_punct; *p++ = nextchar(true); if (!HSH_lookup(token->tok_string, 2)) { retchar(); --p; } } token->tok_length = p - token->tok_string; *p = '\0'; if (token->tok_string[0] == '$' && trans_limit < TRANS_LIMIT) { Firebird::string s; if (fb_utils::readenv(token->tok_string + 1, s)) { LEX_push_string(s.c_str()); ++trans_limit; token = LEX_token(); --trans_limit; return token; } } qli_symbol* symbol = HSH_lookup(token->tok_string, token->tok_length); token->tok_symbol = symbol; if (symbol && symbol->sym_type == SYM_keyword) token->tok_keyword = (kwwords) symbol->sym_keyword; else token->tok_keyword = KW_none; if (sw_trace) puts(token->tok_string); return token; }
/** callRemoteServiceManager @brief Calls service manager to execute command, specified in userInfo @param status @param handle @param userInfo @param outputFunction @param functionArg **/ void callRemoteServiceManager(ISC_STATUS* status, isc_svc_handle handle, Auth::UserData& userData, Firebird::IListUsers* callback) { char spb_buffer[1024]; char* spb = spb_buffer; const int op = userData.op; if (op != Auth::DIS_OPER && op != Auth::OLD_DIS_OPER && op != Auth::MAP_SET_OPER && op != Auth::MAP_DROP_OPER && !userData.user.entered()) { status[0] = isc_arg_gds; status[1] = isc_gsec_switches_error; status[2] = isc_arg_end; return; } switch (op) { case Auth::ADD_OPER: stuffSpbByte(spb, isc_action_svc_add_user); userInfoToSpb(spb, userData); break; case Auth::MOD_OPER: stuffSpbByte(spb, isc_action_svc_modify_user); userInfoToSpb(spb, userData); break; case Auth::DEL_OPER: stuffSpbByte(spb, isc_action_svc_delete_user); stuffSpb2(spb, isc_spb_sec_username, userData.user.get()); if (userData.role.entered()) { stuffSpb2(spb, isc_spb_sql_role_name, userData.role.get()); } break; case Auth::DIS_OPER: case Auth::OLD_DIS_OPER: { char usersDisplayTag = 0; checkServerUsersVersion(handle, usersDisplayTag); stuffSpbByte(spb, usersDisplayTag); } if (userData.user.entered()) { stuffSpb2(spb, isc_spb_sec_username, userData.user.get()); } if (userData.role.entered()) { stuffSpb2(spb, isc_spb_sql_role_name, userData.role.get()); } break; case Auth::MAP_SET_OPER: stuffSpbByte(spb, isc_action_svc_set_mapping); break; case Auth::MAP_DROP_OPER: stuffSpbByte(spb, isc_action_svc_drop_mapping); break; default: status[0] = isc_arg_gds; status[1] = isc_gsec_switches_error; status[2] = isc_arg_end; return; } if (userData.database.entered()) { stuffSpb2(spb, isc_spb_dbname, userData.database.get()); } fb_assert((size_t)(spb - spb_buffer) <= sizeof(spb_buffer)); if (isc_service_start(status, &handle, 0, static_cast<USHORT>(spb - spb_buffer), spb_buffer) != 0) { return; } spb = spb_buffer; stuffSpbByte(spb, isc_info_svc_timeout); stuffSpbShort(spb, 4); stuffSpbLong(spb, 10); char resultBuffer[RESULT_BUF_SIZE + 4]; Firebird::string text; ISC_STATUS_ARRAY temp_status; ISC_STATUS* local_status = status[1] ? temp_status : status; fb_utils::init_status(local_status); if (op == Auth::DIS_OPER || op == Auth::OLD_DIS_OPER) { const char request[] = {isc_info_svc_get_users}; int startQuery = 0; Auth::StackUserData uData; for (;;) { isc_resv_handle reserved = 0; isc_service_query(local_status, &handle, &reserved, static_cast<USHORT>(spb - spb_buffer), spb_buffer, sizeof(request), request, RESULT_BUF_SIZE - startQuery, &resultBuffer[startQuery]); if (local_status[1]) { return; } startQuery = typeBuffer(local_status, resultBuffer, startQuery, uData, callback, text); if (startQuery < 0) { break; } } if (uData.user.get()[0] && callback) { LocalStatus status; CheckStatusWrapper statusWrapper(&status); setAttr(&statusWrapper, &uData); check(&statusWrapper); callback->list(&statusWrapper, &uData); check(&statusWrapper); } } else { const char request = isc_info_svc_line; for (;;) { isc_resv_handle reserved = 0; isc_service_query(local_status, &handle, &reserved, 0, NULL, 1, &request, RESULT_BUF_SIZE, resultBuffer); if (local_status[1]) { return; } char *p = resultBuffer; if (*p++ == isc_info_svc_line) { FB_SIZE_T len = static_cast<FB_SIZE_T>(isc_vax_integer(p, sizeof(USHORT))); p += sizeof(USHORT); if (len > RESULT_BUF_SIZE) { len = RESULT_BUF_SIZE; } if (!len) { if (*p == isc_info_data_not_ready) continue; if (*p == isc_info_end) break; } p[len] = 0; text += p; } } } if (! text.isEmpty()) { local_status[0] = isc_arg_interpreted; // strdup - memory leak in case of errors local_status[1] = reinterpret_cast<ISC_STATUS>(strdup(text.c_str())); local_status[2] = isc_arg_end; } }
// allow different users to read\write\delete files in lock directory // in case of any error just log it and don't stop engine execution void adjustLockDirectoryAccess(const char* pathname) { PSECURITY_DESCRIPTOR pSecDesc = NULL; PSID pSID_Users = NULL; PSID pSID_Administrators = NULL; PACL pNewACL = NULL; try { // We should pass root directory in format "C:\" into GetVolumeInformation(). // In case of pathname is not local folder (i.e. \\share\folder) let // GetVolumeInformation() return an error. Firebird::PathName root(pathname); const Firebird::PathName::size_type pos = root.find(':', 0); if (pos == 1) { root.erase(pos + 1, root.length()); PathUtils::ensureSeparator(root); } DWORD fsflags; if (!GetVolumeInformation(root.c_str(), NULL, 0, NULL, NULL, &fsflags, NULL, 0)) Firebird::system_error::raise("GetVolumeInformation"); if (!(fsflags & FS_PERSISTENT_ACLS)) return; // Adjust security for our new folder : allow BUILTIN\Users group to // read\write\delete files PACL pOldACL = NULL; if (GetNamedSecurityInfo((LPSTR) pathname, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, &pOldACL, NULL, &pSecDesc) != ERROR_SUCCESS) { Firebird::system_error::raise("GetNamedSecurityInfo"); } SID_IDENTIFIER_AUTHORITY sidAuth = SECURITY_NT_AUTHORITY; if (!AllocateAndInitializeSid(&sidAuth, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_USERS, 0, 0, 0, 0, 0, 0, &pSID_Users)) { Firebird::system_error::raise("AllocateAndInitializeSid"); } if (!AllocateAndInitializeSid(&sidAuth, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pSID_Administrators)) { Firebird::system_error::raise("AllocateAndInitializeSid"); } EXPLICIT_ACCESS eas[2]; memset(eas, 0, sizeof(eas)); eas[0].grfAccessPermissions = FILE_GENERIC_READ | FILE_GENERIC_WRITE | DELETE; eas[0].grfAccessMode = GRANT_ACCESS; eas[0].grfInheritance = SUB_OBJECTS_ONLY_INHERIT; eas[0].Trustee.TrusteeForm = TRUSTEE_IS_SID; eas[0].Trustee.TrusteeType = TRUSTEE_IS_GROUP; eas[0].Trustee.ptstrName = (LPSTR) pSID_Users; eas[1].grfAccessPermissions = FILE_GENERIC_READ | FILE_GENERIC_WRITE | DELETE; eas[1].grfAccessMode = GRANT_ACCESS; eas[1].grfInheritance = SUB_OBJECTS_ONLY_INHERIT; eas[1].Trustee.TrusteeForm = TRUSTEE_IS_SID; eas[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP; eas[1].Trustee.ptstrName = (LPSTR) pSID_Administrators; if (SetEntriesInAcl(2, eas, pOldACL, &pNewACL) != ERROR_SUCCESS) Firebird::system_error::raise("SetEntriesInAcl"); if (SetNamedSecurityInfo((LPSTR) pathname, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, pNewACL, NULL) != ERROR_SUCCESS) { Firebird::system_error::raise("SetNamedSecurityInfo"); } } catch (const Firebird::Exception& ex) { Firebird::string str; str.printf("Error adjusting access rights for folder \"%s\" :", pathname); iscLogException(str.c_str(), ex); } if (pSID_Users) { FreeSid(pSID_Users); } if (pSID_Administrators) { FreeSid(pSID_Administrators); } if (pNewACL) { LocalFree(pNewACL); } if (pSecDesc) { LocalFree(pSecDesc); } }
void CryptoManager::changeCryptState(thread_db* tdbb, const Firebird::string& plugName) { if (plugName.length() > 31) { (Arg::Gds(isc_cp_name_too_long) << Arg::Num(31)).raise(); } bool newCryptState = plugName.hasData(); { // window scope Header hdr(tdbb, LCK_write); // Check header page for flags if (hdr->hdr_flags & Ods::hdr_crypt_process) { (Arg::Gds(isc_cp_process_active)).raise(); } bool headerCryptState = hdr->hdr_flags & Ods::hdr_encrypted; if (headerCryptState == newCryptState) { (Arg::Gds(isc_cp_already_crypted)).raise(); } fb_assert(stateLock); // Take exclusive stateLock bool ret = needLock ? LCK_lock(tdbb, stateLock, LCK_PW, LCK_WAIT) : LCK_convert(tdbb, stateLock, LCK_PW, LCK_WAIT); if (!ret) { fb_assert(tdbb->tdbb_status_vector[1]); ERR_punt(); } fb_utils::init_status(tdbb->tdbb_status_vector); needLock = false; // Load plugin if (newCryptState) { loadPlugin(plugName.c_str()); } crypt = newCryptState; // Write modified header page Ods::header_page* header = hdr.write(); if (crypt) { header->hdr_flags |= Ods::hdr_encrypted; plugName.copyTo(header->hdr_crypt_plugin, sizeof header->hdr_crypt_plugin); } else { header->hdr_flags &= ~Ods::hdr_encrypted; } header->hdr_flags |= Ods::hdr_crypt_process; process = true; } // Trigger lock on ChangeCryptState if (!LCK_convert(tdbb, stateLock, LCK_EX, LCK_WAIT)) { ERR_punt(); } if (!LCK_convert(tdbb, stateLock, LCK_SR, LCK_WAIT)) { ERR_punt(); } fb_utils::init_status(tdbb->tdbb_status_vector); // Now we may set hdr_crypt_page for crypt thread { // window scope Header hdr(tdbb, LCK_write); Ods::header_page* header = hdr.write(); header->hdr_crypt_page = 1; } startCryptThread(tdbb); }
ISC_STATUS API_ROUTINE isc_modify_user(ISC_STATUS* status, const USER_SEC_DATA* input_user_data) { /************************************** * * i s c _ m o d i f y _ u s e r * ************************************** * * Functional description * Adds a user to the server's security * database. * Return 0 if the user was added * * Return > 0 if any error occurs. * **************************************/ Auth::StackUserData userInfo; userInfo.op = Auth::MOD_OPER; Firebird::LocalStatus s; Firebird::CheckStatusWrapper statusWrapper(&s); if (input_user_data->user_name) { Firebird::string work = input_user_data->user_name; if (work.length() > USERNAME_LENGTH) { return user_error(status, isc_usrname_too_long); } Firebird::string::size_type l = work.find(' '); if (l != Firebird::string::npos) { work.resize(l); } userInfo.user.set(&statusWrapper, work.c_str()); check(&statusWrapper); userInfo.user.setEntered(&statusWrapper, 1); check(&statusWrapper); } else { return user_error(status, isc_usrname_required); } if (input_user_data->password) { userInfo.pass.set(&statusWrapper, input_user_data->password); check(&statusWrapper); userInfo.pass.setEntered(&statusWrapper, 1); check(&statusWrapper); } else { return user_error(status, isc_password_required); } copyField(userInfo.u, input_user_data->uid, input_user_data->sec_flags & sec_uid_spec); copyField(userInfo.g, input_user_data->gid, input_user_data->sec_flags & sec_gid_spec); copyField(userInfo.group, input_user_data->group_name, input_user_data->sec_flags & sec_group_name_spec); copyField(userInfo.first, input_user_data->first_name, input_user_data->sec_flags & sec_first_name_spec); copyField(userInfo.middle, input_user_data->middle_name, input_user_data->sec_flags & sec_middle_name_spec); copyField(userInfo.last, input_user_data->last_name, input_user_data->sec_flags & sec_last_name_spec); return executeSecurityCommand(status, input_user_data, userInfo); }
SINT64 ConfigFile::Parameter::asInteger() const { if (value.isEmpty()) return 0; SINT64 ret = 0; int sign = 1; int state = 1; // 1 - sign, 2 - numbers, 3 - multiplier Firebird::string trimmed = value; trimmed.trim(" \t"); if (trimmed.isEmpty()) return 0; const char* ch = trimmed.c_str(); for (; *ch; ch++) switch (*ch) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (state > 2) return 0; state = 2; ret = ret * 10 + (*ch - '0'); break; case '-': if (state > 1) return 0; sign = -sign; break; case ' ': case '\t': if (state == 1) break; return 0; case 'k': case 'K': if (state != 2) return 0; state = 3; ret = ret * 1024; break; case 'm': case 'M': if (state != 2) return 0; state = 3; ret = ret * 1024 * 1024; break; case 'g': case 'G': if (state != 2) return 0; state = 3; ret = ret * 1024 * 1024 * 1024; break; default: return 0; }; return sign * ret; }
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; };
void EVL_validate(thread_db* tdbb, const Item& item, const ItemInfo* itemInfo, dsc* desc, bool null) { /************************************** * * E V L _ v a l i d a t e * ************************************** * * Functional description * Validate argument/variable for not null and check constraint * **************************************/ if (itemInfo == NULL) return; jrd_req* request = tdbb->getRequest(); bool err = false; if (null && !itemInfo->nullable) err = true; const char* value = NULL_STRING_MARK; VaryStr<128> temp; MapFieldInfo::ValueType fieldInfo; if (!err && itemInfo->fullDomain && request->getStatement()->mapFieldInfo.get(itemInfo->field, fieldInfo) && fieldInfo.validationExpr) { if (desc && null) desc->dsc_flags |= DSC_null; const bool desc_is_null = !desc || (desc->dsc_flags & DSC_null); request->req_domain_validation = desc; const USHORT flags = request->req_flags; if (!fieldInfo.validationExpr->execute(tdbb, request) && !(request->req_flags & req_null)) { const USHORT length = desc_is_null ? 0 : MOV_make_string(desc, ttype_dynamic, &value, &temp, sizeof(temp) - 1); if (desc_is_null) value = NULL_STRING_MARK; else if (!length) value = ""; else const_cast<char*>(value)[length] = 0; // safe cast - data is on our local stack err = true; } request->req_flags = flags; } Firebird::string s; if (err) { ISC_STATUS status = isc_not_valid_for_var; const char* arg; if (item.type == Item::TYPE_CAST) { status = isc_not_valid_for; arg = "CAST"; } else { if (itemInfo->name.isEmpty()) { int index = item.index + 1; status = isc_not_valid_for; if (item.type == Item::TYPE_VARIABLE) { const jrd_prc* procedure = request->getStatement()->procedure; if (procedure) { if (index <= int(procedure->getOutputFields().getCount())) s.printf("output parameter number %d", index); else { s.printf("variable number %d", index - int(procedure->getOutputFields().getCount())); } } else s.printf("variable number %d", index); } else if (item.type == Item::TYPE_PARAMETER && item.subType == 0) s.printf("input parameter number %d", (index - 1) / 2 + 1); else if (item.type == Item::TYPE_PARAMETER && item.subType == 1) s.printf("output parameter number %d", index); if (s.isEmpty()) arg = UNKNOWN_STRING_MARK; else arg = s.c_str(); } else arg = itemInfo->name.c_str(); } ERR_post(Arg::Gds(status) << Arg::Str(arg) << Arg::Str(value)); } }