PC SOFT

PROFESSIONAL NEWSGROUPS
WINDEVWEBDEV and WINDEV Mobile

Home → WINDEV 25 → PostgreSQL: Solução atende aos requisitos de bloquear os comandos solicitados, registrar tentativas bloqueadas e funcionar de forma portátil em Windows, macOS e Linux.
PostgreSQL: Solução atende aos requisitos de bloquear os comandos solicitados, registrar tentativas bloqueadas e funcionar de forma portátil em Windows, macOS e Linux.
Started by Boller, May, 05 2025 1:51 PM - No answer
Registered member
3,963 messages
Posted on May, 05 2025 - 1:51 PM
Solução do bloqueio de comandos no PostgreSQL para não executar os comandos:

RENAME,
ALTER TABLE,
ALTER COLUMN
GRANT,
DROP,
TRUNCATE
DELETE,

E com registro em log e suporte para Windows, macOS e Linux.

Solução para Bloqueio de Comandos no PostgreSQL
Vamos implementar uma funcionalidade no PostgreSQL que bloqueia os comandos especificados (DROP, TRUNCATE, DELETE, RENAME, ALTER TABLE, ALTER COLUMN, GRANT) com base em um arquivo de configuração .ini e registra todas as tentativas bloqueadas em um log. A solução será portátil para Windows, macOS e Linux.
Visão Geral
1 Arquivo de Configuração: Um arquivo restrict_commands.ini define quais comandos são permitidos ou bloqueados por banco de dados.
2 Verificação de Permissões: Antes de executar cada comando, o código verifica se ele é permitido no banco de dados atual.
3 Registro em Log: Tentativas bloqueadas são registradas em um arquivo de log específico para cada banco de dados.
4 Portabilidade: O código usa funções do PostgreSQL que funcionam em todos os sistemas operacionais suportados.

Código-Fonte Atualizado
1. `restrict_commands.c`
Este arquivo contém a lógica principal para verificar permissões e registrar tentativas bloqueadas.


#include "postgres.h"
#include "utils/guc.h"
#include "storage/fd.h"
#include
#include
#include
#include

static char INI_PATH[1024];
static char LOG_PATH_BASE[1024];

// Inicializa caminhos dinamicamente na inicialização do módulo
void _PG_init(void) {
char share_path[MAXPGPATH];
get_share_path(my_exec_path, share_path);
snprintf(INI_PATH, sizeof(INI_PATH), "%s/restrict_commands.ini", share_path);
snprintf(LOG_PATH_BASE, sizeof(LOG_PATH_BASE), "%s/", DataDir);
}

bool check_command_permission(const char *dbname, const char *operation) {
FILE *fp = AllocateFile(INI_PATH, "r");
if (!fp) {
ereport(WARNING, (errmsg("Cannot open INI file: %s", INI_PATH)));
return true; // Permite por padrão se não conseguir ler
}

char line[256];
char section[128];
bool in_section = false;
snprintf(section, sizeof(section), "[%s]", dbname);

while (fgets(line, sizeof(line), fp)) {
if (strncmp(line, section, strlen(section)) == 0) {
in_section = true;
continue;
}
if (in_section && line[0] == '[')
break;

if (in_section && strstr(line, operation)) {
if (strstr(line, "false")) {
FreeFile(fp);
log_blocked_command(dbname, operation);
return false;
}
}
}

FreeFile(fp);
return true; // Permite por padrão se não especificado
}

void log_blocked_command(const char *dbname, const char *operation) {
char logpath[512];
snprintf(logpath, sizeof(logpath), "%s%s_blocked.log", LOG_PATH_BASE, dbname);

// Verifica permissões de escrita
if (access(LOG_PATH_BASE, W_OK) != 0) {
ereport(WARNING, (errmsg("Cannot write to log directory: %s", LOG_PATH_BASE)));
return;
}

FILE *logf = AllocateFile(logpath, "a");
if (!logf) {
ereport(WARNING, (errmsg("Cannot open log file: %s", logpath)));
return;
}

time_t now = time(NULL);
char *timestamp = ctime(&now);
timestamp[strlen(timestamp)-1] = '\0';

char *user = GetUserNameOrNull();
if (!user) user = "unknown";

fprintf(logf, "[%s] USER: %s tried: %s (BLOCKED)\n", timestamp, user, operation);
FreeFile(logf);
}



2. `restrict_commands.h`
Cabeçalho para as funções definidas em restrict_commands.c.
#ifndef RESTRICT_COMMANDS_H
#define RESTRICT_COMMANDS_H

bool check_command_permission(const char *dbname, const char *operation);
void log_blocked_command(const char *dbname, const char *operation);

#endif /* RESTRICT_COMMANDS_H */

Modificações nos Arquivos do PostgreSQL
Para bloquear os comandos especificados, modificamos os arquivos onde eles são processados, adicionando verificações de permissão.



3.1. `DROP`
• Arquivo: src/backend/commands/dbcommands.c
• Função: DropDatabase()
• Modificação: Adicione no início da função:
#include "utils/restrict_commands.h"
if (!check_command_permission(dbname, "drop")) {
ereport(ERROR, (errmsg("DROP DATABASE is blocked for this database by policy")));
}
• Nota: Para DROP TABLE e similares, use RemoveRelations em tablecmds.c:
#include "utils/restrict_commands.h"
if (!check_command_permission(get_database_name(MyDatabaseId), "drop")) {
ereport(ERROR, (errmsg("DROP is blocked for this database by policy")));
}



3.2. `TRUNCATE`
• Arquivo: src/backend/commands/tablecmds.c
• Função: ExecuteTruncateGuts()
• Modificação: Adicione no início da função:
#include "utils/restrict_commands.h"
if (!check_command_permission(get_database_name(MyDatabaseId), "truncate")) {
ereport(ERROR, (errmsg("TRUNCATE is blocked for this database by policy")));
}



3.3. `DELETE`
• Arquivo: src/backend/commands/delete.c
• Função: ExecDelete()
• Modificação: Adicione no início da função:
#include "utils/restrict_commands.h"
if (!check_command_permission(get_database_name(MyDatabaseId), "delete")) {
ereport(ERROR, (errmsg("DELETE is blocked for this database by policy")));
}



3.4. `RENAME`
• Arquivo: src/backend/commands/tablecmds.c
• Função: RenameRelation()
• Modificação: Adicione no início da função:
#include "utils/restrict_commands.h"
if (!check_command_permission(get_database_name(MyDatabaseId), "rename")) {
ereport(ERROR, (errmsg("RENAME is blocked for this database by policy")));
}



3.5. `ALTER TABLE` e `ALTER COLUMN`
• Arquivo: src/backend/commands/tablecmds.c
• Função: AlterTable()
• Modificação: Adicione no início da função uma verificação geral para ALTER TABLE. Para ALTER COLUMN, verifique o tipo de comando:
#include "utils/restrict_commands.h"
if (!check_command_permission(get_database_name(MyDatabaseId), "alter_table")) {
ereport(ERROR, (errmsg("ALTER TABLE is blocked for this database by policy")));
}
// Verificação específica para ALTER COLUMN
if (cmd->subtype == AT_AlterColumnType &&
!check_command_permission(get_database_name(MyDatabaseId), "alter_column")) {
ereport(ERROR, (errmsg("ALTER COLUMN is blocked for this database by policy")));
}



3.6. `GRANT`
• Arquivo: src/backend/commands/grant.c
• Função: ExecGrantStmt()
• Modificação: Adicione no início da função:
#include "utils/restrict_commands.h"
if (!check_command_permission(get_database_name(MyDatabaseId), "grant")) {
ereport(ERROR, (errmsg("GRANT is blocked for this database by policy")));
}



3.7. Atualização do Makefile
• Arquivo: src/backend/utils/misc/Makefile
• Modificação: Adicione restrict_commands.o à lista de objetos:
OBJS = ... restrict_commands.o ...



Exemplo de `restrict_commands.ini`

Coloque este arquivo no diretório share do PostgreSQL (ex.: /usr/local/pgsql/share/ no Linux/macOS ou

C:\Program Files\PostgreSQL\15\share no Windows).
[db_financeiro]
drop=false
truncate=false
delete=false
rename=false
alter_table=false
alter_column=false
grant=false

[db_erp]
drop=false
truncate=true
delete=true
rename=true
alter_table=true
alter_column=true
grant=true

[db_analytics]
drop=true
truncate=false
delete=false
rename=false
alter_table=false
alter_column=false
grant=false




Portabilidade para Windows, macOS e Linux
• O código usa funções do PostgreSQL como AllocateFile, FreeFile, get_share_path e DataDir, que são portáteis entre Windows, macOS e Linux.
• O arquivo .ini é lido de um caminho relativo ao diretório share, e os logs são gravados no diretório de dados (DataDir), garantindo compatibilidade com a estrutura de arquivos de cada sistema operacional.
• Nenhuma modificação específica por SO é necessária.



Como Aplicar as Mudanças
1 Adicione os arquivos restrict_commands.c e restrict_commands.h em src/backend/utils/misc/.
2 Aplique as modificações nos arquivos listados acima.
3 Compile o PostgreSQL com ./configure, make e make install.
4 Coloque o arquivo restrict_commands.ini no diretório share.
5 Reinicie o servidor PostgreSQL.
Os logs de tentativas bloqueadas serão gravados em /_blocked.log.



Arquivos Modificados
#############

Aqui está a lista final dos arquivos que devem ser modificados no código-fonte do PostgreSQL:
1 src/backend/utils/misc/restrict_commands.c: Código principal para verificação e logging.
2 src/include/utils/restrict_commands.h: Cabeçalho.
3 src/backend/commands/dbcommands.c: Para DROP DATABASE.
4 src/backend/commands/tablecmds.c: Para TRUNCATE, RENAME, ALTER TABLE, ALTER COLUMN,

DROP TABLE.
5 src/backend/commands/delete.c: Para DELETE.
6 src/backend/commands/grant.c: Para GRANT.
7 src/backend/utils/misc/Makefile: Adicionar restrict_commands.o.

Essa solução atende aos requisitos de bloquear os comandos solicitados, registrar tentativas bloqueadas e funcionar de forma portátil em Windows, macOS e Linux.

--
Adriano José Boller
______________________________________________
Consultor e Representante Oficial da
PcSoft no Brasil
+55 (41) 99949 1800
adrianoboller@gmail.com
skype: adrianoboller
http://wxinformatica.com.br/