From 5dcfb897d90b78c622a38855ae6ffd5cb2630d9f Mon Sep 17 00:00:00 2001 From: Ashutosh Sharma Date: Sat, 16 Mar 2024 01:48:44 +0530 Subject: [PATCH] [#407] Vault Implementation --- AUTHORS | 2 +- doc/CONFIGURATION.md | 2 + doc/VAULT.md | 50 ++ doc/etc/pgagroal_vault.conf | 12 + doc/man/pgagroal-admin.1.rst | 2 +- doc/man/pgagroal-cli.1.rst | 2 +- doc/man/pgagroal-vault.1.rst | 50 ++ doc/man/pgagroal.1.rst | 2 +- doc/man/pgagroal.conf.5.rst | 8 +- doc/man/pgagroal_databases.conf.5.rst | 2 +- doc/man/pgagroal_hba.conf.5.rst | 2 +- doc/man/pgagroal_vault.conf.5.rst | 94 +++ doc/tutorial/06_vault.md | 154 +++++ pgagroal.spec | 9 + src/CMakeLists.txt | 16 + src/admin.c | 56 +- src/cli.c | 29 +- src/include/configuration.h | 79 ++- src/include/management.h | 21 + src/include/network.h | 15 +- src/include/pgagroal.h | 135 +++-- src/include/security.h | 15 + src/include/utils.h | 19 + src/libpgagroal/configuration.c | 756 +++++++++++++++++++++---- src/libpgagroal/logging.c | 6 +- src/libpgagroal/management.c | 124 +++- src/libpgagroal/memory.c | 4 +- src/libpgagroal/network.c | 98 ++-- src/libpgagroal/pipeline_perf.c | 20 +- src/libpgagroal/pipeline_session.c | 26 +- src/libpgagroal/pipeline_transaction.c | 24 +- src/libpgagroal/pool.c | 66 +-- src/libpgagroal/prometheus.c | 52 +- src/libpgagroal/remote.c | 32 +- src/libpgagroal/security.c | 169 ++++-- src/libpgagroal/server.c | 32 +- src/libpgagroal/shmem.c | 4 +- src/libpgagroal/tracker.c | 16 +- src/libpgagroal/utils.c | 8 +- src/libpgagroal/worker.c | 10 +- src/main.c | 192 ++++--- src/vault.c | 568 +++++++++++++++++++ 42 files changed, 2408 insertions(+), 575 deletions(-) create mode 100644 doc/VAULT.md create mode 100644 doc/etc/pgagroal_vault.conf create mode 100644 doc/man/pgagroal-vault.1.rst create mode 100644 doc/man/pgagroal_vault.conf.5.rst create mode 100644 doc/tutorial/06_vault.md create mode 100644 src/vault.c diff --git a/AUTHORS b/AUTHORS index 8b37779a..c088e8a2 100644 --- a/AUTHORS +++ b/AUTHORS @@ -10,4 +10,4 @@ Lawrence Wu Yongting You <2010youy01@gmail.com> Ashutosh Sharma Henrique de Carvalho -Yihe Lu \ No newline at end of file +Yihe Lu diff --git a/doc/CONFIGURATION.md b/doc/CONFIGURATION.md index 74e0bf89..b3ee3537 100644 --- a/doc/CONFIGURATION.md +++ b/doc/CONFIGURATION.md @@ -61,6 +61,8 @@ The available keys and their accepted values are reported in the table below. | log_disconnections | `off` | Bool | No | Log disconnects | | blocking_timeout | 30 | Int | No | The number of seconds the process will be blocking for a connection (disable = 0) | | idle_timeout | 0 | Int | No | The number of seconds a connection is been kept alive (disable = 0) | +| rotate_frontend_password_timeout | 0 | Int | No | The number of seconds after which the passwords of frontend users are updated periodically (disable = 0) | +| rotate_frontend_password_length | 8 | Int | No | The length of the randomized frontend password | | max_connection_age | 0 | Int | No | The maximum number of seconds that a connection will live (disable = 0) | | validation | `off` | String | No | Should connection validation be performed. Valid options: `off`, `foreground` and `background` | | background_interval | 300 | Int | No | The interval between background validation scans in seconds | diff --git a/doc/VAULT.md b/doc/VAULT.md new file mode 100644 index 00000000..f67cf58e --- /dev/null +++ b/doc/VAULT.md @@ -0,0 +1,50 @@ +# pgagroal-vault configuration + +The configuration which is mandatory is loaded from either the path specified by the `-c` flag or `/etc/pgagroal/pgagroal_vault.conf`. + +The configuration of `pgagroal-vault` is split into sections using the `[` and `]` characters. + +The pgagroal-vault section, called `[pgagroal-vault]`, is where you configure the overall properties of the vault's server. + +The other section provide configuration for the management port of pgagroal. For now there can be only one pgagroal management port to connect. +This section don't have any requirements to their naming so you can give them +meaningful names but generally named as `[main]`. + +All properties within a section are in the format `key = value`. + +The characters `#` and `;` can be used for comments. A line is totally ignored if the +very first non-space character is a comment one, but it is possible to put a comment at the end of a line. +The `Bool` data type supports the following values: `on`, `yes`, `1`, `true`, `off`, `no`, `0` and `false`. + +See a more complete [sample](./etc/pgagroal_vault.conf) configuration for running `pgagroal-vault` on `localhost`. + +## [pgagroal-vault] + +This section is mandatory and the pooler will refuse to start if the configuration file does not specify one and only one. Usually this section is place on top of the configuration file, but its position within the file does not really matter. +The available keys and their accepted values are reported in the table below. + +| Property | Default | Unit | Required | Description | +|----------|---------|------|----------|-------------| +| host | | String | Yes | The bind address for pgagroal-vault | +| port | | Int | Yes | The bind port for pgagroal-vault | +| log_type | console | String | No | The logging type (console, file, syslog) | +| log_level | info | String | No | The logging level, any of the (case insensitive) strings `FATAL`, `ERROR`, `WARN`, `INFO` and `DEBUG` (that can be more specific as `DEBUG1` thru `DEBUG5`). Debug level greater than 5 will be set to `DEBUG5`. Not recognized values will make the log_level be `INFO` | +| log_path | pgagroal.log | String | No | The log file location. Can be a strftime(3) compatible string. | +| log_rotation_age | 0 | String | No | The age that will trigger a log file rotation. If expressed as a positive number, is managed as seconds. Supports suffixes: 'S' (seconds, the default), 'M' (minutes), 'H' (hours), 'D' (days), 'W' (weeks). A value of `0` disables. | +| log_rotation_size | 0 | String | No | The size of the log file that will trigger a log rotation. Supports suffixes: 'B' (bytes), the default if omitted, 'K' or 'KB' (kilobytes), 'M' or 'MB' (megabytes), 'G' or 'GB' (gigabytes). A value of `0` (with or without suffix) disables. | +| log_line_prefix | %Y-%m-%d %H:%M:%S | String | No | A strftime(3) compatible string to use as prefix for every log line. Must be quoted if contains spaces. | +| log_mode | append | String | No | Append to or create the log file (append, create) | +| log_connections | `off` | Bool | No | Log connects | +| log_disconnections | `off` | Bool | No | Log disconnects | + +## [main] + +The section with a name different from `pgagroal-vault` will be treated as a main section. + +| Property | Default | Unit | Required | Description | +|----------|---------|------|----------|-------------| +| host | | String | Yes | The address of the pgagroal running the management server | +| port | | Int | Yes | The management port of pgagroal | +| user | | String | Yes | The admin user of the pgagroal remote management service | + +Note: For `pgagroal-vault` to function and connect properly to pgagroal, the remote server for management of the `pgagroal` should be enabled i.e. `management` should be greater than 0. \ No newline at end of file diff --git a/doc/etc/pgagroal_vault.conf b/doc/etc/pgagroal_vault.conf new file mode 100644 index 00000000..75ed1219 --- /dev/null +++ b/doc/etc/pgagroal_vault.conf @@ -0,0 +1,12 @@ +[pgagroal-vault] +host = localhost +port = 2500 + +log_type = console +log_level = info +log_path = + +[main] +host = localhost +port = 2347 +user = admin diff --git a/doc/man/pgagroal-admin.1.rst b/doc/man/pgagroal-admin.1.rst index 179f5c24..c4d96a00 100644 --- a/doc/man/pgagroal-admin.1.rst +++ b/doc/man/pgagroal-admin.1.rst @@ -73,4 +73,4 @@ pgagroal is licensed under the 3-clause BSD License. SEE ALSO ======== -pgagroal.conf(5), pgagroal_hba.conf(5), pgagroal_databases.conf(5), pgagroal(1), pgagroal-cli(1) +pgagroal.conf(5), pgagroal_hba.conf(5), pgagroal_databases.conf(5), pgagroal_vault.conf(5), pgagroal(1), pgagroal-cli(1), pgagroal-vault(1) diff --git a/doc/man/pgagroal-cli.1.rst b/doc/man/pgagroal-cli.1.rst index d77ae1d2..bd6a2de6 100644 --- a/doc/man/pgagroal-cli.1.rst +++ b/doc/man/pgagroal-cli.1.rst @@ -108,4 +108,4 @@ pgagroal is licensed under the 3-clause BSD License. SEE ALSO ======== -pgagroal.conf(5), pgagroal_hba.conf(5), pgagroal_databases.conf(5), pgagroal(1), pgagroal-admin(1) +pgagroal.conf(5), pgagroal_hba.conf(5), pgagroal_databases.conf(5), pgagroal_vault.conf(5), pgagroal(1), pgagroal-admin(1), pgagroal-vault(1) diff --git a/doc/man/pgagroal-vault.1.rst b/doc/man/pgagroal-vault.1.rst new file mode 100644 index 00000000..789fc808 --- /dev/null +++ b/doc/man/pgagroal-vault.1.rst @@ -0,0 +1,50 @@ +============== +pgagroal-vault +============== + +-------------------------------------------------------------------------------- +Simple vault that hosts an HTTP server to handle user frontend password requests +-------------------------------------------------------------------------------- + +:Manual section: 1 + +SYNOPSIS +======== + +pgagroal-vault [ -c CONFIG_FILE ] [ -u USERS_FILE ] + +DESCRIPTION +=========== + +**pgagroal-vault** is a basic HTTP server designed to handle special HTTP GET requests for retrieving pgagroal user passwords. When a client sends an HTTP GET request to ``http://:/users/``, the vault extracts ```` from the URL. It then connects to the pgagroal main process to fetch the current ```` corresponding to the ````. + +If the vault successfully fetches the ````, it responds with an HTTP status code 200 and includes ```` in the response body. Otherwise, the server responds with an HTTP 404 error indicating that the password for the specified user could not be found. + +**Note:** For pgagroal-vault to operate correctly, the management port of the pgagroal server must be open and functional. + +OPTIONS +======= + +-c, --config CONFIG_FILE + Set the path to the pgagroal_vault.conf file + +-u, --users USERS_FILE + Set the path to the pgagroal_vault_users.conf file + +-?, --help + Display help + +REPORTING BUGS +============== + +pgagroal is maintained on GitHub at https://github.com/agroal/pgagroal + +COPYRIGHT +========= + +pgagroal is licensed under the 3-clause BSD License. + +SEE ALSO +======== + +pgagroal.conf(5), pgagroal_hba.conf(5), pgagroal_databases.conf(5), pgagroal_vault.conf(5), pgagroal-cli(1), pgagroal-admin(1), pgagroal(1) diff --git a/doc/man/pgagroal.1.rst b/doc/man/pgagroal.1.rst index 95d2bb8d..9a5f7ac1 100644 --- a/doc/man/pgagroal.1.rst +++ b/doc/man/pgagroal.1.rst @@ -61,4 +61,4 @@ pgagroal is licensed under the 3-clause BSD License. SEE ALSO ======== -pgagroal.conf(5), pgagroal_hba.conf(5), pgagroal_databases.conf(5), pgagroal-cli(1), pgagroal-admin(1) +pgagroal.conf(5), pgagroal_hba.conf(5), pgagroal_databases.conf(5), pgagroal_vault.conf(5), pgagroal-cli(1), pgagroal-admin(1), pgagroal-vault(1) diff --git a/doc/man/pgagroal.conf.5.rst b/doc/man/pgagroal.conf.5.rst index d0aeb1de..1c3e41b7 100644 --- a/doc/man/pgagroal.conf.5.rst +++ b/doc/man/pgagroal.conf.5.rst @@ -95,6 +95,12 @@ blocking_timeout idle_timeout The number of seconds a connection is been kept alive (disable = 0). Default is 0 +rotate_frontend_password_timeout + The number of seconds after which the passwords of frontend users are updated periodically (disable = 0). Default is 0 + +rotate_frontend_password_length + The length of randomized frontend passwords. Default is 8 + max_connection_age The maximum number of seconds that a connection will live (disable = 0). Default is 0 @@ -216,4 +222,4 @@ pgagroal is licensed under the 3-clause BSD License. SEE ALSO ======== -pgagroal_hba.conf(5), pgagroal_databases.conf(5), pgagroal(1), pgagroal-cli(1), pgagroal-admin(1) +pgagroal_hba.conf(5), pgagroal_databases.conf(5), pgagroal_vault.conf(5), pgagroal(1), pgagroal-cli(1), pgagroal-admin(1), pgagroal-vault(1) diff --git a/doc/man/pgagroal_databases.conf.5.rst b/doc/man/pgagroal_databases.conf.5.rst index 9332f046..91f13b71 100644 --- a/doc/man/pgagroal_databases.conf.5.rst +++ b/doc/man/pgagroal_databases.conf.5.rst @@ -55,4 +55,4 @@ pgagroal is licensed under the 3-clause BSD License. SEE ALSO ======== -pgagroal.conf(5), pgagroal_hba.conf(5), pgagroal(1), pgagroal-cli(1), pgagroal-admin(1) +pgagroal.conf(5), pgagroal_hba.conf(5), pgagroal_vault.conf(5), pgagroal(1), pgagroal-cli(1), pgagroal-admin(1), pgagroal-vault(1) diff --git a/doc/man/pgagroal_hba.conf.5.rst b/doc/man/pgagroal_hba.conf.5.rst index e5e5ebf3..3ba6165e 100644 --- a/doc/man/pgagroal_hba.conf.5.rst +++ b/doc/man/pgagroal_hba.conf.5.rst @@ -55,4 +55,4 @@ pgagroal is licensed under the 3-clause BSD License. SEE ALSO ======== -pgagroal.conf(5), pgagroal_databases.conf(5), pgagroal(1), pgagroal-cli(1), pgagroal-admin(1) +pgagroal.conf(5), pgagroal_databases.conf(5), pgagroal_vault.conf(5), pgagroal(1), pgagroal-cli(1), pgagroal-admin(1), pgagroal-vault(1) diff --git a/doc/man/pgagroal_vault.conf.5.rst b/doc/man/pgagroal_vault.conf.5.rst new file mode 100644 index 00000000..15639d3d --- /dev/null +++ b/doc/man/pgagroal_vault.conf.5.rst @@ -0,0 +1,94 @@ +=================== +pgagroal_vault.conf +=================== + +------------------------------------------ +Main configuration file for pgagroal-vault +------------------------------------------ + +:Manual section: 5 + +DESCRIPTION +=========== + +pgagroal_vault.conf is the main configuration file for pgagroal-vault. + +The file is split into different sections specified by the ``[`` and ``]`` characters. The main section is called ``[pgagroal-vault]``. + +Other sections (generally called the ``main`` section) specifies the ``pgagroal`` remote management configuration. + +All properties are in the format ``key = value``. + +The characters ``#`` and ``;`` can be used for comments; must be the first character on the line. +The ``Bool`` data type supports the following values: ``on``, ``1``, ``true``, ``off``, ``0`` and ``false``. + +OPTIONS +======= + +The options for the pgagroal-vault section are + +host + The bind address for pgagroal-vault. Mandatory + +port + The bind port for pgagroal-vault. Mandatory + +log_type + The logging type (console, file, syslog). Default is console + +log_level + The logging level, any of the (case insensitive) strings ``FATAL``, ``ERROR``, ``WARN``, ``INFO`` and ``DEBUG`` + (that can be more specific as ``DEBUG1`` thru ``DEBUG5``). Debug level greater than 5 will be set to ``DEBUG5``. + Not recognized values will make the ``log_level`` be ``INFO``. Default is info + +log_path + The log file location. Default is pgagroal-vault.log. Can be a strftime(3) compatible string + +log_rotation_age + The age that will trigger a log file rotation. If expressed as a positive number, is managed as seconds. + Supports suffixes: ``S`` (seconds, the default), ``M`` (minutes), ``H`` (hours), ``D`` (days), ``W`` (weeks). + A value of ``0`` disables. Default is 0 (disabled) + +log_rotation_size + The size of the log file that will trigger a log rotation. Supports suffixes: ``B`` (bytes), the default if omitted, + ``K`` or ``KB`` (kilobytes), ``M`` or ``MB`` (megabytes), ``G`` or ``GB`` (gigabytes). A value of ``0`` (with or without suffix) disables. + Default is 0 + +log_line_prefix + A strftime(3) compatible string to use as prefix for every log line. Must be quoted if contains spaces. + Default is ``%Y-%m-%d %H:%M:%S`` + +log_mode + Append to or create the log file (append, create). Default is append + +log_connections + Log connects. Default is off + +log_disconnections + Log disconnects. Default is off + +The options for the main section are + +host + The address of the pgagroal instance running the management server. Mandatory + +port + The management port of pgagroal. Mandatory + +user + The admin user of the pgagroal remote management service. Mandatory + +REPORTING BUGS +============== + +pgagroal is maintained on GitHub at https://github.com/agroal/pgagroal + +COPYRIGHT +========= + +pgagroal is licensed under the 3-clause BSD License. + +SEE ALSO +======== + +pgagroal.conf(5), pgagroal_hba.conf(5), pgagroal_databases.conf(5), pgagroal(1), pgagroal-cli(1), pgagroal-admin(1), pgagroal-vault(1) diff --git a/doc/tutorial/06_vault.md b/doc/tutorial/06_vault.md new file mode 100644 index 00000000..96b3aef8 --- /dev/null +++ b/doc/tutorial/06_vault.md @@ -0,0 +1,154 @@ +# Setup pgagroal-vault + +This tutorial will show you how to do setup `pgagroal-vault`. + +## Preface + +This tutorial assumes that you have already an installation of PostgreSQL 12 (or higher) and `pgagroal` and also assumes that the remote management is enabled in `pgagroal`. + +In particular, this tutorial refers to the configuration done in [Install pgagroal](https://github.com/pgagroal/pgagroal/blob/master/doc/tutorial/01_install.md). + +Moreover refer to [Enable Remote Management](https://github.com/pgagroal/pgagroal/blob/master/doc/tutorial/03_remote_management.md) to enable remote management and add remote admin user. + +## `pgagroal` users setup + +Assuming that the master key is already generated and an admin is already present for remote management with `admin` username and `admin1234` password. + +### Create a user + +As the `pgagroal` operating system user, add the `myuser` to the pooler: + +``` +pgagroal-admin -f /etc/pgagroal/pgagroal_users.conf -U myuser -P mypassword user add +``` + +The `myuser` and `mypassword` should be the original PostgresSQL's user and its corresponding password. + +### Create a frontend user + +As the `pgagroal` operating system user, add the `myuser` to the pooler: + +``` +pgagroal-admin -f /etc/pgagroal/pgagroal_frontend_users.conf -U myuser -P password user add +``` + +**Remember the frontend password should be between [8-1024] characters long.** + +## Enable Rotation of frontend passwords + +In the main configuration file of `pgagroal` add the following configurations for rotating frontend passwords and make sure management port is enabled in the **[pgagroal]** section of the configuration file. + +``` +management = 2347 +rotate_frontend_password_timeout = 60 +rotate_frontend_password_length = 12 +``` + +## `pgagroal-vault` setup + +In order to run `pgagroal-vault`, you need to configure the vault `pgagroal_vault.conf` configuration file, that will tell the vault how to work, which address to listen, address of management service in `pgagroal` so on, and then `pgagroal_vault_users.conf` that will instrument the vault about the admin username and password of the remote management. + +### Create basic configuration + +It is now time to create the main `/etc/pgagroal/pgagroal_vault.conf` configration file, with your editor of choice of using `cat` from the command line, create the following content: + +``` +cd /etc/pgagroal +cat > pgagroal_vault.conf +[pgagroal-vault] +host = localhost +port = 2500 + +log_type = console +log_level = info +log_path = + +[main] +host = localhost +port = 2347 +user = admin +``` + +and press `Ctrl-D` (if running `cat`) to save the file. + +### Add users file + +As the `pgagroal` operating system user, run the following command: + +``` +pgagroal-admin -f /etc/pgagroal/pgagroal_vault_users.conf -U admin -P admin1234 add-user +``` + +The above will create the `admin` username with the `admin1234` password.Alternately, `/etc/pgagroal/pgagroal_admins.conf` can be provided for vault users information. + +See [the documentation about `pgagroal_vault.conf` for more details](https://github.com/agroal/pgagroal/blob/master/doc/VAULT.md). + +## Start pgagroal-vault + +It is now time to start `pgagroal-vault`, so as the `pgagroal` operating system user run: + +``` +pgagroal-vault -c /etc/pgagroal/pgagroal_vault.conf -u /etc/pgagroal/pgagroal_vault_users.conf +``` + +**Remember if both pgagroal and vault are operating on same system `pgagroal_vault_users.conf` can be same as `pgagroal_admins.conf`** + +This command initializes an HTTP server on localhost port 2500, which is primed to exclusively handle GET requests from clients. + +## Connect to vault + +Since we have deployed an HTTP server we can simply use `curl` to send GET requests + +### Correct requests + +If the requested URL is of form `http://:/users/` such that `` exists, the server will return a header response with `200 status code` and the frontend password corresponding to the `` in the response body. + +**Example** + +` +curl -i http://localhost:2500/users/myuser +` + +Output + +``` +HTTP/1.1 200 OK +Content-Type: text/plain + + +password +``` + +### Incorrect requests + +All the POST requests will be ignored and the server will send a `HTTP 404 ERROR` as a response. + +Any URL other than the format: `http://:/users/*` will result in `HTTP 404 ERROR`. + +**Example** + +` +curl -i http://localhost:2500/user +` + +Output + +``` +HTTP/1.1 404 Not Found + +``` + +A URL of form `http://:/users/` such that `` does not exist will also give `HTTP 404 ERROR`. + +**Example** + +` +curl -i http://localhost:2500/users/randomuser +` + +Output + +``` +HTTP/1.1 404 Not Found + +``` \ No newline at end of file diff --git a/pgagroal.spec b/pgagroal.spec index d19f98c0..6508f7a4 100644 --- a/pgagroal.spec +++ b/pgagroal.spec @@ -45,6 +45,7 @@ cmake -DCMAKE_BUILD_TYPE=Release .. %{__install} -m 644 %{_builddir}/%{name}-%{version}/doc/ARCHITECTURE.md %{buildroot}%{_docdir}/%{name}/ARCHITECTURE.md %{__install} -m 644 %{_builddir}/%{name}-%{version}/doc/CLI.md %{buildroot}%{_docdir}/%{name}/CLI.md %{__install} -m 644 %{_builddir}/%{name}-%{version}/doc/CONFIGURATION.md %{buildroot}%{_docdir}/%{name}/CONFIGURATION.md +%{__install} -m 644 %{_builddir}/%{name}-%{version}/doc/VAULT.md %{buildroot}%{_docdir}/%{name}/VAULT.md %{__install} -m 644 %{_builddir}/%{name}-%{version}/doc/FAILOVER.md %{buildroot}%{_docdir}/%{name}/FAILOVER.md %{__install} -m 644 %{_builddir}/%{name}-%{version}/doc/GETTING_STARTED.md %{buildroot}%{_docdir}/%{name}/GETTING_STARTED.md %{__install} -m 644 %{_builddir}/%{name}-%{version}/doc/PERFORMANCE.md %{buildroot}%{_docdir}/%{name}/PERFORMANCE.md @@ -71,19 +72,23 @@ cmake -DCMAKE_BUILD_TYPE=Release .. %{__install} -m 644 %{_builddir}/%{name}-%{version}/build/doc/pgagroal.1 %{buildroot}%{_mandir}/man1/pgagroal.1 %{__install} -m 644 %{_builddir}/%{name}-%{version}/build/doc/pgagroal-admin.1 %{buildroot}%{_mandir}/man1/pgagroal-admin.1 %{__install} -m 644 %{_builddir}/%{name}-%{version}/build/doc/pgagroal-cli.1 %{buildroot}%{_mandir}/man1/pgagroal-cli.1 +%{__install} -m 644 %{_builddir}/%{name}-%{version}/build/doc/pgagroal-vault.1 %{buildroot}%{_mandir}/man1/pgagroal-vault.1 %{__install} -m 644 %{_builddir}/%{name}-%{version}/build/doc/pgagroal.conf.5 %{buildroot}%{_mandir}/man5/pgagroal.conf.5 %{__install} -m 644 %{_builddir}/%{name}-%{version}/build/doc/pgagroal_databases.conf.5 %{buildroot}%{_mandir}/man5/pgagroal_databases.conf.5 %{__install} -m 644 %{_builddir}/%{name}-%{version}/build/doc/pgagroal_hba.conf.5 %{buildroot}%{_mandir}/man5/pgagroal_hba.conf.5 +%{__install} -m 644 %{_builddir}/%{name}-%{version}/build/doc/pgagroal_vault.conf.5 %{buildroot}%{_mandir}/man5/pgagroal_vault.conf.5 %{__install} -m 755 %{_builddir}/%{name}-%{version}/build/src/pgagroal %{buildroot}%{_bindir}/pgagroal %{__install} -m 755 %{_builddir}/%{name}-%{version}/build/src/pgagroal-cli %{buildroot}%{_bindir}/pgagroal-cli %{__install} -m 755 %{_builddir}/%{name}-%{version}/build/src/pgagroal-admin %{buildroot}%{_bindir}/pgagroal-admin +%{__install} -m 755 %{_builddir}/%{name}-%{version}/build/src/pgagroal-vault %{buildroot}%{_bindir}/pgagroal-vault %{__install} -m 755 %{_builddir}/%{name}-%{version}/build/src/libpgagroal.so.%{version} %{buildroot}%{_libdir}/libpgagroal.so.%{version} chrpath -r %{_libdir} %{buildroot}%{_bindir}/pgagroal chrpath -r %{_libdir} %{buildroot}%{_bindir}/pgagroal-cli chrpath -r %{_libdir} %{buildroot}%{_bindir}/pgagroal-admin +chrpath -r %{_libdir} %{buildroot}%{_bindir}/pgagroal-vault cd %{buildroot}%{_libdir}/ %{__ln_s} -f libpgagroal.so.%{version} libpgagroal.so.1 @@ -95,6 +100,7 @@ cd %{buildroot}%{_libdir}/ %{_docdir}/%{name}/CLI.md %{_docdir}/%{name}/CODE_OF_CONDUCT.md %{_docdir}/%{name}/CONFIGURATION.md +%{_docdir}/%{name}/VAULT.md %{_docdir}/%{name}/FAILOVER.md %{_docdir}/%{name}/GETTING_STARTED.md %{_docdir}/%{name}/PERFORMANCE.md @@ -121,14 +127,17 @@ cd %{buildroot}%{_libdir}/ %{_mandir}/man1/pgagroal.1* %{_mandir}/man1/pgagroal-admin.1* %{_mandir}/man1/pgagroal-cli.1* +%{_mandir}/man1/pgagroal-vault.1* %{_mandir}/man5/pgagroal.conf.5* %{_mandir}/man5/pgagroal_databases.conf.5* %{_mandir}/man5/pgagroal_hba.conf.5* +%{_mandir}/man5/pgagroal_vault.conf.5* %config %{_sysconfdir}/pgagroal/pgagroal.conf %config %{_sysconfdir}/pgagroal/pgagroal_hba.conf %{_bindir}/pgagroal %{_bindir}/pgagroal-cli %{_bindir}/pgagroal-admin +%{_bindir}/pgagroal-vault %{_libdir}/libpgagroal.so %{_libdir}/libpgagroal.so.1 %{_libdir}/libpgagroal.so.%{version} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fea97ab9..d0cea712 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -321,3 +321,19 @@ target_link_libraries(pgagroal-admin-bin pgagroal) install(TARGETS pgagroal-admin-bin DESTINATION ${CMAKE_INSTALL_BINDIR}) + + +# +# Build pgagroal-vault +# +add_executable(pgagroal-vault-bin vault.c ${RESOURCE_OBJECT}) +if (CMAKE_C_LINK_PIE_SUPPORTED) + set_target_properties(pgagroal-vault-bin PROPERTIES LINKER_LANGUAGE C POSITION_INDEPENDENT_CODE TRUE OUTPUT_NAME pgagroal-vault) +else() + set_target_properties(pgagroal-vault-bin PROPERTIES LINKER_LANGUAGE C POSITION_INDEPENDENT_CODE FALSE OUTPUT_NAME pgagroal-vault) +endif() +target_link_libraries(pgagroal-vault-bin pgagroal) + +install(TARGETS pgagroal-vault-bin DESTINATION ${CMAKE_INSTALL_BINDIR}) + + diff --git a/src/admin.c b/src/admin.c index daee40f6..665fc260 100644 --- a/src/admin.c +++ b/src/admin.c @@ -45,9 +45,6 @@ #include #include -#define DEFAULT_PASSWORD_LENGTH 64 -#define MIN_PASSWORD_LENGTH 8 - #define ACTION_UNKNOWN 0 #define ACTION_MASTER_KEY 1 #define ACTION_ADD_USER 2 @@ -55,18 +52,11 @@ #define ACTION_REMOVE_USER 4 #define ACTION_LIST_USERS 5 -static char CHARS[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '-', '_', '=', '+', '[', '{', ']', '}', '\\', '|', ';', ':', - '\'', '\"', ',', '<', '.', '>', '/', '?'}; - static int master_key(char* password, bool generate_pwd, int pwd_length); static int add_user(char* users_path, char* username, char* password, bool generate_pwd, int pwd_length); static int update_user(char* users_path, char* username, char* password, bool generate_pwd, int pwd_length); static int remove_user(char* users_path, char* username); static int list_users(char* users_path); -static char* generate_password(int pwd_length); const struct pgagroal_command command_table[] = { @@ -425,8 +415,11 @@ master_key(char* password, bool generate_pwd, int pwd_length) } else { - password = generate_password(pwd_length); - do_free = false; + if (pgagroal_generate_password(pwd_length, &password)) + { + do_free = false; + goto error; + } } } else @@ -547,7 +540,11 @@ add_user(char* users_path, char* username, char* password, bool generate_pwd, in password: if (generate_pwd) { - password = generate_password(pwd_length); + if (pgagroal_generate_password(pwd_length, &password)) + { + do_free = false; + goto error; + } do_verify = false; printf("Password : %s", password); } @@ -721,7 +718,11 @@ update_user(char* users_path, char* username, char* password, bool generate_pwd, password: if (generate_pwd) { - password = generate_password(pwd_length); + if (pgagroal_generate_password(pwd_length, &password)) + { + do_free = false; + goto error; + } do_verify = false; printf("Password : %s", password); } @@ -969,30 +970,3 @@ list_users(char* users_path) return 1; } - -static char* -generate_password(int pwd_length) -{ - char* pwd; - size_t s; - time_t t; - - s = pwd_length + 1; - - pwd = calloc(1, s); - if (pwd == NULL) - { - pgagroal_log_fatal("Couldn't allocate memory while generating password"); - return NULL; - } - - srand((unsigned)time(&t)); - - for (int i = 0; i < s; i++) - { - *((char*)(pwd + i)) = CHARS[rand() % sizeof(CHARS)]; - } - *((char*)(pwd + pwd_length)) = '\0'; - - return pwd; -} diff --git a/src/cli.c b/src/cli.c index bb331e34..63e88a9e 100644 --- a/src/cli.c +++ b/src/cli.c @@ -499,7 +499,7 @@ main(int argc, char** argv) int option_index = 0; size_t size; char un[MAX_USERNAME_LENGTH]; - struct configuration* config = NULL; + struct main_configuration* config = NULL; bool remote_connection = false; long l_port; char output_format = COMMAND_OUTPUT_FORMAT_TEXT; @@ -616,7 +616,7 @@ main(int argc, char** argv) exit(1); } - size = sizeof(struct configuration); + size = sizeof(struct main_configuration); if (pgagroal_create_shared_memory(size, HUGEPAGE_OFF, &shmem)) { errx(1, "Error creating shared memory"); @@ -637,11 +637,11 @@ main(int argc, char** argv) if (logfile) { - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; - config->log_type = PGAGROAL_LOGGING_TYPE_FILE; - memset(&config->log_path[0], 0, MISC_LENGTH); - memcpy(&config->log_path[0], logfile, MIN(MISC_LENGTH - 1, strlen(logfile))); + config->common.log_type = PGAGROAL_LOGGING_TYPE_FILE; + memset(&config->common.log_path[0], 0, MISC_LENGTH); + memcpy(&config->common.log_path[0], logfile, MIN(MISC_LENGTH - 1, strlen(logfile))); } if (pgagroal_start_logging()) @@ -649,7 +649,7 @@ main(int argc, char** argv) errx(1, "Cannot start the logging subsystem"); } - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; } else { @@ -667,11 +667,11 @@ main(int argc, char** argv) if (logfile) { - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; - config->log_type = PGAGROAL_LOGGING_TYPE_FILE; - memset(&config->log_path[0], 0, MISC_LENGTH); - memcpy(&config->log_path[0], logfile, MIN(MISC_LENGTH - 1, strlen(logfile))); + config->common.log_type = PGAGROAL_LOGGING_TYPE_FILE; + memset(&config->common.log_path[0], 0, MISC_LENGTH); + memcpy(&config->common.log_path[0], logfile, MIN(MISC_LENGTH - 1, strlen(logfile))); } if (pgagroal_start_logging()) @@ -679,7 +679,7 @@ main(int argc, char** argv) errx(1, "Cannot start the logging subsystem"); } - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; } } @@ -703,10 +703,9 @@ main(int argc, char** argv) else { /* Remote connection */ - if (pgagroal_connect(host, atoi(port), &socket)) + if (pgagroal_connect(host, atoi(port), &socket, config->keep_alive, config->non_blocking, &config->buffer_size, config->nodelay)) { /* Remote connection */ - l_port = strtol(port, NULL, 10); if ((errno == ERANGE && (l_port == LONG_MAX || l_port == LONG_MIN)) || (errno != 0 && l_port == 0)) { @@ -722,7 +721,7 @@ main(int argc, char** argv) goto done; } - if (pgagroal_connect(host, (int)l_port, &socket)) + if (pgagroal_connect(host, (int)l_port, &socket, config->keep_alive, config->non_blocking, &config->buffer_size, config->nodelay)) { warnx("No route to host: %s:%ld\n", host, l_port); goto done; diff --git a/src/include/configuration.h b/src/include/configuration.h index a1e2b67e..1d15d24e 100644 --- a/src/include/configuration.h +++ b/src/include/configuration.h @@ -40,6 +40,11 @@ extern "C" { * configuration file. */ #define PGAGROAL_MAIN_INI_SECTION "pgagroal" +/* + * The main section that must be present in the `pgagroal_vault.conf` + * configuration file. + */ +#define PGAGROAL_VAULT_INI_SECTION "pgagroal-vault" /* * The following constants are used to clearly identify @@ -70,11 +75,19 @@ extern "C" { int pgagroal_init_configuration(void* shmem); +/** + * Initialize the vault configuration structure + * @param shmem The shared memory segment + * @return 0 upon success, otherwise 1 + */ +int +pgagroal_vault_init_configuration(void* shmem); + /** * Read the configuration from a file * @param shmem The shared memory segment * @param filename The file name - * @param emitWarnings true if unknown parameters have to + * @param emit_warnings true if unknown parameters have to * reported on stderr * @return 0 (i.e, PGAGROAL_CONFIGURATION_STATUS_OK) upon success, otherwise * - PGAGROAL_CONFIGURATION_STATUS_FILE_NOT_FOUND if the file does not exists @@ -84,7 +97,7 @@ pgagroal_init_configuration(void* shmem); * a [pgagroal] section */ int -pgagroal_read_configuration(void* shmem, char* filename, bool emitWarnings); +pgagroal_read_configuration(void* shmem, char* filename, bool emit_warnings); /** * Validate the configuration @@ -96,6 +109,30 @@ pgagroal_read_configuration(void* shmem, char* filename, bool emitWarnings); int pgagroal_validate_configuration(void* shmem, bool has_unix_socket, bool has_main_sockets); +/** + * Read the configuration of vault from a file + * @param shmem The shared memory segment + * @param filename The file name + * @param emit_warnings true if unknown parameters have to + * reported on stderr + * @return 0 (i.e, PGAGROAL_CONFIGURATION_STATUS_OK) upon success, otherwise + * - PGAGROAL_CONFIGURATION_STATUS_FILE_NOT_FOUND if the file does not exists + * - PGAGROAL_CONFIGURATION_STATUS_FILE_TOO_BIG if the file contains too many sections + * - a positive value to indicate how many errors (with regard to sections) have been found + * - PGAGROAL_CONFIGURATION_STATUS_KO if the file has generic errors, most notably it lacks + * a [pgagroal-vault] section + */ +int +pgagroal_vault_read_configuration(void* shmem, char* filename, bool emit_warnings); + +/** + * Validate the configuration of vault + * @param shmem The shared memory segment + * @return 0 upon success, otherwise 1 + */ +int +pgagroal_vault_validate_configuration(void* shmem); + /** * Read the HBA configuration from a file * @param shmem The shared memory segment @@ -193,6 +230,19 @@ pgagroal_validate_frontend_users_configuration(void* shmem); int pgagroal_read_admins_configuration(void* shmem, char* filename); +/** + * Read the USERS configuration of vault from a file + * @param shmem The shared memory segment + * @param filename The file name + * @return 0 (i.e, PGAGROAL_CONFIGURATION_STATUS_OK) upon success, otherwise + * - PGAGROAL_CONFIGURATION_STATUS_FILE_NOT_FOUND if the file does not exists + * - PGAGROAL_CONFIGURATION_STATUS_FILE_TOO_BIG if the file contains too many users + * (i.e., more users than the number defined in the limits) + * - PGAGROAL_CONFIGURATION_STATUS_CANNOT_DECRYPT to indicate a problem reading the content of the file + */ +int +pgagroal_vault_read_users_configuration(void* shmem, char* filename); + /** * Validate the ADMINS configuration from a file * @param shmem The shared memory segment @@ -317,12 +367,35 @@ pgagroal_write_config_value(char* buffer, char* config_key, size_t buffer_size); * pgagroal_apply_main_configuration( config, NULL, PGAGROAL_MAIN_INI_SECTION, "log_level", "info" ); */ int -pgagroal_apply_main_configuration(struct configuration* config, +pgagroal_apply_main_configuration(struct main_configuration* config, struct server* srv, char* section, char* key, char* value); +/** + * Function to apply a single configuration parameter. + * + * This is the backbone function used when parsing the main configuration file + * and is used to set any of the allowed parameters. + * + * @param config the configuration to apply values onto + * @param srv the server to which the configuration parameter refers to, if needed + * @param section the section of the file, main or server + * @param key the parameter name of the configuration + * @param value the value of the configuration + * @return 0 on success + * + * Examples of usage: + * pgagroal_apply_vault_configuration( config, NULL, PGAGROAL_VAULT_INI_SECTION, "log_level", "info" ); + */ +int +pgagroal_apply_vault_configuration(struct vault_configuration* config, + struct vault_server* srv, + char* section, + char* key, + char* value); + /** * Function to set a configuration value. * diff --git a/src/include/management.h b/src/include/management.h index 167473e4..52ff32ee 100644 --- a/src/include/management.h +++ b/src/include/management.h @@ -62,6 +62,7 @@ extern "C" { #define MANAGEMENT_CONFIG_GET 20 #define MANAGEMENT_CONFIG_SET 21 #define MANAGEMENT_CONFIG_LS 22 +#define MANAGEMENT_GET_PASSWORD 23 /** * Status for the 'ping' (i.e., is-alive) command @@ -75,6 +76,26 @@ extern "C" { #define COMMAND_OUTPUT_FORMAT_TEXT 'T' #define COMMAND_OUTPUT_FORMAT_JSON 'J' +/** + * Get the frontend password of a user + * @param ssl The SSL connection + * @param socket The socket descriptor + * @param user The frontend user + * @param password The desired password + * @return 0 upon success, otherwise 1 + */ +int +pgagroal_management_get_password(SSL* ssl, int socket, char* username, char* password); + +/** + * Write the frontend password of a user to the socket + * @param socket The socket descriptor + * @param password The frontend user + * @return 0 upon success, otherwise 1 + */ +int +pgagroal_management_write_get_password(int socket, char* password); + /** * Read the management header * @param socket The socket descriptor diff --git a/src/include/network.h b/src/include/network.h index e72ca291..dcff9927 100644 --- a/src/include/network.h +++ b/src/include/network.h @@ -42,10 +42,14 @@ extern "C" { * @param port The port number * @param fds The resulting descriptors * @param length The resulting length of descriptors + * @param non_blocking Use non blocking + * @param buffer_size Socket buffer size + * @param no_delay Use NODELAY + * @param backlog the number of backlogs * @return 0 upon success, otherwise 1 */ int -pgagroal_bind(const char* hostname, int port, int** fds, int* length); +pgagroal_bind(const char* hostname, int port, int** fds, int* length, bool no_blocking, int* buffer_size, bool no_delay, int backlog); /** * Bind a Unix Domain Socket @@ -71,10 +75,14 @@ pgagroal_remove_unix_socket(const char* directory, const char* file); * @param hostname The host name * @param port The port number * @param fd The resulting descriptor + * @param keep_alive Use keep alive + * @param non_blocking Use non blocking + * @param buffer_size Socket buffer size + * @param no_delay Use NODELAY * @return 0 upon success, otherwise 1 */ int -pgagroal_connect(const char* hostname, int port, int* fd); +pgagroal_connect(const char* hostname, int port, int* fd, bool keep_alive, bool non_blocking, int* buffer_size, bool no_delay); /** * Connect to a Unix Domain Socket @@ -130,10 +138,11 @@ pgagroal_tcp_nodelay(int fd); /** * Set the configured socket buffer size to a descriptor * @param fd The descriptor + * @param buffer_size Socket buffer size * @return 0 upon success, otherwise 1 */ int -pgagroal_socket_buffers(int fd); +pgagroal_socket_buffers(int fd, int* buffer_size); /** * Apply O_NONBLOCK to a descriptor diff --git a/src/include/pgagroal.h b/src/include/pgagroal.h index 77378565..51a72a28 100644 --- a/src/include/pgagroal.h +++ b/src/include/pgagroal.h @@ -62,22 +62,27 @@ extern "C" { #define PGAGROAL_DEFAULT_FRONTEND_USERS_FILE PGAGROAL_DEFAULT_CONFIGURATION_PATH "pgagroal_frontend_users.conf" #define PGAGROAL_DEFAULT_ADMINS_FILE PGAGROAL_DEFAULT_CONFIGURATION_PATH "pgagroal_admins.conf" #define PGAGROAL_DEFAULT_SUPERUSER_FILE PGAGROAL_DEFAULT_CONFIGURATION_PATH "pgagroal_superuser.conf" +#define PGAGROAL_DEFAULT_VAULT_CONF_FILE PGAGROAL_DEFAULT_CONFIGURATION_PATH "pgagroal_vault.conf" +#define PGAGROAL_DEFAULT_VAULT_USERS_FILE PGAGROAL_DEFAULT_CONFIGURATION_PATH "pgagroal_vault_users.conf" #define MAX_PROCESS_TITLE_LENGTH 256 #define MAX_BUFFER_SIZE 65535 #define DEFAULT_BUFFER_SIZE 65535 #define SECURITY_BUFFER_SIZE 1024 - -#define MAX_USERNAME_LENGTH 128 -#define MAX_DATABASE_LENGTH 256 -#define MAX_TYPE_LENGTH 16 -#define MAX_ADDRESS_LENGTH 64 -#define MAX_PASSWORD_LENGTH 1024 -#define MAX_APPLICATION_NAME 64 - -#define MAX_PATH 1024 -#define MISC_LENGTH 128 +#define HTTP_BUFFER_SIZE 1024 + +#define MAX_USERNAME_LENGTH 128 +#define MAX_DATABASE_LENGTH 256 +#define MAX_TYPE_LENGTH 16 +#define MAX_ADDRESS_LENGTH 64 +#define DEFAULT_PASSWORD_LENGTH 64 +#define MIN_PASSWORD_LENGTH 8 +#define MAX_PASSWORD_LENGTH 1024 +#define MAX_APPLICATION_NAME 64 + +#define MAX_PATH 1024 +#define MISC_LENGTH 128 #define NUMBER_OF_SERVERS 64 #ifdef DEBUG #define MAX_NUMBER_OF_CONNECTIONS 8 @@ -173,15 +178,15 @@ extern "C" { #define likely(x) __builtin_expect (!!(x), 1) #define unlikely(x) __builtin_expect (!!(x), 0) -#define MAX(a, b) \ - ({ __typeof__ (a) _a = (a); \ - __typeof__ (b) _b = (b); \ - _a > _b ? _a : _b; }) +#define MAX(a, b) \ +({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a > _b ? _a : _b; }) -#define MIN(a, b) \ - ({ __typeof__ (a) _a = (a); \ - __typeof__ (b) _b = (b); \ - _a < _b ? _a : _b; }) +#define MIN(a, b) \ +({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a < _b ? _a : _b; }) /* * Common piece of code to perform a sleeping. @@ -193,14 +198,14 @@ extern "C" { SLEEP(5000000L) * */ -#define SLEEP(zzz) \ - do \ - { \ - struct timespec ts_private; \ - ts_private.tv_sec = 0; \ - ts_private.tv_nsec = zzz; \ - nanosleep(&ts_private, NULL); \ - } while (0); +#define SLEEP(zzz) \ +do \ +{ \ + struct timespec ts_private; \ + ts_private.tv_sec = 0; \ + ts_private.tv_nsec = zzz; \ + nanosleep(&ts_private, NULL); \ +} while (0); /* * Commonly used block of code to sleep @@ -216,15 +221,15 @@ extern "C" { else SLEEP_AND_GOTO(100000L, retry) */ -#define SLEEP_AND_GOTO(zzz, goto_to) \ - do \ - { \ - struct timespec ts_private; \ - ts_private.tv_sec = 0; \ - ts_private.tv_nsec = zzz; \ - nanosleep(&ts_private, NULL); \ - goto goto_to; \ - } while (0); +#define SLEEP_AND_GOTO(zzz, goto_to) \ +do \ +{ \ + struct timespec ts_private; \ + ts_private.tv_sec = 0; \ + ts_private.tv_nsec = zzz; \ + nanosleep(&ts_private, NULL); \ + goto goto_to; \ +} while (0); /** * The shared memory segment @@ -326,6 +331,15 @@ struct user char password[MAX_PASSWORD_LENGTH]; /**< The password */ } __attribute__ ((aligned (64))); +/** @struct + * Defines a vault server + */ +struct vault_server +{ + struct server server; + struct user user; +} __attribute__ ((aligned (64))); + /** @struct * Defines the Prometheus connection metric */ @@ -404,11 +418,45 @@ struct prometheus } __attribute__ ((aligned (64))); /** @struct - * Defines the configuration and state of pgagroal + * Defines the common configurations between pgagroal and vault */ struct configuration { char configuration_path[MAX_PATH]; /**< The configuration path */ + char host[MISC_LENGTH]; /**< The host */ + int port; /**< The port */ + + // Logging + int log_type; /**< The logging type */ + int log_level; /**< The logging level */ + char log_path[MISC_LENGTH]; /**< The logging path */ + bool log_connections; /**< Log successful logins */ + bool log_disconnections; /**< Log disconnects */ + int log_mode; /**< The logging mode */ + unsigned int log_rotation_size; /**< bytes to force log rotation */ + unsigned int log_rotation_age; /**< minutes for log rotation */ + char log_line_prefix[MISC_LENGTH]; /**< The logging prefix */ + atomic_schar log_lock; /**< The logging lock */ + char default_log_path[MISC_LENGTH]; /**< The default logging path */ +}; + +/** @struct + * Defines the configuration of pgagroal-vault + */ +struct vault_configuration +{ + struct configuration common; /**< Common base class */ + char users_path[MAX_PATH]; /**< The configuration path */ + int number_of_users; /**< The number of users */ + struct vault_server vault_server; /**< The vault servers */ +} __attribute__ ((aligned (64))); + +/** @struct + * Defines the configuration and state of pgagroal + */ +struct main_configuration +{ + struct configuration common; /**< Common configurations */ char hba_path[MAX_PATH]; /**< The HBA path */ char limit_path[MAX_PATH]; /**< The limit path */ char users_path[MAX_PATH]; /**< The users path */ @@ -416,8 +464,6 @@ struct configuration char admins_path[MAX_PATH]; /**< The admins path */ char superuser_path[MAX_PATH]; /**< The superuser path */ - char host[MISC_LENGTH]; /**< The host */ - int port; /**< The port */ int metrics; /**< The metrics port */ unsigned int metrics_cache_max_age; /**< Number of seconds to cache the Prometheus response */ unsigned int metrics_cache_max_size; /**< Number of bytes max to cache the Prometheus response */ @@ -431,17 +477,6 @@ struct configuration bool failover; /**< Is failover enabled */ char failover_script[MISC_LENGTH]; /**< The failover script */ - int log_type; /**< The logging type */ - int log_level; /**< The logging level */ - char log_path[MISC_LENGTH]; /**< The logging path */ - bool log_connections; /**< Log successful logins */ - bool log_disconnections; /**< Log disconnects */ - int log_mode; /**< The logging mode */ - unsigned int log_rotation_size; /**< bytes to force log rotation */ - unsigned int log_rotation_age; /**< minutes for log rotation */ - char log_line_prefix[MISC_LENGTH]; /**< The logging prefix */ - atomic_schar log_lock; /**< The logging lock */ - unsigned int update_process_title; /**< Behaviour for updating the process title */ bool authquery; /**< Is authentication query enabled */ @@ -457,6 +492,8 @@ struct configuration int blocking_timeout; /**< The blocking timeout in seconds */ int idle_timeout; /**< The idle timeout in seconds */ + int rotate_frontend_password_timeout; /**< The rotation frontend password timeout in seconds */ + int rotate_frontend_password_length; /**< Length of randomised passwords */ int max_connection_age; /**< The max connection age in seconds */ int validation; /**< Validation mode */ int background_interval; /**< Background validation timer in seconds */ diff --git a/src/include/security.h b/src/include/security.h index e3c8c41c..06e8c3b2 100644 --- a/src/include/security.h +++ b/src/include/security.h @@ -138,6 +138,21 @@ pgagroal_user_known(char* user); int pgagroal_tls_valid(void); +/** + * @brief Generate a random ASCII password have size of pwd_length + * @param password the resultant password + * @param password_length length of the password + * @return 0 if success, otherwise 1 + */ +int +pgagroal_generate_password(int password_length, char** password); + +/** + * @brief Initialize RNG + * + */ +void +pgagroal_initialize_random(void); #ifdef __cplusplus } #endif diff --git a/src/include/utils.h b/src/include/utils.h index 3a2b10b5..8fb9b704 100644 --- a/src/include/utils.h +++ b/src/include/utils.h @@ -47,6 +47,25 @@ struct signal_info int slot; /**< The slot */ }; +/** @struct + * Defines the accept io structure + */ +struct accept_io +{ + struct ev_io io; + int socket; + char** argv; +}; + +/** @struct + * Defines the client structure + */ +struct client +{ + pid_t pid; + struct client* next; +}; + /** @struct * Defines pgagroal commands. * The necessary fields are marked with an ">". diff --git a/src/libpgagroal/configuration.c b/src/libpgagroal/configuration.c index 8be7b47a..dac20527 100644 --- a/src/libpgagroal/configuration.c +++ b/src/libpgagroal/configuration.c @@ -74,14 +74,14 @@ static void extract_limit(char* str, int server_max, char** database, char** use static unsigned int as_seconds(char* str, unsigned int* age, unsigned int default_age); static unsigned int as_bytes(char* str, unsigned int* bytes, unsigned int default_bytes); -static int transfer_configuration(struct configuration* config, struct configuration* reload); +static int transfer_configuration(struct main_configuration* config, struct main_configuration* reload); static void copy_server(struct server* dst, struct server* src); static void copy_hba(struct hba* dst, struct hba* src); static void copy_user(struct user* dst, struct user* src); static int restart_int(char* name, int e, int n); static int restart_bool(char* name, bool e, bool n); static int restart_string(char* name, char* e, char* n, bool skip_non_existing); -static int restart_limit(char* name, struct configuration* config, struct configuration* reload); +static int restart_limit(char* name, struct main_configuration* config, struct main_configuration* reload); static int restart_server(struct server* src, struct server* dst); static bool is_empty_string(char* s); @@ -115,9 +115,9 @@ static int to_log_type(char* where, int value); int pgagroal_init_configuration(void* shm) { - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shm; + config = (struct main_configuration*)shm; atomic_init(&config->active_connections, 0); @@ -131,9 +131,10 @@ pgagroal_init_configuration(void* shm) config->gracefully = false; config->pipeline = PIPELINE_AUTO; config->authquery = false; - config->blocking_timeout = 30; config->idle_timeout = 0; + config->rotate_frontend_password_timeout = 0; + config->rotate_frontend_password_length = MIN_PASSWORD_LENGTH; config->max_connection_age = 0; config->validation = VALIDATION_OFF; config->background_interval = 300; @@ -151,12 +152,14 @@ pgagroal_init_configuration(void* shm) config->tracker = false; config->track_prepared_statements = false; - config->log_type = PGAGROAL_LOGGING_TYPE_CONSOLE; - config->log_level = PGAGROAL_LOGGING_LEVEL_INFO; - config->log_connections = false; - config->log_disconnections = false; - config->log_mode = PGAGROAL_LOGGING_MODE_APPEND; - atomic_init(&config->log_lock, STATE_FREE); + config->common.log_type = PGAGROAL_LOGGING_TYPE_CONSOLE; + config->common.log_level = PGAGROAL_LOGGING_LEVEL_INFO; + config->common.log_connections = false; + config->common.log_disconnections = false; + config->common.log_mode = PGAGROAL_LOGGING_MODE_APPEND; + atomic_init(&config->common.log_lock, STATE_FREE); + + memcpy(config->common.default_log_path, "pgagroal.log", strlen("pgagroal.log")); config->max_connections = 100; config->allow_unknown_users = true; @@ -186,14 +189,14 @@ struct config_section * */ int -pgagroal_read_configuration(void* shm, char* filename, bool emitWarnings) +pgagroal_read_configuration(void* shm, char* filename, bool emit_warnings) { FILE* file; char section[LINE_LENGTH]; char line[LINE_LENGTH]; char* key = NULL; char* value = NULL; - struct configuration* config; + struct main_configuration* config; int idx_server = 0; struct server srv; bool has_main_section = false; @@ -215,7 +218,7 @@ pgagroal_read_configuration(void* shm, char* filename, bool emitWarnings) memset(§ion, 0, LINE_LENGTH); memset(§ions, 0, sizeof(struct config_section) * NUMBER_OF_SERVERS + 1); - config = (struct configuration*)shm; + config = (struct main_configuration*)shm; while (fgets(line, sizeof(line), file)) { @@ -280,7 +283,7 @@ pgagroal_read_configuration(void* shm, char* filename, bool emitWarnings) unknown = true; } - if (unknown && emitWarnings) + if (unknown && emit_warnings) { // we cannot use logging here... // if we have a section, the key is not known, @@ -369,21 +372,21 @@ pgagroal_validate_configuration(void* shm, bool has_unix_socket, bool has_main_s { bool tls; struct stat st; - struct configuration* config; + struct main_configuration* config; tls = false; - config = (struct configuration*)shm; + config = (struct main_configuration*)shm; if (!has_main_sockets) { - if (strlen(config->host) == 0) + if (strlen(config->common.host) == 0) { pgagroal_log_fatal("pgagroal: No host defined"); return 1; } - if (config->port <= 0) + if (config->common.port <= 0) { pgagroal_log_fatal("pgagroal: No port defined"); return 1; @@ -461,6 +464,12 @@ pgagroal_validate_configuration(void* shm, bool has_unix_socket, bool has_main_s return 1; } + if (config->rotate_frontend_password_length < MIN_PASSWORD_LENGTH || config->rotate_frontend_password_length > MAX_PASSWORD_LENGTH) + { + pgagroal_log_fatal("pgagroal: rotate_frontend_password_length should be within [8-1024] characters"); + return 1; + } + if (config->max_connections > MAX_NUMBER_OF_CONNECTIONS) { pgagroal_log_warn("pgagroal: max_connections (%d) is greater than allowed (%d)", config->max_connections, MAX_NUMBER_OF_CONNECTIONS); @@ -525,7 +534,7 @@ pgagroal_validate_configuration(void* shm, bool has_unix_socket, bool has_main_s { pgagroal_log_fatal("pgagroal: No host defined for server [%s] (%s:%d)", config->servers[i].name, - config->configuration_path, + config->common.configuration_path[0], config->servers[i].lineno); return 1; } @@ -534,7 +543,7 @@ pgagroal_validate_configuration(void* shm, bool has_unix_socket, bool has_main_s { pgagroal_log_fatal("pgagroal: No port defined for server [%s] (%s:%d)", config->servers[i].name, - config->configuration_path, + config->common.configuration_path[0], config->servers[i].lineno); return 1; } @@ -550,7 +559,7 @@ pgagroal_validate_configuration(void* shm, bool has_unix_socket, bool has_main_s pgagroal_log_fatal("pgagroal: Servers [%s] and [%s] are duplicated! (%s:%d:%d)", config->servers[i].name, config->servers[j].name, - config->configuration_path, + config->common.configuration_path[0], config->servers[i].lineno, config->servers[j].lineno); return 1; @@ -648,6 +657,11 @@ pgagroal_validate_configuration(void* shm, bool has_unix_socket, bool has_main_s pgagroal_log_warn("pgagroal: Using idle_timeout for the transaction pipeline is not recommended"); } + if (config->rotate_frontend_password_timeout > 0) + { + pgagroal_log_warn("pgagroal: Using rotate_frontend_password_timeout for the transaction pipeline is not recommended"); + } + if (config->max_connection_age > 0) { pgagroal_log_warn("pgagroal: Using max_connection_age for the transaction pipeline is not recommended"); @@ -691,6 +705,234 @@ pgagroal_validate_configuration(void* shm, bool has_unix_socket, bool has_main_s return 0; } +/** + * + */ +int +pgagroal_vault_init_configuration(void* shm) +{ + struct vault_configuration* config; + + config = (struct vault_configuration*)shm; + + config->common.port = 0; + + config->vault_server.server.port = 0; + config->vault_server.server.tls = false; + config->number_of_users = 0; + + config->common.log_type = PGAGROAL_LOGGING_TYPE_CONSOLE; + config->common.log_level = PGAGROAL_LOGGING_LEVEL_INFO; + config->common.log_connections = false; + config->common.log_disconnections = false; + config->common.log_mode = PGAGROAL_LOGGING_MODE_APPEND; + atomic_init(&config->common.log_lock, STATE_FREE); + memcpy(config->common.default_log_path, "pgagroal-vault.log", strlen("pgagroal-vault.log")); + + memset(config->vault_server.user.password, 0, MAX_PASSWORD_LENGTH); + + return 0; +} + +/** + * + */ +int +pgagroal_vault_read_configuration(void* shm, char* filename, bool emit_warnings) +{ + FILE* file; + char section[LINE_LENGTH]; + char line[LINE_LENGTH]; + char* key = NULL; + char* value = NULL; + struct vault_configuration* config; + int idx_server = 0; + struct vault_server srv; + bool has_vault_section = false; + + // the max number of sections allowed in the configuration + // file is done by the max number of servers plus the main `pgagroal` + // configuration section + struct config_section sections[1 + 1]; + int idx_sections = 0; + int lineno = 0; + int return_value = 0; + + file = fopen(filename, "r"); + + if (!file) + { + return PGAGROAL_CONFIGURATION_STATUS_FILE_NOT_FOUND; + } + + memset(§ion, 0, LINE_LENGTH); + memset(§ions, 0, sizeof(struct config_section) * 2); + config = (struct vault_configuration*)shm; + + while (fgets(line, sizeof(line), file)) + { + lineno++; + if (!is_empty_string(line) && !is_comment_line(line)) + { + if (section_line(line, section)) + { + // check we don't overflow the number of available sections + if (idx_sections >= 2) + { + warnx("Max number of sections (%d) in configuration file <%s> reached!", + 2, + filename); + return PGAGROAL_CONFIGURATION_STATUS_FILE_TOO_BIG; + } + + // initialize the section structure + memset(sections[idx_sections].name, 0, LINE_LENGTH); + memcpy(sections[idx_sections].name, section, strlen(section)); + sections[idx_sections].lineno = lineno; + sections[idx_sections].main = !strncmp(section, PGAGROAL_VAULT_INI_SECTION, LINE_LENGTH); + if (sections[idx_sections].main) + { + has_vault_section = true; + } + + idx_sections++; + + if (strcmp(section, PGAGROAL_VAULT_INI_SECTION)) + { + if (idx_server > 0 && idx_server <= 2) + { + memcpy(&(config->vault_server), &srv, sizeof(struct vault_server)); + } + else if (idx_server > 1) + { + printf("Maximum number of servers exceeded\n"); + } + + memset(&srv, 0, sizeof(struct vault_server)); + memcpy(&srv.server.name, §ion, strlen(section)); + srv.server.lineno = lineno; + idx_server++; + } + } + else + { + extract_key_value(line, &key, &value); + + if (key && value) + { + bool unknown = false; + + //printf("\nSection <%s> key <%s> = <%s>", section, key, value); + + // apply the configuration setting + if (pgagroal_apply_vault_configuration(config, &srv, section, key, value)) + { + unknown = true; + } + + if (unknown && emit_warnings) + { + // we cannot use logging here... + // if we have a section, the key is not known, + // otherwise it is outside of a section at all + if (strlen(section) > 0) + { + warnx("Unknown key <%s> with value <%s> in section [%s] (line %d of file <%s>)", + key, + value, + section, + lineno, + filename); + } + else + { + warnx("Key <%s> with value <%s> out of any section (line %d of file <%s>)", + key, + value, + lineno, + filename); + } + } + + free(key); + free(value); + key = NULL; + value = NULL; + } + } + } + } + + if (strlen(srv.server.name) > 0) + { + memcpy(&(config->vault_server), &srv, sizeof(struct vault_server)); + } + + fclose(file); + + // check there is at least one main section + if (!has_vault_section) + { + warnx("No vault configuration section [%s] found in file <%s>", + PGAGROAL_VAULT_INI_SECTION, + filename); + return PGAGROAL_CONFIGURATION_STATUS_KO; + } + + return return_value; +} + +/** + * + */ +int +pgagroal_vault_validate_configuration (void* shm) +{ + struct vault_configuration* config; + config = (struct vault_configuration*)shm; + + if (strlen(config->common.host) == 0) + { + pgagroal_log_fatal("pgagroal-vault: No host defined"); + return 1; + } + + if (config->common.port <= 0) + { + pgagroal_log_fatal("pgagroal-vault: No port defined"); + return 1; + } + + if (strlen(config->vault_server.server.host) == 0) + { + pgagroal_log_fatal("pgagroal-vault: No host defined for server [%s] (%s:%d)", + config->vault_server.server.name, + config->common.configuration_path, + config->vault_server.server.lineno); + return 1; + } + + if (config->vault_server.server.port == 0) + { + pgagroal_log_fatal("pgagroal-vault: No port defined for server [%s] (%s:%d)", + config->vault_server.server.name, + config->common.configuration_path, + config->vault_server.server.lineno); + return 1; + } + + if (strlen(config->vault_server.user.username) == 0) + { + pgagroal_log_fatal("pgagroal-vault: No user defined for server [%s] (%s:%d)", + config->vault_server.server.name, + config->common.configuration_path, + config->vault_server.server.lineno); + return 1; + } + + return 0; +} + /** * */ @@ -706,7 +948,7 @@ pgagroal_read_hba_configuration(void* shm, char* filename) char* address = NULL; char* method = NULL; int lineno = 0; - struct configuration* config; + struct main_configuration* config; file = fopen(filename, "r"); @@ -716,7 +958,7 @@ pgagroal_read_hba_configuration(void* shm, char* filename) } index = 0; - config = (struct configuration*)shm; + config = (struct main_configuration*)shm; while (fgets(line, sizeof(line), file)) { @@ -774,9 +1016,9 @@ pgagroal_read_hba_configuration(void* shm, char* filename) int pgagroal_validate_hba_configuration(void* shm) { - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shm; + config = (struct main_configuration*)shm; if (config->number_of_hbas == 0) { @@ -832,7 +1074,7 @@ pgagroal_read_limit_configuration(void* shm, char* filename) int min_size; int server_max; int lineno; - struct configuration* config; + struct main_configuration* config; file = fopen(filename, "r"); @@ -843,7 +1085,7 @@ pgagroal_read_limit_configuration(void* shm, char* filename) index = 0; lineno = 0; - config = (struct configuration*)shm; + config = (struct main_configuration*)shm; server_max = config->max_connections; @@ -923,10 +1165,10 @@ int pgagroal_validate_limit_configuration(void* shm) { int total_connections; - struct configuration* config; + struct main_configuration* config; total_connections = 0; - config = (struct configuration*)shm; + config = (struct main_configuration*)shm; for (int i = 0; i < config->number_of_limits; i++) { @@ -1022,7 +1264,7 @@ pgagroal_read_users_configuration(void* shm, char* filename) char* decoded = NULL; int decoded_length = 0; char* ptr = NULL; - struct configuration* config; + struct main_configuration* config; int status; file = fopen(filename, "r"); @@ -1040,7 +1282,7 @@ pgagroal_read_users_configuration(void* shm, char* filename) } index = 0; - config = (struct configuration*)shm; + config = (struct main_configuration*)shm; while (fgets(line, sizeof(line), file)) { @@ -1144,7 +1386,7 @@ pgagroal_read_frontend_users_configuration(void* shm, char* filename) char* decoded = NULL; int decoded_length = 0; char* ptr = NULL; - struct configuration* config; + struct main_configuration* config; int status = PGAGROAL_CONFIGURATION_STATUS_OK; file = fopen(filename, "r"); @@ -1162,7 +1404,7 @@ pgagroal_read_frontend_users_configuration(void* shm, char* filename) } index = 0; - config = (struct configuration*)shm; + config = (struct main_configuration*)shm; while (fgets(line, sizeof(line), file)) { @@ -1248,9 +1490,9 @@ pgagroal_read_frontend_users_configuration(void* shm, char* filename) int pgagroal_validate_frontend_users_configuration(void* shm) { - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shm; + config = (struct main_configuration*)shm; for (int i = 0; i < config->number_of_frontend_users; i++) { @@ -1291,7 +1533,7 @@ pgagroal_read_admins_configuration(void* shm, char* filename) char* decoded = NULL; int decoded_length = 0; char* ptr = NULL; - struct configuration* config; + struct main_configuration* config; int status = PGAGROAL_CONFIGURATION_STATUS_OK; file = fopen(filename, "r"); @@ -1309,7 +1551,7 @@ pgagroal_read_admins_configuration(void* shm, char* filename) } index = 0; - config = (struct configuration*)shm; + config = (struct main_configuration*)shm; while (fgets(line, sizeof(line), file)) { @@ -1389,15 +1631,128 @@ pgagroal_read_admins_configuration(void* shm, char* filename) return status; } +/** + * + */ +int +pgagroal_vault_read_users_configuration(void* shm, char* filename) +{ + FILE* file; + char line[LINE_LENGTH]; + int index; + char* master_key = NULL; + char* username = NULL; + char* password = NULL; + char* decoded = NULL; + int decoded_length = 0; + char* ptr = NULL; + struct vault_configuration* config; + int status = PGAGROAL_CONFIGURATION_STATUS_OK; + + file = fopen(filename, "r"); + + if (!file) + { + status = PGAGROAL_CONFIGURATION_STATUS_FILE_NOT_FOUND; + goto error; + } + + if (pgagroal_get_master_key(&master_key)) + { + status = PGAGROAL_CONFIGURATION_STATUS_KO; + goto error; + } + + index = 0; + config = (struct vault_configuration*)shm; + + while (fgets(line, sizeof(line), file)) + { + if (!is_empty_string(line) && !is_comment_line(line)) + { + ptr = strtok(line, ":"); + + username = ptr; + + ptr = strtok(NULL, ":"); + + if (ptr == NULL) + { + status = PGAGROAL_CONFIGURATION_STATUS_CANNOT_DECRYPT; + goto error; + } + + if (pgagroal_base64_decode(ptr, strlen(ptr), &decoded, &decoded_length)) + { + status = PGAGROAL_CONFIGURATION_STATUS_CANNOT_DECRYPT; + goto error; + } + + if (pgagroal_decrypt(decoded, decoded_length, master_key, &password)) + { + status = PGAGROAL_CONFIGURATION_STATUS_CANNOT_DECRYPT; + goto error; + } + + if (strlen(username) < MAX_USERNAME_LENGTH && + strlen(password) < MAX_PASSWORD_LENGTH && + !strcmp(config->vault_server.user.username, username)) + { + memcpy(&config->vault_server.user.password, password, strlen(password)); + } + else + { + printf("pgagroal: Invalid ADMIN entry\n"); + printf("%s\n", line); + } + + free(password); + free(decoded); + + password = NULL; + decoded = NULL; + + index++; + } + } + + config->number_of_users = index; + + if (config->number_of_users > NUMBER_OF_ADMINS) + { + status = PGAGROAL_CONFIGURATION_STATUS_FILE_TOO_BIG; + goto error; + } + + free(master_key); + + fclose(file); + + return PGAGROAL_CONFIGURATION_STATUS_OK; + +error: + + free(master_key); + free(password); + free(decoded); + + if (file) + { + fclose(file); + } + + return status; +} + /** * */ int pgagroal_validate_admins_configuration(void* shm) { - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shm; + config = (struct main_configuration*)shm; if (config->management > 0 && config->number_of_admins == 0) { @@ -1419,7 +1774,7 @@ pgagroal_read_superuser_configuration(void* shm, char* filename) char* decoded = NULL; int decoded_length = 0; char* ptr = NULL; - struct configuration* config; + struct main_configuration* config; int status = PGAGROAL_CONFIGURATION_STATUS_OK; file = fopen(filename, "r"); @@ -1437,7 +1792,7 @@ pgagroal_read_superuser_configuration(void* shm, char* filename) } index = 0; - config = (struct configuration*)shm; + config = (struct main_configuration*)shm; while (fgets(line, sizeof(line), file)) { @@ -1530,12 +1885,12 @@ int pgagroal_reload_configuration(void) { size_t reload_size; - struct configuration* reload = NULL; - struct configuration* config; + struct main_configuration* reload = NULL; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; - pgagroal_log_trace("Configuration: %s", config->configuration_path); + pgagroal_log_trace("Configuration: %s", config->common.configuration_path); pgagroal_log_trace("HBA: %s", config->hba_path); pgagroal_log_trace("Limit: %s", config->limit_path); pgagroal_log_trace("Users: %s", config->users_path); @@ -1543,7 +1898,7 @@ pgagroal_reload_configuration(void) pgagroal_log_trace("Admins: %s", config->admins_path); pgagroal_log_trace("Superuser: %s", config->superuser_path); - reload_size = sizeof(struct configuration); + reload_size = sizeof(struct main_configuration); if (pgagroal_create_shared_memory(reload_size, HUGEPAGE_OFF, (void**)&reload)) { @@ -1552,7 +1907,7 @@ pgagroal_reload_configuration(void) pgagroal_init_configuration((void*)reload); - if (pgagroal_read_configuration((void*)reload, config->configuration_path, true)) + if (pgagroal_read_configuration((void*)reload, config->common.configuration_path, true)) { goto error; } @@ -2193,7 +2548,7 @@ extract_value(char* str, int offset, char** value) * parameters), a positive value in the case of a dramatic error. */ static int -transfer_configuration(struct configuration* config, struct configuration* reload) +transfer_configuration(struct main_configuration* config, struct main_configuration* reload) { #ifdef HAVE_LINUX sd_notify(0, "RELOADING=1"); @@ -2201,8 +2556,8 @@ transfer_configuration(struct configuration* config, struct configuration* reloa int unchanged = 0; - memcpy(config->host, reload->host, MISC_LENGTH); - config->port = reload->port; + memcpy(config->common.host, reload->common.host, MISC_LENGTH); + config->common.port = reload->common.port; config->metrics = reload->metrics; config->metrics_cache_max_age = reload->metrics_cache_max_age; unchanged -= restart_int("metrics_cache_max_size", config->metrics_cache_max_size, reload->metrics_cache_max_size); @@ -2221,29 +2576,29 @@ transfer_configuration(struct configuration* config, struct configuration* reloa memcpy(config->failover_script, reload->failover_script, MISC_LENGTH); /* log_type */ - restart_int("log_type", config->log_type, reload->log_type); - config->log_level = reload->log_level; + restart_int("log_type", config->common.log_type, reload->common.log_type); + config->common.log_level = reload->common.log_level; /* log_path */ // if the log main parameters have changed, we need // to restart the logging system - if (strncmp(config->log_path, reload->log_path, MISC_LENGTH) - || config->log_rotation_size != reload->log_rotation_size - || config->log_rotation_age != reload->log_rotation_age - || config->log_mode != reload->log_mode) + if (strncmp(config->common.log_path, reload->common.log_path, MISC_LENGTH) + || config->common.log_rotation_size != reload->common.log_rotation_size + || config->common.log_rotation_age != reload->common.log_rotation_age + || config->common.log_mode != reload->common.log_mode) { pgagroal_log_debug("Log restart triggered!"); pgagroal_stop_logging(); - config->log_rotation_size = reload->log_rotation_size; - config->log_rotation_age = reload->log_rotation_age; - config->log_mode = reload->log_mode; - memcpy(config->log_line_prefix, reload->log_line_prefix, MISC_LENGTH); - memcpy(config->log_path, reload->log_path, MISC_LENGTH); + config->common.log_rotation_size = reload->common.log_rotation_size; + config->common.log_rotation_age = reload->common.log_rotation_age; + config->common.log_mode = reload->common.log_mode; + memcpy(config->common.log_line_prefix, reload->common.log_line_prefix, MISC_LENGTH); + memcpy(config->common.log_path, reload->common.log_path, MISC_LENGTH); pgagroal_start_logging(); } - config->log_connections = reload->log_connections; - config->log_disconnections = reload->log_disconnections; + config->common.log_connections = reload->common.log_connections; + config->common.log_disconnections = reload->common.log_disconnections; /* log_lock */ @@ -2270,6 +2625,8 @@ transfer_configuration(struct configuration* config, struct configuration* reloa config->blocking_timeout = reload->blocking_timeout; config->idle_timeout = reload->idle_timeout; + config->rotate_frontend_password_timeout = reload->rotate_frontend_password_timeout; + config->rotate_frontend_password_length = reload->rotate_frontend_password_length; config->max_connection_age = reload->max_connection_age; config->validation = reload->validation; config->background_interval = reload->background_interval; @@ -2515,7 +2872,7 @@ restart_string(char* name, char* e, char* n, bool skip_non_existing) } static int -restart_limit(char* name, struct configuration* config, struct configuration* reload) +restart_limit(char* name, struct main_configuration* config, struct main_configuration* reload) { int ret; @@ -2643,16 +3000,16 @@ as_logging_rotation_age(char* str, unsigned int* age) void pgagroal_init_pidfile_if_needed(void) { - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; if (strlen(config->pidfile) == 0) { // no pidfile set, use a default one snprintf(config->pidfile, sizeof(config->pidfile), "%s/pgagroal.%d.pid", config->unix_socket_dir, - config->port); + config->common.port); pgagroal_log_debug("PID file automatically set to: [%s]", config->pidfile); } } @@ -2660,9 +3017,9 @@ pgagroal_init_pidfile_if_needed(void) bool pgagroal_can_prefill(void) { - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; if (config->number_of_users > 0 && config->number_of_limits > 0) { @@ -2709,7 +3066,7 @@ key_in_section(char* wanted, char* section, char* key, bool global, bool* unknow // if here there is a match on the key, ensure the section is // appropriate - if (global && !strncmp(section, PGAGROAL_MAIN_INI_SECTION, MISC_LENGTH)) + if (global && (!strncmp(section, PGAGROAL_MAIN_INI_SECTION, MISC_LENGTH) | !strncmp(section, PGAGROAL_VAULT_INI_SECTION, MISC_LENGTH))) { return true; } @@ -3066,7 +3423,7 @@ as_update_process_title(char* str, unsigned int* policy, unsigned int default_po int pgagroal_write_config_value(char* buffer, char* config_key, size_t buffer_size) { - struct configuration* config; + struct main_configuration* config; char section[MISC_LENGTH]; char context[MISC_LENGTH]; @@ -3074,7 +3431,7 @@ pgagroal_write_config_value(char* buffer, char* config_key, size_t buffer_size) int begin = -1, end = -1; bool main_section; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; memset(section, 0, MISC_LENGTH); memset(context, 0, MISC_LENGTH); @@ -3149,50 +3506,50 @@ pgagroal_write_config_value(char* buffer, char* config_key, size_t buffer_size) if (!strncmp(key, "host", MISC_LENGTH)) { - return to_string(buffer, config->host, buffer_size); + return to_string(buffer, config->common.host, buffer_size); } else if (!strncmp(key, "port", MISC_LENGTH)) { - return to_int(buffer, config->port); + return to_int(buffer, config->common.port); } else if (!strncmp(key, "log_type", MISC_LENGTH)) { - return to_log_type(buffer, config->log_type); + return to_log_type(buffer, config->common.log_type); } else if (!strncmp(key, "log_mode", MISC_LENGTH)) { - return to_log_mode(buffer, config->log_mode); + return to_log_mode(buffer, config->common.log_mode); } else if (!strncmp(key, "log_line_prefix", MISC_LENGTH)) { - return to_string(buffer, config->log_line_prefix, buffer_size); + return to_string(buffer, config->common.log_line_prefix, buffer_size); } else if (!strncmp(key, "log_level", MISC_LENGTH)) { - return to_log_level(buffer, config->log_level); + return to_log_level(buffer, config->common.log_level); } else if (!strncmp(key, "log_rotation_size", MISC_LENGTH)) { - return to_int(buffer, config->log_rotation_size); + return to_int(buffer, config->common.log_rotation_size); } else if (!strncmp(key, "log_rotation_age", MISC_LENGTH)) { - return to_int(buffer, config->log_rotation_age); + return to_int(buffer, config->common.log_rotation_age); } else if (!strncmp(key, "log_connections", MISC_LENGTH)) { - return to_bool(buffer, config->log_connections); + return to_bool(buffer, config->common.log_connections); } else if (!strncmp(key, "log_disconnections", MISC_LENGTH)) { - return to_bool(buffer, config->log_disconnections); + return to_bool(buffer, config->common.log_disconnections); } else if (!strncmp(key, "log_path", MISC_LENGTH)) { - return to_string(buffer, config->log_path, buffer_size); + return to_string(buffer, config->common.log_path, buffer_size); } else if (!strncmp(key, "metrics", MISC_LENGTH)) { @@ -3246,6 +3603,14 @@ pgagroal_write_config_value(char* buffer, char* config_key, size_t buffer_size) { return to_int(buffer, config->idle_timeout); } + else if (!strncmp(key, "rotate_frontend_password_timeout", MISC_LENGTH)) + { + return to_int(buffer, config->rotate_frontend_password_timeout); + } + else if (!strncmp(key, "rotate_frontend_password_length", MISC_LENGTH)) + { + return to_int(buffer, config->rotate_frontend_password_length); + } else if (!strncmp(key, "max_connection_age", MISC_LENGTH)) { return to_int(buffer, config->max_connection_age); @@ -3348,10 +3713,10 @@ static int pgagroal_write_server_config_value(char* buffer, char* server_name, char* config_key, size_t buffer_size) { int server_index = -1; - struct configuration* config; + struct main_configuration* config; int state; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; for (int i = 0; i < NUMBER_OF_SERVERS; i++) { @@ -3436,9 +3801,9 @@ static int pgagroal_write_hba_config_value(char* buffer, char* username, char* config_key, size_t buffer_size) { int hba_index = -1; - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; for (int i = 0; i < NUMBER_OF_HBAS; i++) { @@ -3500,9 +3865,9 @@ static int pgagroal_write_limit_config_value(char* buffer, char* database, char* config_key, size_t buffer_size) { int limit_index = -1; - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; for (int i = 0; i < NUMBER_OF_LIMITS; i++) { @@ -3792,7 +4157,7 @@ to_pipeline(char* where, int value) * into one of its possible string descriptions. * * @param where the buffer used to store the stringy thing - * @param value the config->log_level setting + * @param value the config->common.log_level setting * @return 0 on success, 1 otherwise */ static int @@ -3835,7 +4200,7 @@ to_log_level(char* where, int value) * into one of its possible string descriptions. * * @param where the buffer used to store the stringy thing - * @param value the config->log_mode setting + * @param value the config->common.log_mode setting * @return 0 on success, 1 otherwise */ static int @@ -3865,7 +4230,7 @@ to_log_mode(char* where, int value) * into one of its possible string descriptions. * * @param where the buffer used to store the stringy thing - * @param value the config->log_type setting + * @param value the config->common.log_type setting * @return 0 on success, 1 otherwise */ static int @@ -3894,7 +4259,7 @@ to_log_type(char* where, int value) } int -pgagroal_apply_main_configuration(struct configuration* config, +pgagroal_apply_main_configuration(struct main_configuration* config, struct server* srv, char* section, char* key, @@ -3912,7 +4277,7 @@ pgagroal_apply_main_configuration(struct configuration* config, { max = MISC_LENGTH - 1; } - memcpy(config->host, value, max); + memcpy(config->common.host, value, max); } else if (key_in_section("host", section, key, false, &unknown)) { @@ -3932,7 +4297,7 @@ pgagroal_apply_main_configuration(struct configuration* config, } else if (key_in_section("port", section, key, true, NULL)) { - if (as_int(value, &config->port)) + if (as_int(value, &config->common.port)) { unknown = true; } @@ -4101,6 +4466,20 @@ pgagroal_apply_main_configuration(struct configuration* config, unknown = true; } } + else if (key_in_section("rotate_frontend_password_timeout", section, key, true, &unknown)) + { + if (as_int(value, &config->rotate_frontend_password_timeout)) + { + unknown = true; + } + } + else if (key_in_section("rotate_frontend_password_length", section, key, true, &unknown)) + { + if (as_int(value, &config->rotate_frontend_password_length)) + { + unknown = true; + } + } else if (key_in_section("max_connection_age", section, key, true, &unknown)) { if (as_int(value, &config->max_connection_age)) @@ -4165,11 +4544,11 @@ pgagroal_apply_main_configuration(struct configuration* config, } else if (key_in_section("log_type", section, key, true, &unknown)) { - config->log_type = as_logging_type(value); + config->common.log_type = as_logging_type(value); } else if (key_in_section("log_level", section, key, true, &unknown)) { - config->log_level = as_logging_level(value); + config->common.log_level = as_logging_level(value); } else if (key_in_section("log_path", section, key, true, &unknown)) { @@ -4178,18 +4557,18 @@ pgagroal_apply_main_configuration(struct configuration* config, { max = MISC_LENGTH - 1; } - memcpy(config->log_path, value, max); + memcpy(config->common.log_path, value, max); } else if (key_in_section("log_rotation_size", section, key, true, &unknown)) { - if (as_logging_rotation_size(value, &config->log_rotation_size)) + if (as_logging_rotation_size(value, &config->common.log_rotation_size)) { unknown = true; } } else if (key_in_section("log_rotation_age", section, key, true, &unknown)) { - if (as_logging_rotation_age(value, &config->log_rotation_age)) + if (as_logging_rotation_age(value, &config->common.log_rotation_age)) { unknown = true; } @@ -4202,26 +4581,26 @@ pgagroal_apply_main_configuration(struct configuration* config, max = MISC_LENGTH - 1; } - memcpy(config->log_line_prefix, value, max); + memcpy(config->common.log_line_prefix, value, max); } else if (key_in_section("log_connections", section, key, true, &unknown)) { - if (as_bool(value, &config->log_connections)) + if (as_bool(value, &config->common.log_connections)) { unknown = true; } } else if (key_in_section("log_disconnections", section, key, true, &unknown)) { - if (as_bool(value, &config->log_disconnections)) + if (as_bool(value, &config->common.log_disconnections)) { unknown = true; } } else if (key_in_section("log_mode", section, key, true, &unknown)) { - config->log_mode = as_logging_mode(value); + config->common.log_mode = as_logging_mode(value); } else if (key_in_section("max_connections", section, key, true, &unknown)) { @@ -4328,11 +4707,168 @@ pgagroal_apply_main_configuration(struct configuration* config, } } +int +pgagroal_apply_vault_configuration(struct vault_configuration* config, + struct vault_server* srv, + char* section, + char* key, + char* value) +{ + size_t max = 0; + bool unknown = false; + + // pgagroal_log_trace( "Configuration setting [%s] <%s> -> <%s>", section, key, value ); + + if (key_in_section("host", section, key, true, NULL)) + { + max = strlen(value); + if (max > MISC_LENGTH - 1) + { + max = MISC_LENGTH - 1; + } + memcpy(config->common.host, value, max); + } + else if (key_in_section("host", section, key, false, &unknown)) + { + max = strlen(section); + if (max > MISC_LENGTH - 1) + { + max = MISC_LENGTH - 1; + } + memcpy(&srv->server.name, section, max); + max = strlen(value); + if (max > MISC_LENGTH - 1) + { + max = MISC_LENGTH - 1; + } + memcpy(&srv->server.host, value, max); + } + else if (key_in_section("port", section, key, true, NULL)) + { + if (as_int(value, &config->common.port)) + { + unknown = true; + } + } + else if (key_in_section("port", section, key, false, &unknown)) + { + memcpy(&srv->server.name, section, strlen(section)); + if (as_int(value, &srv->server.port)) + { + unknown = true; + } + } + else if (key_in_section("user", section, key, false, &unknown)) + { + max = strlen(value); + if (max > MISC_LENGTH - 1) + { + max = MISC_LENGTH - 1; + } + memcpy(&srv->user.username, value, max); + } + else if (key_in_section("tls", section, key, false, &unknown)) + { + if (as_bool(value, &srv->server.tls)) + { + unknown = true; + } + } + else if (key_in_section("tls_ca_file", section, key, false, &unknown)) + { + max = strlen(value); + if (max > MISC_LENGTH - 1) + { + max = MISC_LENGTH - 1; + } + memcpy(&srv->server.tls_ca_file, value, max); + } + else if (key_in_section("tls_cert_file", section, key, false, &unknown)) + { + max = strlen(value); + if (max > MISC_LENGTH - 1) + { + max = MISC_LENGTH - 1; + } + memcpy(&srv->server.tls_cert_file, value, max); + } + else if (key_in_section("tls_key_file", section, key, false, &unknown)) + { + max = strlen(value); + if (max > MISC_LENGTH - 1) + { + max = MISC_LENGTH - 1; + } + memcpy(&srv->server.tls_key_file, value, max); + } + else if (key_in_section("log_type", section, key, true, &unknown)) + { + config->common.log_type = as_logging_type(value); + } + else if (key_in_section("log_level", section, key, true, &unknown)) + { + config->common.log_level = as_logging_level(value); + } + else if (key_in_section("log_path", section, key, true, &unknown)) + { + max = strlen(value); + if (max > MISC_LENGTH - 1) + { + max = MISC_LENGTH - 1; + } + memcpy(config->common.log_path, value, max); + } + else if (key_in_section("log_rotation_size", section, key, true, &unknown)) + { + if (as_logging_rotation_size(value, &config->common.log_rotation_size)) + { + unknown = true; + } + } + else if (key_in_section("log_rotation_age", section, key, true, &unknown)) + { + if (as_logging_rotation_age(value, &config->common.log_rotation_age)) + { + unknown = true; + } + } + else if (key_in_section("log_line_prefix", section, key, true, &unknown)) + { + max = strlen(value); + if (max > MISC_LENGTH - 1) + { + max = MISC_LENGTH - 1; + } + + memcpy(config->common.log_line_prefix, value, max); + } + else if (key_in_section("log_connections", section, key, true, &unknown)) + { + + if (as_bool(value, &config->common.log_connections)) + { + unknown = true; + } + } + else if (key_in_section("log_disconnections", section, key, true, &unknown)) + { + if (as_bool(value, &config->common.log_disconnections)) + { + unknown = true; + } + } + else if (key_in_section("log_mode", section, key, true, &unknown)) + { + config->common.log_mode = as_logging_mode(value); + } + return 0; +} + int pgagroal_apply_configuration(char* config_key, char* config_value) { - struct configuration* config; - struct configuration* current_config; + struct main_configuration* config; + struct main_configuration* current_config; char section[MISC_LENGTH]; char context[MISC_LENGTH]; @@ -4344,9 +4880,9 @@ pgagroal_apply_configuration(char* config_key, char* config_value) struct server* srv_src; // get the currently running configuration - current_config = (struct configuration*)shmem; + current_config = (struct main_configuration*)shmem; // create a new configuration that will be the clone of the previous one - config_size = sizeof(struct configuration); + config_size = sizeof(struct main_configuration); if (pgagroal_create_shared_memory(config_size, HUGEPAGE_OFF, (void**)&config)) { goto error; @@ -4537,7 +5073,7 @@ pgagroal_apply_configuration(char* config_key, char* config_value) if (config != NULL) { - memcpy(config, current_config, sizeof(struct configuration)); + memcpy(config, current_config, sizeof(struct main_configuration)); pgagroal_destroy_shared_memory((void*)config, config_size); } diff --git a/src/libpgagroal/logging.c b/src/libpgagroal/logging.c index a1c6301f..2395e43a 100644 --- a/src/libpgagroal/logging.c +++ b/src/libpgagroal/logging.c @@ -174,7 +174,7 @@ pgagroal_init_logging(void) if (!log_file) { - printf("Failed to open log file %s due to %s\n", strlen(config->log_path) > 0 ? config->log_path : "pgagroal.log", strerror(errno)); + printf("Failed to open log file %s due to %s\n", strlen(config->log_path) > 0 ? config->log_path : config->default_log_path, strerror(errno)); errno = 0; log_rotation_disable(); return 1; @@ -200,7 +200,7 @@ pgagroal_start_logging(void) if (!log_file) { - printf("Failed to open log file %s due to %s\n", strlen(config->log_path) > 0 ? config->log_path : "pgagroal.log", strerror(errno)); + printf("Failed to open log file %s due to %s\n", strlen(config->log_path) > 0 ? config->log_path : config->default_log_path, strerror(errno)); errno = 0; return 1; } @@ -241,7 +241,7 @@ log_file_open(void) if (strftime(current_log_path, sizeof(current_log_path), config->log_path, tm) <= 0) { // cannot parse the format string, fallback to default logging - memcpy(current_log_path, "pgagroal.log", strlen("pgagroal.log")); + memcpy(current_log_path, config->default_log_path, strlen(config->default_log_path)); log_rotation_disable(); } diff --git a/src/libpgagroal/management.c b/src/libpgagroal/management.c index 30af7d54..a02765fd 100644 --- a/src/libpgagroal/management.c +++ b/src/libpgagroal/management.c @@ -186,6 +186,7 @@ pgagroal_management_read_payload(int socket, signed char id, int* payload_i, cha case MANAGEMENT_ENABLEDB: case MANAGEMENT_DISABLEDB: case MANAGEMENT_CONFIG_GET: + case MANAGEMENT_GET_PASSWORD: case MANAGEMENT_CONFIG_SET: if (read_complete(NULL, socket, &buf4[0], sizeof(buf4))) @@ -249,13 +250,13 @@ int pgagroal_management_transfer_connection(int32_t slot) { int fd; - struct configuration* config; + struct main_configuration* config; struct cmsghdr* cmptr = NULL; struct iovec iov[1]; struct msghdr msg; char buf2[2]; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; if (pgagroal_connect_unix_socket(config->unix_socket_dir, MAIN_UDS, &fd)) { @@ -321,9 +322,9 @@ int pgagroal_management_return_connection(int32_t slot) { int fd; - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; if (pgagroal_connect_unix_socket(config->unix_socket_dir, MAIN_UDS, &fd)) { @@ -354,9 +355,9 @@ pgagroal_management_kill_connection(int32_t slot, int socket) { int fd; char buf[4]; - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; if (pgagroal_connect_unix_socket(config->unix_socket_dir, MAIN_UDS, &fd)) { @@ -466,6 +467,68 @@ pgagroal_management_enabledb(SSL* ssl, int fd, char* database) return 1; } +int +pgagroal_management_get_password(SSL* ssl, int fd, char* username, char* pass) +{ + char buf[4]; + int* password_length = NULL; + char password[MAX_PASSWORD_LENGTH]; + + password_length = (int*)malloc(sizeof(int)); + if (!password_length) + { + goto error; + } + + if (write_header(ssl, fd, MANAGEMENT_GET_PASSWORD, -1)) + { + pgagroal_log_warn("pgagroal_management_get_password: write-header: %d", fd); + errno = 0; + goto error; + } + + pgagroal_write_int32(&buf, strlen(username)); + if (write_complete(ssl, fd, &buf, sizeof(buf))) + { + pgagroal_log_warn("pgagroal_management_get_password: write: %d %s", fd, strerror(errno)); + errno = 0; + goto error; + } + + if (write_complete(ssl, fd, username, strlen(username))) + { + pgagroal_log_warn("pgagroal_management_get_password: write: %d %s", fd, strerror(errno)); + errno = 0; + goto error; + } + + // Read the Password length + if (read_complete(ssl, fd, &buf, sizeof(buf))) + { + pgagroal_log_warn("pgagroal_management_get_password: read: %d %s", fd, strerror(errno)); + errno = 0; + goto error; + } + *password_length = pgagroal_read_int32(&buf); + + // Read the Password + memset(password, 0, sizeof(password)); + if (read_complete(ssl, fd, password, *password_length)) + { + pgagroal_log_warn("pgagroal_management_get_password: read: %d %s", fd, strerror(errno)); + errno = 0; + goto error; + } + + memcpy(pass, password, *password_length); + + return 0; + +error: + + return 1; +} + int pgagroal_management_disabledb(SSL* ssl, int fd, char* database) { @@ -839,13 +902,13 @@ pgagroal_management_write_status(int socket, bool graceful) char buf[16]; int active; int total; - struct configuration* config; + struct main_configuration* config; memset(&buf, 0, sizeof(buf)); active = 0; total = 0; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; if (!graceful) { @@ -952,9 +1015,9 @@ int pgagroal_management_write_details(int socket) { char header[12 + MAX_NUMBER_OF_CONNECTIONS]; - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; memset(&header, 0, sizeof(header)); @@ -1140,6 +1203,29 @@ pgagroal_management_write_isalive(int socket, bool gracefully) return 1; } +int +pgagroal_management_write_get_password(int socket, char* password) +{ + char buffer[MAX_PASSWORD_LENGTH + 4]; // first 4 bytes contains the length of the password + memset(buffer, 0, sizeof(buffer)); + + pgagroal_write_int32(&buffer, strlen(password)); + memcpy(buffer + 4, password, strlen(password)); + + if (write_complete(NULL, socket, buffer, strlen(password) + 4)) + { + pgagroal_log_warn("pgagroal_management_write_get_password: write: %d %s\n", socket, strerror(errno)); + errno = 0; + goto error; + } + + return 0; + +error: + + return 1; +} + int pgagroal_management_reset(SSL* ssl, int fd) { @@ -1191,9 +1277,9 @@ pgagroal_management_client_done(pid_t pid) { char buf[4]; int fd; - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; if (pgagroal_connect_unix_socket(config->unix_socket_dir, MAIN_UDS, &fd)) { @@ -1234,13 +1320,13 @@ pgagroal_management_client_fd(int32_t slot, pid_t pid) { char p[MISC_LENGTH]; int fd; - struct configuration* config; + struct main_configuration* config; struct cmsghdr* cmptr = NULL; struct iovec iov[1]; struct msghdr msg; char buf[2]; /* send_fd()/recv_fd() 2-byte protocol */ - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; memset(&p, 0, sizeof(p)); snprintf(&p[0], sizeof(p), ".s.%d", pid); @@ -1353,9 +1439,9 @@ pgagroal_management_remove_fd(int32_t slot, int socket, pid_t pid) char p[MISC_LENGTH]; int fd; char buf[4]; - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; if (atomic_load(&config->states[slot]) == STATE_NOTINIT) { @@ -2013,11 +2099,11 @@ pgagroal_management_read_conf_ls(SSL* ssl, int socket, char output_format) int pgagroal_management_write_conf_ls(int socket) { - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; - if (pgagroal_management_write_conf_ls_detail(socket, config->configuration_path)) + if (pgagroal_management_write_conf_ls_detail(socket, config->common.configuration_path)) { goto error; } diff --git a/src/libpgagroal/memory.c b/src/libpgagroal/memory.c index 5efecbde..860bac46 100644 --- a/src/libpgagroal/memory.c +++ b/src/libpgagroal/memory.c @@ -52,13 +52,13 @@ static void* data = NULL; void pgagroal_memory_init(void) { - struct configuration* config; + struct main_configuration* config; #ifdef DEBUG assert(shmem != NULL); #endif - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; pgagroal_memory_size(config->buffer_size); } diff --git a/src/libpgagroal/network.c b/src/libpgagroal/network.c index 42125a36..b37ffee9 100644 --- a/src/libpgagroal/network.c +++ b/src/libpgagroal/network.c @@ -47,17 +47,18 @@ #include #include #include +#include #include #include #include -static int bind_host(const char* hostname, int port, int** fds, int* length); +static int bind_host(const char* hostname, int port, int** fds, int* length, bool non_blocking, int* buffer_size, bool no_delay, int backlog); /** * */ int -pgagroal_bind(const char* hostname, int port, int** fds, int* length) +pgagroal_bind(const char* hostname, int port, int** fds, int* length, bool non_blocking, int* buffer_size, bool no_delay, int backlog) { struct ifaddrs* ifaddr, * ifa; struct sockaddr_in* sa4; @@ -97,7 +98,7 @@ pgagroal_bind(const char* hostname, int port, int** fds, int* length) inet_ntop(AF_INET6, &sa6->sin6_addr, addr, sizeof(addr)); } - if (bind_host(addr, port, &new_fds, &new_length)) + if (bind_host(addr, port, &new_fds, &new_length, non_blocking, buffer_size, no_delay, backlog)) { free(new_fds); continue; @@ -127,7 +128,7 @@ pgagroal_bind(const char* hostname, int port, int** fds, int* length) return 0; } - return bind_host(hostname, port, fds, length); + return bind_host(hostname, port, fds, length, non_blocking, buffer_size, no_delay, backlog); } /** @@ -140,9 +141,9 @@ pgagroal_bind_unix_socket(const char* directory, const char* file, int* fd) char buf[107]; struct stat st = {0}; struct sockaddr_un addr; - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; if ((*fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { @@ -220,7 +221,7 @@ pgagroal_remove_unix_socket(const char* directory, const char* file) * */ int -pgagroal_connect(const char* hostname, int port, int* fd) +pgagroal_connect(const char* hostname, int port, int* fd, bool keep_alive, bool non_blocking, int* buffer_size, bool no_delay) { struct addrinfo hints = {0}; struct addrinfo* servinfo = NULL; @@ -230,9 +231,6 @@ pgagroal_connect(const char* hostname, int port, int* fd) int rv; char sport[5]; int error = 0; - struct configuration* config; - - config = (struct configuration*)shmem; memset(&sport, 0, sizeof(sport)); sprintf(&sport[0], "%d", port); @@ -265,7 +263,7 @@ pgagroal_connect(const char* hostname, int port, int* fd) if (*fd != -1) { - if (config != NULL && config->keep_alive) + if (keep_alive) { if (setsockopt(*fd, SOL_SOCKET, SO_KEEPALIVE, &yes, optlen) == -1) { @@ -277,7 +275,7 @@ pgagroal_connect(const char* hostname, int port, int* fd) } } - if (config != NULL && config->nodelay) + if (no_delay) { if (setsockopt(*fd, IPPROTO_TCP, TCP_NODELAY, &yes, optlen) == -1) { @@ -289,25 +287,22 @@ pgagroal_connect(const char* hostname, int port, int* fd) } } - if (config != NULL) + if (setsockopt(*fd, SOL_SOCKET, SO_RCVBUF, buffer_size, optlen) == -1) { - if (setsockopt(*fd, SOL_SOCKET, SO_RCVBUF, &config->buffer_size, optlen) == -1) - { - error = errno; - pgagroal_disconnect(*fd); - errno = 0; - *fd = -1; - continue; - } + error = errno; + pgagroal_disconnect(*fd); + errno = 0; + *fd = -1; + continue; + } - if (setsockopt(*fd, SOL_SOCKET, SO_SNDBUF, &config->buffer_size, optlen) == -1) - { - error = errno; - pgagroal_disconnect(*fd); - errno = 0; - *fd = -1; - continue; - } + if (setsockopt(*fd, SOL_SOCKET, SO_SNDBUF, buffer_size, optlen) == -1) + { + error = errno; + pgagroal_disconnect(*fd); + errno = 0; + *fd = -1; + continue; } if (connect(*fd, p->ai_addr, p->ai_addrlen) == -1) @@ -329,7 +324,7 @@ pgagroal_connect(const char* hostname, int port, int* fd) freeaddrinfo(servinfo); /* Set O_NONBLOCK on the socket */ - if (config != NULL && config->non_blocking) + if (non_blocking) { pgagroal_socket_nonblocking(*fd, true); } @@ -506,41 +501,32 @@ pgagroal_socket_has_error(int fd) int pgagroal_tcp_nodelay(int fd) { - struct configuration* config; int yes = 1; socklen_t optlen = sizeof(int); - config = (struct configuration*)shmem; - - if (config->nodelay) + if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, optlen) == -1) { - if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, optlen) == -1) - { - pgagroal_log_warn("tcp_nodelay: %d %s", fd, strerror(errno)); - errno = 0; - return 1; - } + pgagroal_log_warn("tcp_nodelay: %d %s", fd, strerror(errno)); + errno = 0; + return 1; } return 0; } int -pgagroal_socket_buffers(int fd) +pgagroal_socket_buffers(int fd, int* buffer_size) { - struct configuration* config; socklen_t optlen = sizeof(int); - config = (struct configuration*)shmem; - - if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &config->buffer_size, optlen) == -1) + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, buffer_size, optlen) == -1) { pgagroal_log_warn("socket_buffers: SO_RCVBUF %d %s", fd, strerror(errno)); errno = 0; return 1; } - if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &config->buffer_size, optlen) == -1) + if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, buffer_size, optlen) == -1) { pgagroal_log_warn("socket_buffers: SO_SNDBUF %d %s", fd, strerror(errno)); errno = 0; @@ -554,7 +540,7 @@ pgagroal_socket_buffers(int fd) * */ static int -bind_host(const char* hostname, int port, int** fds, int* length) +bind_host(const char* hostname, int port, int** fds, int* length, bool non_blocking, int* buffer_size, bool no_delay, int backlog) { int* result = NULL; int index, size; @@ -563,9 +549,6 @@ bind_host(const char* hostname, int port, int** fds, int* length) int yes = 1; int rv; char* sport; - struct configuration* config; - - config = (struct configuration*)shmem; index = 0; size = 0; @@ -621,7 +604,7 @@ bind_host(const char* hostname, int port, int** fds, int* length) continue; } - if (config->non_blocking) + if (non_blocking) { if (pgagroal_socket_nonblocking(sockfd, true)) { @@ -630,16 +613,19 @@ bind_host(const char* hostname, int port, int** fds, int* length) } } - if (pgagroal_socket_buffers(sockfd)) + if (pgagroal_socket_buffers(sockfd, buffer_size)) { pgagroal_disconnect(sockfd); continue; } - if (pgagroal_tcp_nodelay(sockfd)) + if (no_delay) { - pgagroal_disconnect(sockfd); - continue; + if (pgagroal_tcp_nodelay(sockfd)) + { + pgagroal_disconnect(sockfd); + continue; + } } if (bind(sockfd, addr->ai_addr, addr->ai_addrlen) == -1) @@ -649,7 +635,7 @@ bind_host(const char* hostname, int port, int** fds, int* length) continue; } - if (listen(sockfd, config->backlog) == -1) + if (listen(sockfd, backlog) == -1) { pgagroal_disconnect(sockfd); pgagroal_log_debug("server: listen: %s:%d (%s)", hostname, port, strerror(errno)); diff --git a/src/libpgagroal/pipeline_perf.c b/src/libpgagroal/pipeline_perf.c index c12c8701..c0f911cf 100644 --- a/src/libpgagroal/pipeline_perf.c +++ b/src/libpgagroal/pipeline_perf.c @@ -79,9 +79,9 @@ performance_initialize(void* shmem, void** pipeline_shmem, size_t* pipeline_shme static void performance_start(struct ev_loop* loop, struct worker_io* w) { - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; for (int i = 0; i < config->max_connections; i++) { @@ -115,7 +115,7 @@ performance_client(struct ev_loop* loop, struct ev_io* watcher, int revents) int status = MESSAGE_STATUS_ERROR; struct worker_io* wi = NULL; struct message* msg = NULL; - struct configuration* config = NULL; + struct main_configuration* config = NULL; wi = (struct worker_io*)watcher; @@ -156,7 +156,7 @@ performance_client(struct ev_loop* loop, struct ev_io* watcher, int revents) return; client_done: - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; pgagroal_log_debug("[C] Client done (slot %d database %s user %s): %s (socket %d status %d)", wi->slot, config->connections[wi->slot].database, config->connections[wi->slot].username, strerror(errno), wi->client_fd, status); @@ -176,7 +176,7 @@ performance_client(struct ev_loop* loop, struct ev_io* watcher, int revents) return; client_error: - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; pgagroal_log_warn("[C] Client error (slot %d database %s user %s): %s (socket %d status %d)", wi->slot, config->connections[wi->slot].database, config->connections[wi->slot].username, strerror(errno), wi->client_fd, status); @@ -189,7 +189,7 @@ performance_client(struct ev_loop* loop, struct ev_io* watcher, int revents) return; server_error: - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; pgagroal_log_warn("[C] Server error (slot %d database %s user %s): %s (socket %d status %d)", wi->slot, config->connections[wi->slot].database, config->connections[wi->slot].username, strerror(errno), wi->server_fd, status); @@ -209,7 +209,7 @@ performance_server(struct ev_loop* loop, struct ev_io* watcher, int revents) bool fatal = false; struct worker_io* wi = NULL; struct message* msg = NULL; - struct configuration* config = NULL; + struct main_configuration* config = NULL; wi = (struct worker_io*)watcher; @@ -258,7 +258,7 @@ performance_server(struct ev_loop* loop, struct ev_io* watcher, int revents) return; client_error: - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; pgagroal_log_warn("[S] Client error (slot %d database %s user %s): %s (socket %d status %d)", wi->slot, config->connections[wi->slot].database, config->connections[wi->slot].username, strerror(errno), wi->client_fd, status); @@ -271,7 +271,7 @@ performance_server(struct ev_loop* loop, struct ev_io* watcher, int revents) return; server_done: - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; pgagroal_log_debug("[S] Server done (slot %d database %s user %s): %s (socket %d status %d)", wi->slot, config->connections[wi->slot].database, config->connections[wi->slot].username, strerror(errno), wi->server_fd, status); @@ -282,7 +282,7 @@ performance_server(struct ev_loop* loop, struct ev_io* watcher, int revents) return; server_error: - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; pgagroal_log_warn("[S] Server error (slot %d database %s user %s): %s (socket %d status %d)", wi->slot, config->connections[wi->slot].database, config->connections[wi->slot].username, strerror(errno), wi->server_fd, status); diff --git a/src/libpgagroal/pipeline_session.c b/src/libpgagroal/pipeline_session.c index 562aea8a..b4289229 100644 --- a/src/libpgagroal/pipeline_session.c +++ b/src/libpgagroal/pipeline_session.c @@ -98,9 +98,9 @@ session_initialize(void* shmem, void** pipeline_shmem, size_t* pipeline_shmem_si void* session_shmem = NULL; size_t session_shmem_size; struct client_session* client; - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; *pipeline_shmem = NULL; *pipeline_shmem_size = 0; @@ -133,9 +133,9 @@ static void session_start(struct ev_loop* loop, struct worker_io* w) { struct client_session* client; - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; in_tx = false; next_client_message = 0; @@ -195,9 +195,9 @@ session_periodic(void) int socket; struct message* cancel_msg = NULL; struct client_session* client; - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; if (config->disconnect_client > 0 && pipeline_shmem != NULL) { @@ -244,7 +244,7 @@ session_periodic(void) } else { - ret = pgagroal_connect(config->servers[server].host, config->servers[server].port, &socket); + ret = pgagroal_connect(config->servers[server].host, config->servers[server].port, &socket, config->keep_alive, config->non_blocking, &config->buffer_size, config->nodelay); } if (ret == 0) @@ -286,10 +286,10 @@ session_client(struct ev_loop* loop, struct ev_io* watcher, int revents) int status = MESSAGE_STATUS_ERROR; struct worker_io* wi = NULL; struct message* msg = NULL; - struct configuration* config = NULL; + struct main_configuration* config = NULL; wi = (struct worker_io*)watcher; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; client_active(wi->slot); @@ -452,7 +452,7 @@ session_server(struct ev_loop* loop, struct ev_io* watcher, int revents) bool fatal = false; struct worker_io* wi = NULL; struct message* msg = NULL; - struct configuration* config = NULL; + struct main_configuration* config = NULL; wi = (struct worker_io*)watcher; @@ -554,7 +554,7 @@ session_server(struct ev_loop* loop, struct ev_io* watcher, int revents) return; client_error: - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; pgagroal_log_warn("[S] Client error (slot %d database %s user %s): %s (socket %d status %d)", wi->slot, config->connections[wi->slot].database, config->connections[wi->slot].username, strerror(errno), wi->client_fd, status); @@ -569,7 +569,7 @@ session_server(struct ev_loop* loop, struct ev_io* watcher, int revents) return; server_done: - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; pgagroal_log_debug("[S] Server done (slot %d database %s user %s): %s (socket %d status %d)", wi->slot, config->connections[wi->slot].database, config->connections[wi->slot].username, strerror(errno), wi->server_fd, status); @@ -582,7 +582,7 @@ session_server(struct ev_loop* loop, struct ev_io* watcher, int revents) return; server_error: - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; pgagroal_log_warn("[S] Server error (slot %d database %s user %s): %s (socket %d status %d)", wi->slot, config->connections[wi->slot].database, config->connections[wi->slot].username, strerror(errno), wi->server_fd, status); diff --git a/src/libpgagroal/pipeline_transaction.c b/src/libpgagroal/pipeline_transaction.c index 20de6211..61cbcdcd 100644 --- a/src/libpgagroal/pipeline_transaction.c +++ b/src/libpgagroal/pipeline_transaction.c @@ -104,9 +104,9 @@ transaction_start(struct ev_loop* loop, struct worker_io* w) { char p[MISC_LENGTH]; bool is_new; - struct configuration* config = NULL; + struct main_configuration* config = NULL; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; slot = -1; memcpy(&username[0], config->connections[w->slot].username, MAX_USERNAME_LENGTH); @@ -162,9 +162,9 @@ transaction_stop(struct ev_loop* loop, struct worker_io* w) { if (slot != -1) { - struct configuration* config = NULL; + struct main_configuration* config = NULL; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; /* We are either in 'X' or the client terminated (consider cancel query) */ if (in_tx) @@ -199,10 +199,10 @@ transaction_client(struct ev_loop* loop, struct ev_io* watcher, int revents) SSL* s_ssl = NULL; struct worker_io* wi = NULL; struct message* msg = NULL; - struct configuration* config = NULL; + struct main_configuration* config = NULL; wi = (struct worker_io*)watcher; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; /* We can't use the information from wi except from client_fd/client_ssl */ if (slot == -1) @@ -402,10 +402,10 @@ transaction_server(struct ev_loop* loop, struct ev_io* watcher, int revents) bool has_z = false; struct worker_io* wi = NULL; struct message* msg = NULL; - struct configuration* config = NULL; + struct main_configuration* config = NULL; wi = (struct worker_io*)watcher; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; /* We can't use the information from wi except from client_fd/client_ssl */ wi->server_fd = config->connections[slot].fd; @@ -591,9 +591,9 @@ static void shutdown_mgt(struct ev_loop* loop) { char p[MISC_LENGTH]; - struct configuration* config = NULL; + struct main_configuration* config = NULL; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; memset(&p, 0, sizeof(p)); snprintf(&p[0], sizeof(p), ".s.%d", getpid()); @@ -615,9 +615,9 @@ accept_cb(struct ev_loop* loop, struct ev_io* watcher, int revents) int32_t payload_slot; int payload_i; char* payload_s = NULL; - struct configuration* config = NULL; + struct main_configuration* config = NULL; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; if (EV_ERROR & revents) { diff --git a/src/libpgagroal/pool.c b/src/libpgagroal/pool.c index ee72d020..1892796f 100644 --- a/src/libpgagroal/pool.c +++ b/src/libpgagroal/pool.c @@ -73,10 +73,10 @@ pgagroal_get_connection(char* username, char* database, bool reuse, bool transac int retries; int ret; - struct configuration* config; + struct main_configuration* config; struct prometheus* prometheus; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; prometheus = (struct prometheus*)prometheus_shmem; pgagroal_prometheus_connection_get(); @@ -181,7 +181,7 @@ pgagroal_get_connection(char* username, char* database, bool reuse, bool transac } else { - ret = pgagroal_connect(config->servers[server].host, config->servers[server].port, &fd); + ret = pgagroal_connect(config->servers[server].host, config->servers[server].port, &fd, config->keep_alive, config->non_blocking, &config->buffer_size, config->nodelay); } if (ret) @@ -368,12 +368,12 @@ int pgagroal_return_connection(int slot, SSL* ssl, bool transaction_mode) { int state; - struct configuration* config; + struct main_configuration* config; time_t now; signed char in_use; signed char age_check; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; /* Kill the connection, if it lives longer than max_connection_age */ if (config->max_connection_age > 0) @@ -470,9 +470,9 @@ pgagroal_kill_connection(int slot, SSL* ssl) int ssl_shutdown; int result = 0; int fd; - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; pgagroal_log_debug("pgagroal_kill_connection: Slot %d FD %d State %d PID %d", slot, config->connections[slot].fd, atomic_load(&config->states[slot]), @@ -555,12 +555,12 @@ pgagroal_idle_timeout(void) time_t now; signed char free; signed char idle_check; - struct configuration* config; + struct main_configuration* config; pgagroal_start_logging(); pgagroal_memory_init(); - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; now = time(NULL); prefill = false; @@ -614,12 +614,12 @@ pgagroal_max_connection_age(void) time_t now; signed char free; signed char age_check; - struct configuration* config; + struct main_configuration* config; pgagroal_start_logging(); pgagroal_memory_init(); - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; now = time(NULL); prefill = false; @@ -673,12 +673,12 @@ pgagroal_validation(void) time_t now; signed char free; signed char validation; - struct configuration* config; + struct main_configuration* config; pgagroal_start_logging(); pgagroal_memory_init(); - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; now = time(NULL); pgagroal_log_debug("pgagroal_validation"); @@ -766,12 +766,12 @@ pgagroal_flush(int mode, char* database) signed char in_use; bool do_kill; signed char server_state; - struct configuration* config; + struct main_configuration* config; pgagroal_start_logging(); pgagroal_memory_init(); - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; prefill = false; @@ -880,13 +880,13 @@ pgagroal_flush(int mode, char* database) void pgagroal_flush_server(signed char server) { - struct configuration* config; + struct main_configuration* config; int primary = -1; pgagroal_start_logging(); pgagroal_memory_init(); - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; pgagroal_log_debug("pgagroal_flush_server %s", config->servers[server].name); for (int i = 0; i < config->max_connections; i++) @@ -948,12 +948,12 @@ pgagroal_flush_server(signed char server) void pgagroal_prefill(bool initial) { - struct configuration* config; + struct main_configuration* config; pgagroal_start_logging(); pgagroal_memory_init(); - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; pgagroal_log_debug("pgagroal_prefill"); @@ -1058,9 +1058,9 @@ pgagroal_prefill(bool initial) int pgagroal_pool_init(void) { - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; /* States */ for (int i = 0; i < MAX_NUMBER_OF_CONNECTIONS; i++) @@ -1088,9 +1088,9 @@ pgagroal_pool_init(void) int pgagroal_pool_shutdown(void) { - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; for (int i = 0; i < config->max_connections; i++) { @@ -1122,9 +1122,9 @@ pgagroal_pool_shutdown(void) int pgagroal_pool_status(void) { - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; pgagroal_log_debug("pgagroal_pool_status: %d/%d", atomic_load(&config->active_connections), config->max_connections); @@ -1144,10 +1144,10 @@ static int find_best_rule(char* username, char* database) { int best_rule; - struct configuration* config; + struct main_configuration* config; best_rule = -1; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; if (config->number_of_limits > 0) { @@ -1197,9 +1197,9 @@ remove_connection(char* username, char* database) { signed char free; signed char remove; - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; pgagroal_log_trace("remove_connection"); for (int i = config->max_connections - 1; i >= 0; i--) @@ -1238,10 +1238,10 @@ connection_details(int slot) int state; char time_buf[32]; char start_buf[32]; - struct configuration* config; + struct main_configuration* config; struct connection connection; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; connection = config->connections[slot]; state = atomic_load(&config->states[slot]); @@ -1446,9 +1446,9 @@ do_prefill(char* username, char* database, int size) signed char state; int free = 0; int connections = 0; - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; for (int i = 0; i < config->max_connections; i++) { diff --git a/src/libpgagroal/prometheus.c b/src/libpgagroal/prometheus.c index e7582a01..a3371302 100644 --- a/src/libpgagroal/prometheus.c +++ b/src/libpgagroal/prometheus.c @@ -99,12 +99,12 @@ pgagroal_prometheus(int client_fd) int status; int page; struct message* msg = NULL; - struct configuration* config; + struct main_configuration* config; pgagroal_start_logging(); pgagroal_memory_init(); - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; status = pgagroal_read_timeout_message(NULL, client_fd, config->authentication_timeout, &msg); if (status != MESSAGE_STATUS_OK) @@ -154,10 +154,10 @@ pgagroal_init_prometheus(size_t* p_size, void** p_shmem) { size_t tmp_p_size = 0; void* tmp_p_shmem = NULL; - struct configuration* config; + struct main_configuration* config; struct prometheus* prometheus; - config = (struct configuration*) shmem; + config = (struct main_configuration*) shmem; *p_size = 0; *p_shmem = NULL; @@ -639,11 +639,11 @@ void pgagroal_prometheus_reset(void) { signed char cache_is_free; - struct configuration* config; + struct main_configuration* config; struct prometheus* prometheus; struct prometheus_cache* cache; - config = (struct configuration*) shmem; + config = (struct main_configuration*) shmem; prometheus = (struct prometheus*)prometheus_shmem; cache = (struct prometheus_cache*)prometheus_cache_shmem; @@ -729,10 +729,10 @@ pgagroal_prometheus_failed_servers(void) { int count; struct prometheus* prometheus; - struct configuration* config; + struct main_configuration* config; prometheus = (struct prometheus*)prometheus_shmem; - config = (struct configuration*) shmem; + config = (struct main_configuration*) shmem; count = 0; @@ -1348,10 +1348,10 @@ static void general_information(int client_fd) { char* data = NULL; - struct configuration* config; + struct main_configuration* config; struct prometheus* prometheus; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; prometheus = (struct prometheus*)prometheus_shmem; @@ -1483,9 +1483,9 @@ connection_information(int client_fd) char* data = NULL; int active; int total; - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; active = 0; total = 0; @@ -1640,9 +1640,9 @@ static void limit_information(int client_fd) { char* data = NULL; - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; if (config->number_of_limits > 0) { @@ -2031,10 +2031,10 @@ static void connection_awaiting_information(int client_fd) { char* data = NULL; - struct configuration* config; + struct main_configuration* config; struct prometheus* prometheus; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; prometheus = (struct prometheus*)prometheus_shmem; @@ -2128,9 +2128,9 @@ send_chunk(int client_fd, char* data) static bool is_metrics_cache_configured(void) { - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; // cannot have caching if not set metrics! if (config->metrics == 0) @@ -2171,11 +2171,11 @@ int pgagroal_init_prometheus_cache(size_t* p_size, void** p_shmem) { struct prometheus_cache* cache; - struct configuration* config; + struct main_configuration* config; size_t cache_size = 0; size_t struct_size = 0; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; // first of all, allocate the overall cache structure cache_size = metrics_cache_size_to_alloc(); @@ -2219,10 +2219,10 @@ pgagroal_init_prometheus_cache(size_t* p_size, void** p_shmem) static size_t metrics_cache_size_to_alloc(void) { - struct configuration* config; + struct main_configuration* config; size_t cache_size = 0; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; // which size to use ? // either the configured (i.e., requested by user) if lower than the max size @@ -2230,8 +2230,8 @@ metrics_cache_size_to_alloc(void) if (is_metrics_cache_configured()) { cache_size = config->metrics_cache_max_size > 0 - ? MIN(config->metrics_cache_max_size, PROMETHEUS_MAX_CACHE_SIZE) - : PROMETHEUS_DEFAULT_CACHE_SIZE; + ? MIN(config->metrics_cache_max_size, PROMETHEUS_MAX_CACHE_SIZE) + : PROMETHEUS_DEFAULT_CACHE_SIZE; } return cache_size; @@ -2320,12 +2320,12 @@ metrics_cache_append(char* data) static bool metrics_cache_finalize(void) { - struct configuration* config; + struct main_configuration* config; struct prometheus_cache* cache; time_t now; cache = (struct prometheus_cache*)prometheus_cache_shmem; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; if (!is_metrics_cache_configured()) { diff --git a/src/libpgagroal/remote.c b/src/libpgagroal/remote.c index 515fd6b2..86395325 100644 --- a/src/libpgagroal/remote.c +++ b/src/libpgagroal/remote.c @@ -54,14 +54,14 @@ pgagroal_remote_management(int client_fd, char* address) signed char type; SSL* client_ssl = NULL; struct message* msg = NULL; - struct configuration* config; + struct main_configuration* config; pgagroal_start_logging(); pgagroal_memory_init(); exit_code = 0; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; pgagroal_log_debug("pgagroal_remote_management: connect %d", client_fd); @@ -150,6 +150,34 @@ pgagroal_remote_management(int client_fd, char* address) goto done; } + break; + + case MANAGEMENT_GET_PASSWORD: + // Read username size from local + status = pgagroal_read_timeout_message(client_ssl, client_fd, config->authentication_timeout, &msg); + if (status != MESSAGE_STATUS_OK) + { + goto done; + } + + status = pgagroal_write_message(NULL, server_fd, msg); + if (status != MESSAGE_STATUS_OK) + { + goto done; + } + + status = pgagroal_read_timeout_message(NULL, server_fd, config->authentication_timeout, &msg); + if (status != MESSAGE_STATUS_OK) + { + goto done; + } + + status = pgagroal_write_message(client_ssl, client_fd, msg); + if (status != MESSAGE_STATUS_OK) + { + goto done; + } + break; default: pgagroal_log_warn("Unknown management operation: %d", type); diff --git a/src/libpgagroal/security.c b/src/libpgagroal/security.c index 40487747..5d3bbd9a 100644 --- a/src/libpgagroal/security.c +++ b/src/libpgagroal/security.c @@ -143,7 +143,7 @@ pgagroal_authenticate(int client_fd, char* address, int* slot, SSL** client_ssl, int server = 0; int server_fd = -1; int hba_method; - struct configuration* config; + struct main_configuration* config; struct message* msg = NULL; struct message* request_msg = NULL; int32_t request; @@ -152,7 +152,7 @@ pgagroal_authenticate(int client_fd, char* address, int* slot, SSL** client_ssl, char* appname = NULL; SSL* c_ssl = NULL; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; *slot = -1; *client_ssl = NULL; @@ -191,7 +191,7 @@ pgagroal_authenticate(int client_fd, char* address, int* slot, SSL** client_ssl, } else { - ret = pgagroal_connect(config->servers[server].host, config->servers[server].port, &server_fd); + ret = pgagroal_connect(config->servers[server].host, config->servers[server].port, &server_fd, config->keep_alive, config->non_blocking, &config->buffer_size, config->nodelay); } if (ret) @@ -475,13 +475,13 @@ pgagroal_prefill_auth(char* username, char* password, char* database, int* slot, int server_fd = -1; int auth_type = -1; signed char server_state; - struct configuration* config = NULL; + struct main_configuration* config = NULL; struct message* startup_msg = NULL; struct message* msg = NULL; int ret = -1; int status = -1; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; *slot = -1; *server_ssl = NULL; @@ -575,7 +575,7 @@ pgagroal_remote_management_auth(int client_fd, char* address, SSL** client_ssl) { int status = MESSAGE_STATUS_ERROR; int hba_method; - struct configuration* config; + struct main_configuration* config; struct message* msg = NULL; struct message* request_msg = NULL; int32_t request; @@ -585,7 +585,7 @@ pgagroal_remote_management_auth(int client_fd, char* address, SSL** client_ssl) char* password = NULL; SSL* c_ssl = NULL; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; *client_ssl = NULL; @@ -1263,12 +1263,12 @@ static int use_pooled_connection(SSL* c_ssl, int client_fd, int slot, char* username, char* database, int hba_method, SSL** server_ssl) { int status = MESSAGE_STATUS_ERROR; - struct configuration* config = NULL; + struct main_configuration* config = NULL; struct message* auth_msg = NULL; struct message* msg = NULL; char* password = NULL; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; password = get_frontend_password(username); if (password == NULL) @@ -1430,9 +1430,9 @@ use_unpooled_connection(struct message* request_msg, SSL* c_ssl, int client_fd, signed char server_state; struct message* msg = NULL; struct message* auth_msg = NULL; - struct configuration* config = NULL; + struct main_configuration* config = NULL; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; server_fd = config->connections[slot].fd; password = get_frontend_password(username); @@ -1629,12 +1629,12 @@ client_password(SSL* c_ssl, int client_fd, char* username, char* password, int s int status; time_t start_time; bool non_blocking; - struct configuration* config; + struct main_configuration* config; struct message* msg = NULL; pgagroal_log_debug("client_password %d %d", client_fd, slot); - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; status = pgagroal_write_auth_password(c_ssl, client_fd); if (status != MESSAGE_STATUS_OK) @@ -1708,12 +1708,12 @@ client_md5(SSL* c_ssl, int client_fd, char* username, char* password, int slot) char* shadow = NULL; char* md5_req = NULL; char* md5 = NULL; - struct configuration* config; + struct main_configuration* config; struct message* msg = NULL; pgagroal_log_debug("client_md5 %d %d", client_fd, slot); - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; salt[0] = (char)(random() & 0xFF); salt[1] = (char)(random() & 0xFF); @@ -1838,14 +1838,14 @@ client_scram256(SSL* c_ssl, int client_fd, char* username, char* password, int s unsigned char* server_signature_calc = NULL; int server_signature_calc_length = 0; char* base64_server_signature_calc = NULL; - struct configuration* config; + struct main_configuration* config; struct message* msg = NULL; struct message* sasl_continue = NULL; struct message* sasl_final = NULL; pgagroal_log_debug("client_scram256 %d %d", client_fd, slot); - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; status = pgagroal_write_auth_scram256(c_ssl, client_fd); if (status != MESSAGE_STATUS_OK) @@ -2042,12 +2042,12 @@ client_ok(SSL* c_ssl, int client_fd, int slot) size_t size; char* data; struct message msg; - struct configuration* config; + struct main_configuration* config; data = NULL; memset(&msg, 0, sizeof(msg)); - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; if (config->connections[slot].has_security == SECURITY_TRUST) { @@ -2114,9 +2114,9 @@ server_passthrough(struct message* msg, int auth_type, SSL* c_ssl, int client_fd int auth_response = -1; struct message* smsg = NULL; struct message* kmsg = NULL; - struct configuration* config = NULL; + struct main_configuration* config = NULL; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; server_fd = config->connections[slot].fd; pgagroal_log_trace("server_passthrough %d %d", auth_type, slot); @@ -2315,9 +2315,9 @@ server_authenticate(struct message* msg, int auth_type, char* username, char* pa int ret = AUTH_ERROR; struct message* smsg = NULL; struct message* kmsg = NULL; - struct configuration* config = NULL; + struct main_configuration* config = NULL; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; for (int i = 0; i < NUMBER_OF_SECURITY_MESSAGES; i++) { @@ -2399,9 +2399,9 @@ server_authenticate(struct message* msg, int auth_type, char* username, char* pa static int server_trust(int slot, SSL* server_ssl) { - struct configuration* config = NULL; + struct main_configuration* config = NULL; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; pgagroal_log_trace("server_trust"); @@ -2419,9 +2419,9 @@ server_password(char* username, char* password, int slot, SSL* server_ssl) int server_fd; struct message* auth_msg = NULL; struct message* password_msg = NULL; - struct configuration* config = NULL; + struct main_configuration* config = NULL; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; server_fd = config->connections[slot].fd; pgagroal_log_trace("server_password"); @@ -2510,9 +2510,9 @@ server_md5(char* username, char* password, int slot, SSL* server_ssl) char* salt = NULL; struct message* auth_msg = NULL; struct message* md5_msg = NULL; - struct configuration* config = NULL; + struct main_configuration* config = NULL; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; server_fd = config->connections[slot].fd; pgagroal_log_trace("server_md5"); @@ -2662,9 +2662,9 @@ server_scram256(char* username, char* password, int slot, SSL* server_ssl) struct message* sasl_continue_response = NULL; struct message* sasl_final = NULL; struct message* msg = NULL; - struct configuration* config = NULL; + struct main_configuration* config = NULL; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; server_fd = config->connections[slot].fd; pgagroal_log_trace("server_scram256"); @@ -2865,9 +2865,9 @@ server_scram256(char* username, char* password, int slot, SSL* server_ssl) static bool is_allowed(char* username, char* database, char* address, int* hba_method) { - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; for (int i = 0; i < config->number_of_hbas; i++) { @@ -3045,9 +3045,9 @@ is_allowed_address(char* address, char* entry) static bool is_disabled(char* database) { - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; for (int i = 0; i < NUMBER_OF_DISABLED; i++) { @@ -3064,9 +3064,9 @@ is_disabled(char* database) static int get_hba_method(int index) { - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; if (!strcasecmp(config->hbas[index].method, "reject")) { @@ -3104,9 +3104,9 @@ get_hba_method(int index) static char* get_password(char* username) { - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; for (int i = 0; i < config->number_of_users; i++) { @@ -3122,9 +3122,9 @@ get_password(char* username) static char* get_frontend_password(char* username) { - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; for (int i = 0; i < config->number_of_frontend_users; i++) { @@ -3140,9 +3140,9 @@ get_frontend_password(char* username) static char* get_admin_password(char* username) { - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; for (int i = 0; i < config->number_of_admins; i++) { @@ -3314,9 +3314,9 @@ pgagroal_md5(char* str, int length, char** md5) bool pgagroal_user_known(char* user) { - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; for (int i = 0; i < config->number_of_users; i++) { @@ -3332,10 +3332,10 @@ pgagroal_user_known(char* user) int pgagroal_tls_valid(void) { - struct configuration* config; + struct main_configuration* config; struct stat st = {0}; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; if (config->tls) { @@ -4350,9 +4350,9 @@ server_signature(char* password, char* salt, int salt_length, int iterations, static bool is_tls_user(char* username, char* database) { - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; for (int i = 0; i < config->number_of_hbas; i++) { @@ -4533,9 +4533,9 @@ create_ssl_server(SSL_CTX* ctx, int socket, SSL** ssl) { SSL* s = NULL; STACK_OF(X509_NAME) * root_cert_list = NULL; - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; if (strlen(config->tls_cert_file) == 0) { @@ -4641,9 +4641,9 @@ auth_query(SSL* c_ssl, int client_fd, int slot, char* username, char* database, SSL* su_ssl = NULL; char* shadow = NULL; int ret; - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; /* Get connection to server using the superuser */ ret = auth_query_get_connection(config->superuser.username, config->superuser.password, database, &su_socket, &su_ssl); @@ -4752,14 +4752,14 @@ auth_query_get_connection(char* username, char* password, char* database, int* s signed char isfree; time_t start_time; char* error = NULL; - struct configuration* config = NULL; + struct main_configuration* config = NULL; struct message* startup_msg = NULL; struct message* startup_response_msg = NULL; struct message* msg = NULL; int ret = -1; int status = -1; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; *server_fd = -1; @@ -4791,7 +4791,7 @@ auth_query_get_connection(char* username, char* password, char* database, int* s } else { - ret = pgagroal_connect(config->servers[server].host, config->servers[server].port, server_fd); + ret = pgagroal_connect(config->servers[server].host, config->servers[server].port, server_fd, config->keep_alive, config->non_blocking, &config->buffer_size, config->nodelay); } if (ret) @@ -5385,10 +5385,10 @@ auth_query_client_md5(SSL* c_ssl, int client_fd, char* username, char* hash, int bool non_blocking; char* md5_req = NULL; char* md5 = NULL; - struct configuration* config; + struct main_configuration* config; struct message* msg = NULL; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; salt[0] = (char)(random() & 0xFF); salt[1] = (char)(random() & 0xFF); @@ -5505,14 +5505,14 @@ auth_query_client_scram256(SSL* c_ssl, int client_fd, char* username, char* shad unsigned char* server_signature_calc = NULL; int server_signature_calc_length = 0; char* base64_server_signature_calc = NULL; - struct configuration* config; + struct main_configuration* config; struct message* msg = NULL; struct message* sasl_continue = NULL; struct message* sasl_final = NULL; pgagroal_log_debug("auth_query_client_scram256 %d %d", client_fd, slot); - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; status = pgagroal_write_auth_scram256(c_ssl, client_fd); if (status != MESSAGE_STATUS_OK) @@ -5716,12 +5716,12 @@ auth_query_client_scram256(SSL* c_ssl, int client_fd, char* username, char* shad static int establish_client_tls_connection(int server, int fd, SSL** ssl) { - struct configuration* config = NULL; + struct main_configuration* config = NULL; struct message* ssl_msg = NULL; struct message* msg = NULL; int status = -1; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; if (config->servers[server].tls) { @@ -5840,3 +5840,48 @@ create_client_tls_connection(int fd, SSL** ssl, char* tls_key_file, char* tls_ce return AUTH_ERROR; } + +void +pgagroal_initialize_random() +{ + time_t t; + srand((unsigned)time(&t)); +} + +int +pgagroal_generate_password(int pwd_length, char** password) +{ + char* pwd; + + pwd = (char*) malloc((pwd_length + 1) * sizeof(char)); + if (!pwd) + { + pgagroal_log_fatal("Couldn't allocate memory while generating password"); + return 1; + } + + for (int i = 0; i < pwd_length; i++) + { + pwd[i] = (char) (32 + rand() % (126 - 32 + 1)); + } + pwd[pwd_length] = '\0'; + + // avoid leading/trailing/consecutive spaces. + if (pwd[0] == ' ') + { + pwd[0] = (char) (33 + rand() % (126 - 33 + 1)); + } + if (pwd[pwd_length - 1] == ' ') + { + pwd[pwd_length - 1] = (char) (33 + rand() % (126 - 33 + 1)); + } + for (int i = 2; i < pwd_length - 1; i++) + { + if (pwd[i] == ' ' && pwd[i - 1] == ' ') + { + pwd[i] = (char) (33 + rand() % (126 - 33 + 1)); + } + } + *password = pwd; + return 0; +} diff --git a/src/libpgagroal/server.c b/src/libpgagroal/server.c index b4b48c3b..c2760906 100644 --- a/src/libpgagroal/server.c +++ b/src/libpgagroal/server.c @@ -50,10 +50,10 @@ pgagroal_get_primary(int* server) { int primary; signed char server_state; - struct configuration* config; + struct main_configuration* config; primary = -1; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; /* Find PRIMARY */ for (int i = 0; primary == -1 && i < config->number_of_servers; i++) @@ -114,9 +114,9 @@ pgagroal_update_server_state(int slot, int socket, SSL* ssl) char is_recovery[size]; struct message qmsg; struct message* tmsg = NULL; - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; server = config->connections[slot].server; memset(&qmsg, 0, sizeof(struct message)); @@ -171,9 +171,9 @@ pgagroal_update_server_state(int slot, int socket, SSL* ssl) int pgagroal_server_status(void) { - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; for (int i = 0; i < NUMBER_OF_SERVERS; i++) { @@ -219,9 +219,9 @@ pgagroal_server_failover(int slot) signed char primary; signed char old_primary; int ret = 1; - struct configuration* config = NULL; + struct main_configuration* config = NULL; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; primary = SERVER_PRIMARY; @@ -245,9 +245,9 @@ pgagroal_server_force_failover(int server) { signed char cur_state; signed char prev_state; - struct configuration* config = NULL; + struct main_configuration* config = NULL; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; cur_state = atomic_load(&config->servers[server].state); @@ -272,9 +272,9 @@ int pgagroal_server_reset(char* server) { signed char state; - struct configuration* config = NULL; + struct main_configuration* config = NULL; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; for (int i = 0; i < config->number_of_servers; i++) { @@ -300,9 +300,9 @@ pgagroal_server_switch(char* server) int old_primary; int new_primary; signed char state; - struct configuration* config = NULL; + struct main_configuration* config = NULL; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; old_primary = -1; new_primary = -1; @@ -345,9 +345,9 @@ failover(int old_primary) char new_primary_port[6]; int status; pid_t pid; - struct configuration* config = NULL; + struct main_configuration* config = NULL; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; new_primary = -1; diff --git a/src/libpgagroal/shmem.c b/src/libpgagroal/shmem.c index bb24487b..7544fbe8 100644 --- a/src/libpgagroal/shmem.c +++ b/src/libpgagroal/shmem.c @@ -91,9 +91,9 @@ pgagroal_create_shared_memory(size_t size, unsigned char hp, void** shmem) int pgagroal_resize_shared_memory(size_t size, void* shmem, size_t* new_size, void** new_shmem) { - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; *new_size = size + (config->max_connections * sizeof(struct connection)); if (pgagroal_create_shared_memory(*new_size, config->hugepage, new_shmem)) diff --git a/src/libpgagroal/tracker.c b/src/libpgagroal/tracker.c index bf444cd5..4b99c242 100644 --- a/src/libpgagroal/tracker.c +++ b/src/libpgagroal/tracker.c @@ -46,9 +46,9 @@ void pgagroal_tracking_event_basic(int id, char* username, char* database) { int primary; - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; if (config->tracker) { @@ -93,9 +93,9 @@ pgagroal_tracking_event_basic(int id, char* username, char* database) void pgagroal_tracking_event_slot(int id, int slot) { - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; if (config->tracker) { @@ -144,9 +144,9 @@ pgagroal_tracking_event_slot(int id, int slot) void pgagroal_tracking_event_socket(int id, int socket) { - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; if (config->tracker) { @@ -168,9 +168,9 @@ static int count_connections(void) { int active = 0; - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; for (int i = 0; i < config->max_connections; i++) { diff --git a/src/libpgagroal/utils.c b/src/libpgagroal/utils.c index e7036668..36bcac40 100644 --- a/src/libpgagroal/utils.c +++ b/src/libpgagroal/utils.c @@ -730,9 +730,9 @@ pgagroal_set_proc_title(int argc, char** argv, char* s1, char* s2) size_t size; char** env = environ; int es = 0; - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; // sanity check: if the user does not want to // update the process title, do nothing @@ -819,11 +819,11 @@ pgagroal_set_proc_title(int argc, char** argv, char* s1, char* s2) void pgagroal_set_connection_proc_title(int argc, char** argv, struct connection* connection) { - struct configuration* config; + struct main_configuration* config; int primary; char* info = NULL; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; if (pgagroal_get_primary(&primary)) { diff --git a/src/libpgagroal/worker.c b/src/libpgagroal/worker.c index d0c01deb..56528179 100644 --- a/src/libpgagroal/worker.c +++ b/src/libpgagroal/worker.c @@ -63,7 +63,7 @@ pgagroal_worker(int client_fd, char* address, char** argv) time_t start_time; bool started = false; int auth_status; - struct configuration* config; + struct main_configuration* config; struct pipeline p; bool tx_pool = false; int32_t slot = -1; @@ -73,7 +73,7 @@ pgagroal_worker(int client_fd, char* address, char** argv) pgagroal_start_logging(); pgagroal_memory_init(); - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; memset(&client_io, 0, sizeof(struct worker_io)); memset(&server_io, 0, sizeof(struct worker_io)); @@ -96,7 +96,7 @@ pgagroal_worker(int client_fd, char* address, char** argv) pgagroal_tracking_event_socket(TRACKER_SOCKET_ASSOCIATE_SERVER, config->connections[slot].fd); - if (config->log_connections) + if (config->common.log_connections) { pgagroal_log_info("connect: user=%s database=%s address=%s", config->connections[slot].username, config->connections[slot].database, address); @@ -186,14 +186,14 @@ pgagroal_worker(int client_fd, char* address, char** argv) } else { - if (config->log_connections) + if (config->common.log_connections) { pgagroal_log_info("connect: address=%s", address); } pgagroal_prometheus_client_wait_sub(); } - if (config->log_disconnections) + if (config->common.log_disconnections) { if (auth_status == AUTH_SUCCESS) { diff --git a/src/main.c b/src/main.c index aef6e287..d734075f 100644 --- a/src/main.c +++ b/src/main.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -43,25 +44,25 @@ #include /* system */ +#include +#include #include #include #include #include +#include +#include #include #include #include #include -#include -#include -#include #include #include #include #include #include -#include +#include -#include #ifdef HAVE_LINUX #include #endif @@ -78,6 +79,7 @@ static void graceful_cb(struct ev_loop* loop, ev_signal* w, int revents); static void coredump_cb(struct ev_loop* loop, ev_signal* w, int revents); static void idle_timeout_cb(struct ev_loop* loop, ev_periodic* w, int revents); static void max_connection_age_cb(struct ev_loop* loop, ev_periodic* w, int revents); +static void rotate_frontend_password_cb(struct ev_loop* loop, ev_periodic* w, int revents); static void validation_cb(struct ev_loop* loop, ev_periodic* w, int revents); static void disconnect_client_cb(struct ev_loop* loop, ev_periodic* w, int revents); static bool accept_fatal(int error); @@ -88,19 +90,6 @@ static void create_pidfile_or_exit(void); static void remove_pidfile(void); static void shutdown_ports(void); -struct accept_io -{ - struct ev_io io; - int socket; - char** argv; -}; - -struct client -{ - pid_t pid; - struct client* next; -}; - static volatile int keep_running = 1; static char** argv_ptr; static struct ev_loop* main_loop = NULL; @@ -134,9 +123,9 @@ start_mgt(void) static void shutdown_mgt(void) { - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; ev_io_stop(main_loop, (struct ev_io*)&io_mgt); pgagroal_disconnect(unix_management_socket); @@ -159,12 +148,12 @@ static void shutdown_uds(void) { char pgsql[MISC_LENGTH]; - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; memset(&pgsql, 0, sizeof(pgsql)); - snprintf(&pgsql[0], sizeof(pgsql), ".s.PGSQL.%d", config->port); + snprintf(&pgsql[0], sizeof(pgsql), ".s.PGSQL.%d", config->common.port); ev_io_stop(main_loop, (struct ev_io*)&io_uds); pgagroal_disconnect(unix_pgsql_socket); @@ -314,18 +303,18 @@ main(int argc, char** argv) struct ev_periodic max_connection_age; struct ev_periodic validation; struct ev_periodic disconnect_client; + struct ev_periodic rotate_frontend_password; struct rlimit flimit; size_t shmem_size; size_t pipeline_shmem_size = 0; size_t prometheus_shmem_size = 0; size_t prometheus_cache_shmem_size = 0; size_t tmp_size; - struct configuration* config = NULL; + struct main_configuration* config = NULL; int ret; int c; bool conf_file_mandatory; char message[MISC_LENGTH]; // a generic message used for errors - argv_ptr = argv; while (1) @@ -399,7 +388,7 @@ main(int argc, char** argv) errx(1, "Using the root account is not allowed"); } - shmem_size = sizeof(struct configuration); + shmem_size = sizeof(struct main_configuration); if (pgagroal_create_shared_memory(shmem_size, HUGEPAGE_OFF, &shmem)) { #ifdef HAVE_LINUX @@ -409,7 +398,7 @@ main(int argc, char** argv) } pgagroal_init_configuration(shmem); - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; memset(&known_fds, 0, sizeof(known_fds)); memset(message, 0, MISC_LENGTH); @@ -444,7 +433,7 @@ main(int argc, char** argv) errx(1, "%s (file <%s>)", message, configuration_path); } - memcpy(&config->configuration_path[0], configuration_path, MIN(strlen(configuration_path), MAX_PATH - 1)); + memcpy(&config->common.configuration_path[0], configuration_path, MIN(strlen(configuration_path), MAX_PATH - 1)); // the HBA file is mandatory! hba_path = hba_path != NULL ? hba_path : PGAGROAL_DEFAULT_HBA_FILE; @@ -811,7 +800,7 @@ main(int argc, char** argv) } shmem_size = tmp_size; shmem = tmp_shmem; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; if (pgagroal_init_prometheus(&prometheus_shmem_size, &prometheus_shmem)) { @@ -850,7 +839,7 @@ main(int argc, char** argv) if (daemon) { - if (config->log_type == PGAGROAL_LOGGING_TYPE_CONSOLE) + if (config->common.log_type == PGAGROAL_LOGGING_TYPE_CONSOLE) { #ifdef HAVE_LINUX sd_notify(0, "STATUS=Daemon mode can't be used with console logging"); @@ -886,6 +875,7 @@ main(int argc, char** argv) create_pidfile_or_exit(); pgagroal_pool_init(); + pgagroal_initialize_random(); pgagroal_set_proc_title(argc, argv, "main", NULL); @@ -904,7 +894,7 @@ main(int argc, char** argv) char pgsql[MISC_LENGTH]; memset(&pgsql, 0, sizeof(pgsql)); - snprintf(&pgsql[0], sizeof(pgsql), ".s.PGSQL.%d", config->port); + snprintf(&pgsql[0], sizeof(pgsql), ".s.PGSQL.%d", config->common.port); if (pgagroal_bind_unix_socket(config->unix_socket_dir, &pgsql[0], &unix_pgsql_socket)) { @@ -919,11 +909,11 @@ main(int argc, char** argv) /* Bind main socket */ if (!has_main_sockets) { - if (pgagroal_bind(config->host, config->port, &main_fds, &main_fds_length)) + if (pgagroal_bind(config->common.host, config->common.port, &main_fds, &main_fds_length, config->non_blocking, &config->buffer_size, config->nodelay, config->backlog)) { - pgagroal_log_fatal("pgagroal: Could not bind to %s:%d", config->host, config->port); + pgagroal_log_fatal("pgagroal: Could not bind to %s:%d", config->common.host, config->common.port); #ifdef HAVE_LINUX - sd_notifyf(0, "STATUS=Could not bind to %s:%d", config->host, config->port); + sd_notifyf(0, "STATUS=Could not bind to %s:%d", config->common.host, config->common.port); #endif goto error; } @@ -1043,14 +1033,21 @@ main(int argc, char** argv) ev_periodic_start (main_loop, &disconnect_client); } + if (config->rotate_frontend_password_timeout > 0) + { + ev_periodic_init (&rotate_frontend_password, rotate_frontend_password_cb, 0., + config->rotate_frontend_password_timeout, 0); + ev_periodic_start (main_loop, &rotate_frontend_password); + } + if (config->metrics > 0) { /* Bind metrics socket */ - if (pgagroal_bind(config->host, config->metrics, &metrics_fds, &metrics_fds_length)) + if (pgagroal_bind(config->common.host, config->metrics, &metrics_fds, &metrics_fds_length, config->non_blocking, &config->buffer_size, config->nodelay, config->backlog)) { - pgagroal_log_fatal("pgagroal: Could not bind to %s:%d", config->host, config->metrics); + pgagroal_log_fatal("pgagroal: Could not bind to %s:%d", config->common.host, config->metrics); #ifdef HAVE_LINUX - sd_notifyf(0, "STATUS=Could not bind to %s:%d", config->host, config->metrics); + sd_notifyf(0, "STATUS=Could not bind to %s:%d", config->common.host, config->metrics); #endif goto error; } @@ -1070,11 +1067,11 @@ main(int argc, char** argv) if (config->management > 0) { /* Bind management socket */ - if (pgagroal_bind(config->host, config->management, &management_fds, &management_fds_length)) + if (pgagroal_bind(config->common.host, config->management, &management_fds, &management_fds_length, config->non_blocking, &config->buffer_size, config->nodelay, config->backlog)) { - pgagroal_log_fatal("pgagroal: Could not bind to %s:%d", config->host, config->management); + pgagroal_log_fatal("pgagroal: Could not bind to %s:%d", config->common.host, config->management); #ifdef HAVE_LINUX - sd_notifyf(0, "STATUS=Could not bind to %s:%d", config->host, config->management); + sd_notifyf(0, "STATUS=Could not bind to %s:%d", config->common.host, config->management); #endif goto error; } @@ -1093,8 +1090,8 @@ main(int argc, char** argv) pgagroal_log_info("pgagroal: %s started on %s:%d", PGAGROAL_VERSION, - config->host, - config->port); + config->common.host, + config->common.port); for (int i = 0; i < main_fds_length; i++) { pgagroal_log_debug("Socket: %d", *(main_fds + i)); @@ -1209,7 +1206,7 @@ accept_main_cb(struct ev_loop* loop, struct ev_io* watcher, int revents) char address[INET6_ADDRSTRLEN]; pid_t pid; struct accept_io* ai; - struct configuration* config; + struct main_configuration* config; if (EV_ERROR & revents) { @@ -1219,7 +1216,7 @@ accept_main_cb(struct ev_loop* loop, struct ev_io* watcher, int revents) } ai = (struct accept_io*)watcher; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; memset(&address, 0, sizeof(address)); @@ -1237,7 +1234,7 @@ accept_main_cb(struct ev_loop* loop, struct ev_io* watcher, int revents) shutdown_uds(); memset(&pgsql, 0, sizeof(pgsql)); - snprintf(&pgsql[0], sizeof(pgsql), ".s.PGSQL.%d", config->port); + snprintf(&pgsql[0], sizeof(pgsql), ".s.PGSQL.%d", config->common.port); if (pgagroal_bind_unix_socket(config->unix_socket_dir, &pgsql[0], &unix_pgsql_socket)) { @@ -1249,9 +1246,9 @@ accept_main_cb(struct ev_loop* loop, struct ev_io* watcher, int revents) main_fds = NULL; main_fds_length = 0; - if (pgagroal_bind(config->host, config->port, &main_fds, &main_fds_length)) + if (pgagroal_bind(config->common.host, config->common.port, &main_fds, &main_fds_length, config->non_blocking, &config->buffer_size, config->nodelay, config->backlog)) { - pgagroal_log_fatal("pgagroal: Could not bind to %s:%d", config->host, config->port); + pgagroal_log_fatal("pgagroal: Could not bind to %s:%d", config->common.host, config->common.port); exit(1); } @@ -1330,7 +1327,7 @@ accept_mgt_cb(struct ev_loop* loop, struct ev_io* watcher, int revents) int payload_i, secondary_payload_i; char* payload_s = NULL; char* secondary_payload_s = NULL; - struct configuration* config; + struct main_configuration* config; if (EV_ERROR & revents) { @@ -1338,7 +1335,7 @@ accept_mgt_cb(struct ev_loop* loop, struct ev_io* watcher, int revents) return; } - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; client_addr_length = sizeof(client_addr); client_fd = accept(watcher->fd, (struct sockaddr*)&client_addr, &client_addr_length); @@ -1558,6 +1555,25 @@ accept_mgt_cb(struct ev_loop* loop, struct ev_io* watcher, int revents) pgagroal_log_debug("pgagroal: Management config-set for key <%s> setting value to <%s>", payload_s, secondary_payload_s); pgagroal_management_write_config_set(client_fd, payload_s, secondary_payload_s); break; + case MANAGEMENT_GET_PASSWORD: + { + // get frontend password + char frontend_password[MAX_PASSWORD_LENGTH]; + memset(frontend_password, 0, sizeof(frontend_password)); + + for (int i = 0; i < config->number_of_frontend_users; i++) + { + if (!strcmp(&config->frontend_users[i].username[0], payload_s)) + { + memcpy(frontend_password, config->frontend_users[i].password, strlen(config->frontend_users[i].password)); + } + } + + // Send password to the vault + pgagroal_management_write_get_password(client_fd, frontend_password); + pgagroal_disconnect(client_fd); + return; + } default: pgagroal_log_debug("pgagroal: Unknown management id: %d", id); break; @@ -1584,7 +1600,7 @@ accept_metrics_cb(struct ev_loop* loop, struct ev_io* watcher, int revents) struct sockaddr_in6 client_addr; socklen_t client_addr_length; int client_fd; - struct configuration* config; + struct main_configuration* config; if (EV_ERROR & revents) { @@ -1593,7 +1609,7 @@ accept_metrics_cb(struct ev_loop* loop, struct ev_io* watcher, int revents) return; } - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; client_addr_length = sizeof(client_addr); client_fd = accept(watcher->fd, (struct sockaddr*)&client_addr, &client_addr_length); @@ -1612,9 +1628,9 @@ accept_metrics_cb(struct ev_loop* loop, struct ev_io* watcher, int revents) metrics_fds = NULL; metrics_fds_length = 0; - if (pgagroal_bind(config->host, config->metrics, &metrics_fds, &metrics_fds_length)) + if (pgagroal_bind(config->common.host, config->metrics, &metrics_fds, &metrics_fds_length, config->non_blocking, &config->buffer_size, config->nodelay, config->backlog)) { - pgagroal_log_fatal("pgagroal: Could not bind to %s:%d", config->host, config->metrics); + pgagroal_log_fatal("pgagroal: Could not bind to %s:%d", config->common.host, config->metrics); exit(1); } @@ -1658,7 +1674,7 @@ accept_management_cb(struct ev_loop* loop, struct ev_io* watcher, int revents) socklen_t client_addr_length; int client_fd; char address[INET6_ADDRSTRLEN]; - struct configuration* config; + struct main_configuration* config; if (EV_ERROR & revents) { @@ -1669,7 +1685,7 @@ accept_management_cb(struct ev_loop* loop, struct ev_io* watcher, int revents) memset(&address, 0, sizeof(address)); - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; client_addr_length = sizeof(client_addr); client_fd = accept(watcher->fd, (struct sockaddr*)&client_addr, &client_addr_length); @@ -1688,9 +1704,9 @@ accept_management_cb(struct ev_loop* loop, struct ev_io* watcher, int revents) management_fds = NULL; management_fds_length = 0; - if (pgagroal_bind(config->host, config->management, &management_fds, &management_fds_length)) + if (pgagroal_bind(config->common.host, config->management, &management_fds, &management_fds_length, config->non_blocking, &config->buffer_size, config->nodelay, config->backlog)) { - pgagroal_log_fatal("pgagroal: Could not bind to %s:%d", config->host, config->management); + pgagroal_log_fatal("pgagroal: Could not bind to %s:%d", config->common.host, config->management); exit(1); } @@ -1756,9 +1772,9 @@ reload_cb(struct ev_loop* loop, ev_signal* w, int revents) static void graceful_cb(struct ev_loop* loop, ev_signal* w, int revents) { - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; pgagroal_log_debug("pgagroal: gracefully requested"); @@ -1849,6 +1865,34 @@ disconnect_client_cb(struct ev_loop* loop, ev_periodic* w, int revents) } } +static void +rotate_frontend_password_cb(struct ev_loop* loop, ev_periodic* w, int revents) +{ + char* pwd; + + if (EV_ERROR & revents) + { + pgagroal_log_trace("rotate_frontend_password_cb: got invalid event: %s", strerror(errno)); + return; + } + + struct main_configuration* config; + + config = (struct main_configuration*)shmem; + + for (int i = 0; i < config->number_of_frontend_users; i++) + { + if (pgagroal_generate_password(config->rotate_frontend_password_length, &pwd)) + { + pgagroal_log_debug("rotate_frontend_password_cb: unable to rotate password"); + return; + } + memcpy(&config->frontend_users[i].password, pwd, strlen(pwd) + 1); + pgagroal_log_trace("rotate_frontend_password_cb: current pass for username=%s:%s", config->frontend_users[i].username, config->frontend_users[i].password); + free(pwd); + } +} + static bool accept_fatal(int error) { @@ -1939,9 +1983,9 @@ static void reload_configuration(void) { char pgsql[MISC_LENGTH]; - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; shutdown_io(); shutdown_uds(); @@ -1951,7 +1995,7 @@ reload_configuration(void) pgagroal_reload_configuration(); memset(&pgsql, 0, sizeof(pgsql)); - snprintf(&pgsql[0], sizeof(pgsql), ".s.PGSQL.%d", config->port); + snprintf(&pgsql[0], sizeof(pgsql), ".s.PGSQL.%d", config->common.port); if (pgagroal_bind_unix_socket(config->unix_socket_dir, &pgsql[0], &unix_pgsql_socket)) { @@ -1963,9 +2007,9 @@ reload_configuration(void) main_fds = NULL; main_fds_length = 0; - if (pgagroal_bind(config->host, config->port, &main_fds, &main_fds_length)) + if (pgagroal_bind(config->common.host, config->common.port, &main_fds, &main_fds_length, config->non_blocking, &config->buffer_size, config->nodelay, config->backlog)) { - pgagroal_log_fatal("pgagroal: Could not bind to %s:%d", config->host, config->port); + pgagroal_log_fatal("pgagroal: Could not bind to %s:%d", config->common.host, config->common.port); goto error; } @@ -1985,9 +2029,9 @@ reload_configuration(void) metrics_fds_length = 0; /* Bind metrics socket */ - if (pgagroal_bind(config->host, config->metrics, &metrics_fds, &metrics_fds_length)) + if (pgagroal_bind(config->common.host, config->metrics, &metrics_fds, &metrics_fds_length, config->non_blocking, &config->buffer_size, config->nodelay, config->backlog)) { - pgagroal_log_fatal("pgagroal: Could not bind to %s:%d", config->host, config->metrics); + pgagroal_log_fatal("pgagroal: Could not bind to %s:%d", config->common.host, config->metrics); goto error; } @@ -2007,9 +2051,9 @@ reload_configuration(void) management_fds_length = 0; /* Bind management socket */ - if (pgagroal_bind(config->host, config->management, &management_fds, &management_fds_length)) + if (pgagroal_bind(config->common.host, config->management, &management_fds, &management_fds_length, config->non_blocking, &config->buffer_size, config->nodelay, config->backlog)) { - pgagroal_log_fatal("pgagroal: Could not bind to %s:%d", config->host, config->management); + pgagroal_log_fatal("pgagroal: Could not bind to %s:%d", config->common.host, config->management); goto error; } @@ -2056,9 +2100,9 @@ create_pidfile_or_exit(void) pid_t pid; int r; int fd; - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; if (strlen(config->pidfile) > 0) { @@ -2093,9 +2137,9 @@ create_pidfile_or_exit(void) static void remove_pidfile(void) { - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; if (strlen(config->pidfile) > 0) { @@ -2109,9 +2153,9 @@ remove_pidfile(void) static void shutdown_ports(void) { - struct configuration* config; + struct main_configuration* config; - config = (struct configuration*)shmem; + config = (struct main_configuration*)shmem; shutdown_io(); diff --git a/src/vault.c b/src/vault.c new file mode 100644 index 00000000..133fbfed --- /dev/null +++ b/src/vault.c @@ -0,0 +1,568 @@ +/* + * Copyright (C) 2024 The pgagroal community + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may + * be used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* pgagroal */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* system */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_LINUX +#include +#endif + +#define MAX_FDS 64 + +static void accept_vault_cb(struct ev_loop* loop, struct ev_io* watcher, int revents); +static void shutdown_cb(struct ev_loop* loop, ev_signal* w, int revents); +static bool accept_fatal(int error); +static int connect_pgagroal(struct vault_configuration* config, char* username, char* password, SSL* s_ssl, int* client_socket); +static void route_users(int client_fd, char* username, char* response, size_t response_size); +static void route_not_found(char* response, size_t response_size); +static int router(int client_fd, SSL* ssl); + +static volatile int keep_running = 1; +static char** argv_ptr; +static struct ev_loop* main_loop = NULL; +static struct accept_io io_main; +static int* server_fd = NULL; +static int server_fds_length = -1; +static int default_buffer_size = DEFAULT_BUFFER_SIZE; + +static int +router(int client_fd, SSL* ssl) +{ + int exit_code = 0; + ssize_t bytes_read; + ssize_t bytes_write; + char* body = NULL; + char method[8]; + char path[128]; + char buffer[HTTP_BUFFER_SIZE]; + char contents[HTTP_BUFFER_SIZE]; + char response[HTTP_BUFFER_SIZE]; + char format_string[HTTP_BUFFER_SIZE]; + char username[MAX_USERNAME_LENGTH + 1]; // Assuming username is less than 128 characters + + // Read the request + bytes_read = read(client_fd, buffer, sizeof(buffer) - 1); + buffer[bytes_read] = '\0'; + + sscanf(buffer, "%7s %127s", method, path); + + // Extract the POST data + body = strstr(buffer, "\r\n\r\n"); + if (body) + { + strcpy(contents, body + 4); + } + + // Parse URL parameters for GET requests only + if (strcmp(method, "GET") == 0) + { + // Call the appropriate handler function for the URL path + if (strncmp(path, "/users/", 7) == 0 && strcmp(method, "GET") == 0) // Only one '/' + { + // Extract the username from the path + snprintf(format_string, sizeof(format_string), "/users/%%%ds", MAX_USERNAME_LENGTH); + sscanf(path, "/users/%128s", username); + // Call the appropriate handler function with the username + route_users(client_fd, username, response, sizeof(response)); + } + else + { + route_not_found(response, sizeof(response)); + } + } + else + { + route_not_found(response, sizeof(response)); + } + + // Send the response + bytes_write = write(client_fd, response, strlen(response)); + + if (bytes_write <= 0) + { + exit_code = 1; + } + + return exit_code; +} + +static void +route_users(int client_fd, char* username, char* response, size_t response_size) +{ + struct vault_configuration* config = (struct vault_configuration*)shmem; + int client_pgagroal_fd = -1; + char password[MAX_PASSWORD_LENGTH + 1]; + + // Connect to pgagroal management port + if (connect_pgagroal(config, config->vault_server.user.username, config->vault_server.user.password, NULL, &client_pgagroal_fd)) // Change NULL to ssl + { + pgagroal_log_error("pgagroal-vault: Couldn't connect to %s:%d", config->vault_server.server.host, config->vault_server.server.port); + // Send Error Response + route_not_found(response, response_size); + return; + } + + memset(password, 0, MAX_PASSWORD_LENGTH); + + // Call GET_PASSWORD at management port + if (pgagroal_management_get_password(NULL, client_pgagroal_fd, username, password)) + { + pgagroal_log_error("pgagroal-vault: Couldn't get password from the management"); + // Send Error Response + route_not_found(response, response_size); + return; + } + + if (strlen(password) == 0) // user not found + { + pgagroal_log_warn("pgagroal-vault: Couldn't find the user: %s", username); + route_not_found(response, response_size); + } + + else + { + snprintf(response, response_size, "HTTP/1.1 200 OK\r\n" + "Content-Type: text/plain\r\n" + "\r\n\r\n" + "%s\r\n", + password); + } +} + +static void +route_not_found(char* response, size_t response_size) +{ + snprintf(response, response_size, "HTTP/1.1 404 Not Found\r\n\r\n"); +} + +static int +connect_pgagroal(struct vault_configuration* config, char* username, char* password, SSL* s_ssl, int* client_socket) +{ + if (pgagroal_connect(config->vault_server.server.host, config->vault_server.server.port, client_socket, false, false, &default_buffer_size, false)) + { + pgagroal_disconnect(*client_socket); + return 1; + } + + pgagroal_log_debug("connect_pgagroal: Authenticating the remote management access to %s:%d", config->vault_server.server.host, config->vault_server.server.port); + username = config->vault_server.user.username; + + for (int i = 0; i < strlen(password); i++) + { + if ((unsigned char)(*(password + i)) & 0x80) + { + + pgagroal_log_debug("pgagroal-vault: Bad credentials for %s", username); + return 1; + } + } + + /* Authenticate */ + if (pgagroal_remote_management_scram_sha256(username, password, *client_socket, &s_ssl) != AUTH_SUCCESS) + { + pgagroal_log_debug("pgagroal-vault: Bad credentials for %s", username); + pgagroal_disconnect(*client_socket); + return 1; + } + + return 0; +} + +static void +start_vault_io(void) +{ + int sockfd = *server_fd; + + memset(&io_main, 0, sizeof(struct accept_io)); + ev_io_init((struct ev_io*)&io_main, accept_vault_cb, sockfd, EV_READ); + io_main.socket = sockfd; + io_main.argv = argv_ptr; + ev_io_start(main_loop, (struct ev_io*)&io_main); +} + +static void +shutdown_vault_io(void) +{ + ev_io_stop(main_loop, (struct ev_io*)&io_main); + pgagroal_disconnect(io_main.socket); + errno = 0; +} + +static void +usage(void) +{ + printf("pgagroal-vault %s\n", PGAGROAL_VERSION); + printf(" Simple vault that hosts an HTTP server to handle user frontend password requests\n"); + printf("\n"); + + printf("Usage:\n"); + printf(" pgagroal-vault [ -c CONFIG_FILE ] [ -u USERS_FILE ] \n"); + printf("\n"); + printf("Options:\n"); + printf(" -c, --config CONFIG_FILE Set the path to the pgagroal_vault.conf file\n"); + printf(" Default: %s\n", PGAGROAL_DEFAULT_VAULT_CONF_FILE); + printf(" -u, --users USERS_FILE Set the password for the admin user of management port\n"); + printf(" -?, --help Display help\n"); + printf("\n"); + printf("pgagroal: %s\n", PGAGROAL_HOMEPAGE); + printf("Report bugs: %s\n", PGAGROAL_ISSUES); +} + +int +main(int argc, char** argv) +{ + int ret; + int exit_code = 0; + char* configuration_path = NULL; + char* users_path = NULL; + struct signal_info signal_watcher[1]; // Can add more + int c; + int option_index = 0; + size_t size; + struct vault_configuration* config = NULL; + char message[MISC_LENGTH]; // a generic message used for errors + + while (1) + { + static struct option long_options[] = + { + {"config", required_argument, 0, 'c'}, + {"users", required_argument, 0, 'u'}, + {"help", no_argument, 0, '?'} + }; + + c = getopt_long(argc, argv, "?c:u:", + long_options, &option_index); + + if (c == -1) + { + break; + } + + switch (c) + { + case 'c': + configuration_path = optarg; + break; + case 'u': + users_path = optarg; + break; + case '?': + usage(); + exit(1); + break; + default: + break; + } + } + + if (getuid() == 0) + { + errx(1, "pgagroal-vault: Using the root account is not allowed"); + } + + size = sizeof(struct vault_configuration); + if (pgagroal_create_shared_memory(size, HUGEPAGE_OFF, &shmem)) + { + errx(1, "pgagroal-vault: Error creating shared memory"); + } + + memset(message, 0, MISC_LENGTH); + + pgagroal_vault_init_configuration(shmem); + config = (struct vault_configuration*)shmem; + + configuration_path = configuration_path != NULL ? configuration_path : PGAGROAL_DEFAULT_VAULT_CONF_FILE; + if ((ret = pgagroal_vault_read_configuration(shmem, configuration_path, false)) != PGAGROAL_CONFIGURATION_STATUS_OK) + { + // the configuration has some problem, build up a descriptive message + if (ret == PGAGROAL_CONFIGURATION_STATUS_FILE_NOT_FOUND) + { + snprintf(message, MISC_LENGTH, "Configuration file not found"); + } + else if (ret == PGAGROAL_CONFIGURATION_STATUS_FILE_TOO_BIG) + { + snprintf(message, MISC_LENGTH, "Too many sections"); + } + else if (ret == PGAGROAL_CONFIGURATION_STATUS_KO) + { + snprintf(message, MISC_LENGTH, "Invalid configuration file"); + } + else if (ret > 0) + { + snprintf(message, MISC_LENGTH, "%d problematic or duplicated section%c", + ret, + ret > 1 ? 's' : ' '); + } + + errx(1, "pgagroal-vault: %s (file <%s>)", message, configuration_path); + } + + memcpy(&config->common.configuration_path[0], configuration_path, MIN(strlen(configuration_path), MAX_PATH - 1)); + + if (pgagroal_init_logging()) + { + exit(1); + } + + if (pgagroal_start_logging()) + { + errx(1, "Failed to start logging"); + } + + if (pgagroal_vault_validate_configuration(shmem)) + { + errx(1, "pgagroal-vault: Invalid VAULT configuration"); + } + + config = (struct vault_configuration*)shmem; + + // -- Read the USERS file -- +read_users_path: + if (users_path != NULL) + { + memset(message, 0, MISC_LENGTH); + ret = pgagroal_vault_read_users_configuration(shmem, users_path); + if (ret == PGAGROAL_CONFIGURATION_STATUS_FILE_NOT_FOUND) + { + + snprintf(message, MISC_LENGTH, "USERS configuration file not found"); + errx(1, "pgagroal-vault: %s (file <%s>)", message, users_path); + } + else if (ret == PGAGROAL_CONFIGURATION_STATUS_CANNOT_DECRYPT) + { + errx(1, "pgagroal-vault: Invalid entry in the file"); + } + else if (ret == PGAGROAL_CONFIGURATION_STATUS_FILE_TOO_BIG) + { + snprintf(message, MISC_LENGTH, "Too many users defined %d (max %d)", config->number_of_users, NUMBER_OF_ADMINS); + errx(1, "pgagroal-vault: %s (file <%s>)", message, users_path); + } + else if (ret == PGAGROAL_CONFIGURATION_STATUS_OK) + { + memcpy(&config->users_path[0], users_path, MIN(strlen(users_path), MAX_PATH - 1)); + } + } + else + { + // the user did not specify a file on the command line + // so try the default one and allow it to be missing + users_path = PGAGROAL_DEFAULT_VAULT_USERS_FILE; + goto read_users_path; + } + + // -- Bind & Listen at the given hostname and port -- + + if (pgagroal_bind(config->common.host, config->common.port, &server_fd, &server_fds_length, false, &default_buffer_size, false, -1)) + { + errx(1, "pgagroal-vault: Could not bind to %s:%d", config->common.host, config->common.port); + } + + // -- Initialize the watcher and start loop -- + main_loop = ev_default_loop(0); + + if (!main_loop) + { + errx(1, "pgagroal-vault: No loop implementation"); + } + + ev_signal_init((struct ev_signal*)&signal_watcher[0], shutdown_cb, SIGTERM); + + for (int i = 0; i < 1; i++) + { + signal_watcher[i].slot = -1; + ev_signal_start(main_loop, (struct ev_signal*)&signal_watcher[i]); + } + + start_vault_io(); + + pgagroal_log_info("pgagroal-vault %s: Started on %s:%d", + PGAGROAL_VERSION, + config->common.host, + config->common.port); + + while (keep_running) + { + ev_loop(main_loop, 0); + } + + pgagroal_log_info("pgagroal-vault: shutdown"); + // -- Free all memory -- + pgagroal_stop_logging(); + pgagroal_destroy_shared_memory(shmem, size); + free(server_fd); + + return exit_code; +} + +static void +shutdown_cb(struct ev_loop* loop, ev_signal* w, int revents) +{ + pgagroal_log_debug("pgagroal-vault: Shutdown requested"); + ev_break(loop, EVBREAK_ALL); + keep_running = 0; +} + +static void +accept_vault_cb(struct ev_loop* loop, struct ev_io* watcher, int revents) +{ + struct sockaddr_in6 client_addr; + socklen_t client_addr_length; + int client_fd; + char address[INET6_ADDRSTRLEN]; + pid_t pid; + struct vault_configuration* config; + + if (EV_ERROR & revents) + { + pgagroal_log_debug("accept_vault_cb: Invalid event: %s", strerror(errno)); + errno = 0; + return; + } + + config = (struct vault_configuration*)shmem; + + memset(&address, 0, sizeof(address)); + + client_addr_length = sizeof(client_addr); + client_fd = accept(watcher->fd, (struct sockaddr*)&client_addr, &client_addr_length); + + if (client_fd == -1) + { + if (accept_fatal(errno) && keep_running) + { + pgagroal_log_warn("accept_vault_cb: Restarting listening port due to: %s (%d)", strerror(errno), watcher->fd); + + shutdown_vault_io(); + + free(server_fd); + server_fd = NULL; + + if (pgagroal_bind(config->common.host, config->common.port, &server_fd, &server_fds_length, false, &default_buffer_size, false, -1)) + { + pgagroal_log_fatal("pgagroal-vault: Could not bind to %s:%d", config->common.host, config->common.port); + exit(1); + } + + if (!fork()) + { + shutdown_vault_io(); + } + + start_vault_io(); + pgagroal_log_debug("Socket: %d", *server_fd); + } + else + { + pgagroal_log_debug("accept: %s (%d)", strerror(errno), watcher->fd); + } + errno = 0; + return; + } + pgagroal_get_address((struct sockaddr*)&client_addr, (char*)&address, sizeof(address)); + + pgagroal_log_trace("accept_vault_cb: client address: %s", address); + + pid = fork(); + if (pid == -1) + { + /* No process */ + pgagroal_log_error("accept_vault_cb: Couldn't create process"); + } + else if (pid == 0) + { + char* addr = calloc(1, strlen(address) + 1); + if (addr == NULL) + { + pgagroal_log_fatal("accept_vault_cb: Couldn't allocate memory for client address"); + return; + } + memcpy(addr, address, strlen(address)); + + ev_loop_fork(loop); + shutdown_vault_io(); + + if (router(client_fd, NULL)) + { + pgagroal_log_error("Couldn't write to client"); + exit(1); + } + + exit(0); + } + + pgagroal_disconnect(client_fd); +} + +static bool +accept_fatal(int error) +{ + switch (error) + { + case EAGAIN: + case ENETDOWN: + case EPROTO: + case ENOPROTOOPT: + case EHOSTDOWN: +#ifdef HAVE_LINUX + case ENONET: +#endif + case EHOSTUNREACH: + case EOPNOTSUPP: + case ENETUNREACH: + return false; + break; + } + + return true; +} \ No newline at end of file