From 8df2d941d98fc28446b9ece8479821260a6f302f Mon Sep 17 00:00:00 2001 From: Deepika Shanmugam Date: Fri, 15 Mar 2024 15:53:18 +0100 Subject: [PATCH 1/7] Add a new parameter to have an option to choose TCP socket creation --- app/dockerdwrapperwithcompose.c | 56 +++++++++++++++++++++++---------- app/manifest.json | 7 ++++- 2 files changed, 46 insertions(+), 17 deletions(-) diff --git a/app/dockerdwrapperwithcompose.c b/app/dockerdwrapperwithcompose.c index 6a8412f..9972028 100644 --- a/app/dockerdwrapperwithcompose.c +++ b/app/dockerdwrapperwithcompose.c @@ -250,13 +250,15 @@ start_dockerd(void) char *use_sd_card_value = get_parameter_value("SDCardSupport"); char *use_tls_value = get_parameter_value("UseTLS"); char *use_ipc_socket_value = get_parameter_value("IPCSocket"); + char *use_tcp_socket_value = get_parameter_value("TCPSocket"); if (use_sd_card_value == NULL || use_tls_value == NULL || - use_ipc_socket_value == NULL) { + use_ipc_socket_value == NULL || use_tcp_socket_value == NULL) { goto end; } bool use_sdcard = strcmp(use_sd_card_value, "yes") == 0; bool use_tls = strcmp(use_tls_value, "yes") == 0; bool use_ipc_socket = strcmp(use_ipc_socket_value, "yes") == 0; + bool use_tcp_socket = strcmp(use_tcp_socket_value, "yes") == 0; if (use_sdcard) { // Confirm that the SD card is usable @@ -326,27 +328,48 @@ start_dockerd(void) goto end; } - args_offset += g_snprintf(args + args_offset, - args_len - args_offset, - " %s %s %s %s %s %s %s %s", - "-H tcp://0.0.0.0:2376", - "--tlsverify", - "--tlscacert", - ca_path, - "--tlscert", - cert_path, - "--tlskey", - key_path); - - g_strlcat(msg, " in TLS mode", msg_len); - } else { + if (use_tcp_socket) { + args_offset += g_snprintf(args + args_offset, + args_len - args_offset, + " %s %s %s %s %s %s %s %s", + "-H tcp://0.0.0.0:2376", + "--tlsverify", + "--tlscacert", + ca_path, + "--tlscert", + cert_path, + "--tlskey", + key_path); + + g_strlcat(msg, " in TLS mode with TCP socket", msg_len); + } else { + args_offset += g_snprintf(args + args_offset, + args_len - args_offset, + " %s %s %s %s %s %s %s", + "--tlsverify", + "--tlscacert", + ca_path, + "--tlscert", + cert_path, + "--tlskey", + key_path); + + g_strlcat(msg, " in TLS mode without TCP socket", msg_len); + } + } else if (!use_tls && use_tcp_socket) { args_offset += g_snprintf(args + args_offset, args_len - args_offset, " %s %s", "-H tcp://0.0.0.0:2375", "--tls=false"); - g_strlcat(msg, " in unsecured mode", msg_len); + g_strlcat(msg, " in unsecured mode with TCP socket", msg_len); + } else { + // Without TLS and without TCP socket + args_offset += g_snprintf( + args + args_offset, args_len - args_offset, " %s", "--tls=false"); + + g_strlcat(msg, " in unsecured mode without TCP socket", msg_len); } if (use_sdcard) { @@ -409,6 +432,7 @@ start_dockerd(void) free(use_sd_card_value); free(use_tls_value); free(use_ipc_socket_value); + free(use_tcp_socket_value); g_clear_error(&error); return return_value; diff --git a/app/manifest.json b/app/manifest.json index 490b458..276f7dc 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -30,13 +30,18 @@ }, { "name": "UseTLS", - "default": "yes", + "default": "no", "type": "enum:no|No, yes|Yes" }, { "name": "IPCSocket", "default": "yes", "type": "enum:no|No, yes|Yes" + }, + { + "name": "TCPSocket", + "default": "no", + "type": "enum:no|No, yes|Yes" } ] } From e61911dbd55936516bab918622f0b2cc009dcc01 Mon Sep 17 00:00:00 2001 From: Deepika Shanmugam Date: Mon, 18 Mar 2024 16:50:44 +0100 Subject: [PATCH 2/7] Update Readme file --- README.md | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index ad71ede..6ed282c 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ this is the recommended way to install this ACAP. > Meanwhile, the solution is to allow root to be able to install the Docker Compose ACAP. > > On the web page of the device: +> > 1. Go to the Apps page, toggle on `Allow root-privileged apps`. > 1. Go to System -> Account page, under SSH accounts toggle off `Restrict root access` to be able to send the TLS certificates. Make sure to set the password of the `root` SSH user. @@ -76,12 +77,13 @@ It's also possible to build and use a locally built image. See the ## Securing the Docker Compose ACAP using TLS -The Docker Compose ACAP can be run either unsecured or in TLS mode. The Docker Compose ACAP uses -TLS as default. Use the "Use TLS" dropdown in the web interface to switch -between the two different modes. It's also possible to toggle this option by -calling the parameter management API in [VAPIX](https://www.axis.com/vapix-library/) and setting the -`root.dockerdwrapperwithcompose.UseTLS` parameter to `yes` or `no`. The following commands would -enable TLS: +The Docker Compose ACAP can be run either unsecured mode or in TLS mode with or without TCP socket. +The Docker Compose ACAP use unsecured mode without TCP socket creation as default. Use the "Use TLS" +and "TCP Socket" dropdowns in the web interface to switch between the two different modes(yes/no). It's +also possible to toggle this option by calling the parameter management API in +[VAPIX](https://www.axis.com/vapix-library/) and setting the `root.dockerdwrapperwithcompose.UseTLS` +parameter to `yes` or `no` and `root.dockerdwrapperwithcompose.TCPSocket` parameter to `yes` or `no`. +The following commands would enable TLS: ```sh DEVICE_IP= @@ -91,6 +93,13 @@ curl -s --anyauth -u "root:$DEVICE_PASSWORD" \ "http://$DEVICE_IP/axis-cgi/param.cgi?action=update&root.dockerdwrapperwithcompose.UseTLS=yes" ``` +The following command would enable TCP Socket: + +```sh +curl -s --anyauth -u "root:$DEVICE_PASSWORD" \ + "http://$DEVICE_IP/axis-cgi/param.cgi?action=update&root.dockerdwrapperwithcompose.TCPSocket=yes" +``` + Note that the dockerd service will be restarted every time TLS is activated or deactivated. Running the ACAP using TLS requires some additional setup, see next chapter. Running the ACAP without TLS requires no further setup. From 3d16a12c4f05c322df1b9eaa400b0495f915f5c2 Mon Sep 17 00:00:00 2001 From: Deepika Shanmugam Date: Mon, 18 Mar 2024 17:10:45 +0100 Subject: [PATCH 3/7] Update Readme file --- README.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6ed282c..cef3898 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,8 @@ It's also possible to build and use a locally built image. See the ## Securing the Docker Compose ACAP using TLS The Docker Compose ACAP can be run either unsecured mode or in TLS mode with or without TCP socket. -The Docker Compose ACAP use unsecured mode without TCP socket creation as default. Use the "Use TLS" +The Docker Compose ACAP use unsecured mode without TCP socket creation as default. There is an option +to create TCP socket, if you need to access the Docker daemon remotely. Use the "Use TLS" and "TCP Socket" dropdowns in the web interface to switch between the two different modes(yes/no). It's also possible to toggle this option by calling the parameter management API in [VAPIX](https://www.axis.com/vapix-library/) and setting the `root.dockerdwrapperwithcompose.UseTLS` @@ -235,11 +236,20 @@ more information. Below is an example of how to remotely run a docker command on an Axis device running the Docker Compose ACAP in unsecured mode: +With TCP Socket: + ```sh DOCKER_INSECURE_PORT=2375 docker -H=:$DOCKER_INSECURE_PORT version ``` +Below is an example of how to remotely run a docker command on an Axis device running +the Docker Compose ACAP in unsecured mode with IPC socket: + +```sh +docker -H unix:///var/run/docker.sock version +``` + See [Client key and certificate](#client-key-and-certificate) for an example of how to remotely run docker commands on a device running a secured Docker Compose ACAP using TLS. From 4fa48d12c6ac2baaeec9854dea9ec13a50bb304b Mon Sep 17 00:00:00 2001 From: Deepika Shanmugam Date: Tue, 19 Mar 2024 14:59:26 +0100 Subject: [PATCH 4/7] Ensure that TLS mode is only active when TCP socket is set to "yes" --- README.md | 37 ++++++++++++++------ app/dockerdwrapperwithcompose.c | 62 ++++++++++++++------------------- 2 files changed, 53 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index cef3898..66b431e 100644 --- a/README.md +++ b/README.md @@ -77,30 +77,45 @@ It's also possible to build and use a locally built image. See the ## Securing the Docker Compose ACAP using TLS -The Docker Compose ACAP can be run either unsecured mode or in TLS mode with or without TCP socket. -The Docker Compose ACAP use unsecured mode without TCP socket creation as default. There is an option -to create TCP socket, if you need to access the Docker daemon remotely. Use the "Use TLS" -and "TCP Socket" dropdowns in the web interface to switch between the two different modes(yes/no). It's -also possible to toggle this option by calling the parameter management API in -[VAPIX](https://www.axis.com/vapix-library/) and setting the `root.dockerdwrapperwithcompose.UseTLS` -parameter to `yes` or `no` and `root.dockerdwrapperwithcompose.TCPSocket` parameter to `yes` or `no`. -The following commands would enable TLS: +The Docker Compose ACAP can be run in either TLS mode or unsecured mode. The Docker Compose ACAP +uses unsecured mode by default. There is an option to choose between "TCPSocket" and "IPCSocket" socket +parameters. The API listens to IPC socket by default, even if the "IPCSocket" parameter is set to 'no'. +The TLS mode can be used with a TCP socket, as well as with or without an IPC socket. When the parameter +"TCPSocket" is set to 'no', the parameter "UseTLS" will also be set to 'no'. + +Use the "Use TLS", "TCP Socket" and "IPC Socket" dropdowns in the web interface to switch between the +two different modes(yes/no). Whenever these settings change, the Docker daemon will automatically restart. +It's also possible to toggle this option by calling the parameter management API in [VAPIX](https://www.axis.com/vapix-library/) +and setting `root.dockerdwrapperwithcompose.UseTLS`, `root.dockerdwrapperwithcompose.TCPSocket` and +`root.dockerdwrapperwithcompose.IPCSocket` parameters to `yes` or `no`. The following commands would +enable those parameters: ```sh DEVICE_IP= DEVICE_PASSWORD='' +``` + +Enable TLS: +```sh curl -s --anyauth -u "root:$DEVICE_PASSWORD" \ "http://$DEVICE_IP/axis-cgi/param.cgi?action=update&root.dockerdwrapperwithcompose.UseTLS=yes" ``` -The following command would enable TCP Socket: +Enable TCP Socket: ```sh curl -s --anyauth -u "root:$DEVICE_PASSWORD" \ "http://$DEVICE_IP/axis-cgi/param.cgi?action=update&root.dockerdwrapperwithcompose.TCPSocket=yes" ``` +Enable IPC Socket: + +```sh +curl -s --anyauth -u "root:$DEVICE_PASSWORD" \ + "http://$DEVICE_IP/axis-cgi/param.cgi?action=update&root.dockerdwrapperwithcompose.IPCSocket=yes" +``` + Note that the dockerd service will be restarted every time TLS is activated or deactivated. Running the ACAP using TLS requires some additional setup, see next chapter. Running the ACAP without TLS requires no further setup. @@ -234,7 +249,7 @@ port 2376 when running secured using TLS. Please read section [Securing the Docker Compose ACAP using TLS](#securing-the-docker-compose-acap-using-tls) for more information. Below is an example of how to remotely run a docker command on an Axis device running -the Docker Compose ACAP in unsecured mode: +the Docker Compose ACAP in unsecured mode with TCP socket: With TCP Socket: @@ -243,6 +258,8 @@ DOCKER_INSECURE_PORT=2375 docker -H=:$DOCKER_INSECURE_PORT version ``` +With IPC Socket: + Below is an example of how to remotely run a docker command on an Axis device running the Docker Compose ACAP in unsecured mode with IPC socket: diff --git a/app/dockerdwrapperwithcompose.c b/app/dockerdwrapperwithcompose.c index 9972028..3e7cef0 100644 --- a/app/dockerdwrapperwithcompose.c +++ b/app/dockerdwrapperwithcompose.c @@ -296,7 +296,7 @@ start_dockerd(void) g_strlcpy(msg, "Starting dockerd", msg_len); - if (use_tls) { + if (use_tcp_socket && use_tls) { const char *ca_path = "/usr/local/packages/dockerdwrapperwithcompose/ca.pem"; const char *cert_path = @@ -328,35 +328,21 @@ start_dockerd(void) goto end; } - if (use_tcp_socket) { - args_offset += g_snprintf(args + args_offset, - args_len - args_offset, - " %s %s %s %s %s %s %s %s", - "-H tcp://0.0.0.0:2376", - "--tlsverify", - "--tlscacert", - ca_path, - "--tlscert", - cert_path, - "--tlskey", - key_path); - - g_strlcat(msg, " in TLS mode with TCP socket", msg_len); - } else { - args_offset += g_snprintf(args + args_offset, - args_len - args_offset, - " %s %s %s %s %s %s %s", - "--tlsverify", - "--tlscacert", - ca_path, - "--tlscert", - cert_path, - "--tlskey", - key_path); - - g_strlcat(msg, " in TLS mode without TCP socket", msg_len); - } - } else if (!use_tls && use_tcp_socket) { + args_offset += g_snprintf(args + args_offset, + args_len - args_offset, + " %s %s %s %s %s %s %s %s", + "-H tcp://0.0.0.0:2376", + "--tlsverify", + "--tlscacert", + ca_path, + "--tlscert", + cert_path, + "--tlskey", + key_path); + + g_strlcat(msg, " in TLS mode with TCP socket", msg_len); + + } else if (use_tcp_socket && !use_tls) { args_offset += g_snprintf(args + args_offset, args_len - args_offset, " %s %s", @@ -364,12 +350,9 @@ start_dockerd(void) "--tls=false"); g_strlcat(msg, " in unsecured mode with TCP socket", msg_len); - } else { - // Without TLS and without TCP socket - args_offset += g_snprintf( - args + args_offset, args_len - args_offset, " %s", "--tls=false"); - - g_strlcat(msg, " in unsecured mode without TCP socket", msg_len); + } else if (!use_tcp_socket && use_tls) { + syslog(LOG_WARNING, "Set UseTLS as 'no' when TCP socket is set as 'no'."); + goto end; } if (use_sdcard) { @@ -392,6 +375,7 @@ start_dockerd(void) g_strlcat(msg, " with IPC socket.", msg_len); } else { + // By default, API listens on IPC socket even if it's set to 'no' g_strlcat(msg, " without IPC socket.", msg_len); } @@ -538,6 +522,12 @@ parameter_changed_callback(const gchar *name, } else if (strcmp(parname, "UseTLS") == 0) { syslog(LOG_INFO, "UseTLS changed to: %s", value); restart_dockerd = true; + } else if (strcmp(parname, "TCPSocket") == 0) { + syslog(LOG_INFO, "TCPSocket changed to: %s", value); + restart_dockerd = true; + } else if (strcmp(parname, "IPCSocket") == 0) { + syslog(LOG_INFO, "IPCSocket changed to: %s", value); + restart_dockerd = true; } else { syslog(LOG_WARNING, "Parameter %s is not recognized", name); restart_dockerd = false; From b51517ce0a968929616faf17546ce50846cf26c6 Mon Sep 17 00:00:00 2001 From: Deepika Shanmugam Date: Tue, 19 Mar 2024 15:29:05 +0100 Subject: [PATCH 5/7] Removing unneccessary content --- README.md | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 66b431e..8bb6594 100644 --- a/README.md +++ b/README.md @@ -79,9 +79,8 @@ It's also possible to build and use a locally built image. See the The Docker Compose ACAP can be run in either TLS mode or unsecured mode. The Docker Compose ACAP uses unsecured mode by default. There is an option to choose between "TCPSocket" and "IPCSocket" socket -parameters. The API listens to IPC socket by default, even if the "IPCSocket" parameter is set to 'no'. -The TLS mode can be used with a TCP socket, as well as with or without an IPC socket. When the parameter -"TCPSocket" is set to 'no', the parameter "UseTLS" will also be set to 'no'. +parameters. The TLS mode can be used with a TCP socket, as well as with or without an IPC socket. When +the parameter "TCPSocket" is set to 'no', the parameter "UseTLS" will also be set to 'no'. Use the "Use TLS", "TCP Socket" and "IPC Socket" dropdowns in the web interface to switch between the two different modes(yes/no). Whenever these settings change, the Docker daemon will automatically restart. @@ -249,24 +248,13 @@ port 2376 when running secured using TLS. Please read section [Securing the Docker Compose ACAP using TLS](#securing-the-docker-compose-acap-using-tls) for more information. Below is an example of how to remotely run a docker command on an Axis device running -the Docker Compose ACAP in unsecured mode with TCP socket: - -With TCP Socket: +the Docker Compose ACAP in unsecured mode: ```sh DOCKER_INSECURE_PORT=2375 docker -H=:$DOCKER_INSECURE_PORT version ``` -With IPC Socket: - -Below is an example of how to remotely run a docker command on an Axis device running -the Docker Compose ACAP in unsecured mode with IPC socket: - -```sh -docker -H unix:///var/run/docker.sock version -``` - See [Client key and certificate](#client-key-and-certificate) for an example of how to remotely run docker commands on a device running a secured Docker Compose ACAP using TLS. From f2136d6bf50fbef007a4144c64ec8f729e13de09 Mon Sep 17 00:00:00 2001 From: Deepika Shanmugam Date: Wed, 20 Mar 2024 11:49:53 +0100 Subject: [PATCH 6/7] Dont't start dockerd when no sockets revert TLS runs with IPC --- README.md | 8 +++---- app/dockerdwrapperwithcompose.c | 40 +++++++++++++++++---------------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 8bb6594..3a60147 100644 --- a/README.md +++ b/README.md @@ -77,10 +77,10 @@ It's also possible to build and use a locally built image. See the ## Securing the Docker Compose ACAP using TLS -The Docker Compose ACAP can be run in either TLS mode or unsecured mode. The Docker Compose ACAP -uses unsecured mode by default. There is an option to choose between "TCPSocket" and "IPCSocket" socket -parameters. The TLS mode can be used with a TCP socket, as well as with or without an IPC socket. When -the parameter "TCPSocket" is set to 'no', the parameter "UseTLS" will also be set to 'no'. +The Docker Compose ACAP can be run in either TLS mode or unsecured mode. The Docker Compose ACAP uses +unsecured mode by default.These modes can be used with or without TCP and IPC sockets.There is an option +to choose between "TCPSocket" and "IPCSocket" socket parameters. It should be noted that if TCP and IPC +sockets are not enabled, Dockerd will not start. Use the "Use TLS", "TCP Socket" and "IPC Socket" dropdowns in the web interface to switch between the two different modes(yes/no). Whenever these settings change, the Docker daemon will automatically restart. diff --git a/app/dockerdwrapperwithcompose.c b/app/dockerdwrapperwithcompose.c index 3e7cef0..ca3509f 100644 --- a/app/dockerdwrapperwithcompose.c +++ b/app/dockerdwrapperwithcompose.c @@ -296,7 +296,7 @@ start_dockerd(void) g_strlcpy(msg, "Starting dockerd", msg_len); - if (use_tcp_socket && use_tls) { + if (use_tls) { const char *ca_path = "/usr/local/packages/dockerdwrapperwithcompose/ca.pem"; const char *cert_path = @@ -327,21 +327,21 @@ start_dockerd(void) if (!ca_exists || !cert_exists || !key_exists) { goto end; } - - args_offset += g_snprintf(args + args_offset, - args_len - args_offset, - " %s %s %s %s %s %s %s %s", - "-H tcp://0.0.0.0:2376", - "--tlsverify", - "--tlscacert", - ca_path, - "--tlscert", - cert_path, - "--tlskey", - key_path); - - g_strlcat(msg, " in TLS mode with TCP socket", msg_len); - + if (use_tcp_socket) { + args_offset += g_snprintf(args + args_offset, + args_len - args_offset, + " %s %s %s %s %s %s %s %s", + "-H tcp://0.0.0.0:2376", + "--tlsverify", + "--tlscacert", + ca_path, + "--tlscert", + cert_path, + "--tlskey", + key_path); + + g_strlcat(msg, " in TLS mode with TCP socket", msg_len); + } } else if (use_tcp_socket && !use_tls) { args_offset += g_snprintf(args + args_offset, args_len - args_offset, @@ -350,9 +350,6 @@ start_dockerd(void) "--tls=false"); g_strlcat(msg, " in unsecured mode with TCP socket", msg_len); - } else if (!use_tcp_socket && use_tls) { - syslog(LOG_WARNING, "Set UseTLS as 'no' when TCP socket is set as 'no'."); - goto end; } if (use_sdcard) { @@ -374,6 +371,11 @@ start_dockerd(void) "-H unix:///var/run/docker.sock"); g_strlcat(msg, " with IPC socket.", msg_len); + } else if (!use_ipc_socket && !use_tcp_socket) { + syslog(LOG_WARNING, + "Dockerd fails to start. Either IPC socket or TCP socket should be " + "selected."); + goto end; } else { // By default, API listens on IPC socket even if it's set to 'no' g_strlcat(msg, " without IPC socket.", msg_len); From 135e5c5b9965cb4ee35b3e96384baf3fef9d5db5 Mon Sep 17 00:00:00 2001 From: Deepika Shanmugam Date: Fri, 22 Mar 2024 13:03:07 +0100 Subject: [PATCH 7/7] Update based on the latest refactoring --- README.md | 21 +- app/dockerdwrapperwithcompose.c | 388 +++++++++++++++++++++----------- app/manifest.json | 2 +- 3 files changed, 269 insertions(+), 142 deletions(-) diff --git a/README.md b/README.md index 3a60147..b99170d 100644 --- a/README.md +++ b/README.md @@ -77,17 +77,15 @@ It's also possible to build and use a locally built image. See the ## Securing the Docker Compose ACAP using TLS -The Docker Compose ACAP can be run in either TLS mode or unsecured mode. The Docker Compose ACAP uses -unsecured mode by default.These modes can be used with or without TCP and IPC sockets.There is an option -to choose between "TCPSocket" and "IPCSocket" socket parameters. It should be noted that if TCP and IPC -sockets are not enabled, Dockerd will not start. +The Docker Compose ACAP application can be run in either TLS mode or unsecured mode. The Docker Compose +ACAP application uses TLS mode by default. These modes can be used with or without TCP and IPC sockets. +It should be noted that if TCP and IPC sockets are not enabled, Dockerd will not start. -Use the "Use TLS", "TCP Socket" and "IPC Socket" dropdowns in the web interface to switch between the +Use the "Use TLS" and "TCP Socket" dropdowns in the web interface to switch between the two different modes(yes/no). Whenever these settings change, the Docker daemon will automatically restart. It's also possible to toggle this option by calling the parameter management API in [VAPIX](https://www.axis.com/vapix-library/) -and setting `root.dockerdwrapperwithcompose.UseTLS`, `root.dockerdwrapperwithcompose.TCPSocket` and -`root.dockerdwrapperwithcompose.IPCSocket` parameters to `yes` or `no`. The following commands would -enable those parameters: +and setting `root.dockerdwrapperwithcompose.UseTLS` and `root.dockerdwrapperwithcompose.TCPSocket` parameters +to `yes` or `no`. The following commands would enable those parameters: ```sh DEVICE_IP= @@ -108,13 +106,6 @@ curl -s --anyauth -u "root:$DEVICE_PASSWORD" \ "http://$DEVICE_IP/axis-cgi/param.cgi?action=update&root.dockerdwrapperwithcompose.TCPSocket=yes" ``` -Enable IPC Socket: - -```sh -curl -s --anyauth -u "root:$DEVICE_PASSWORD" \ - "http://$DEVICE_IP/axis-cgi/param.cgi?action=update&root.dockerdwrapperwithcompose.IPCSocket=yes" -``` - Note that the dockerd service will be restarted every time TLS is activated or deactivated. Running the ACAP using TLS requires some additional setup, see next chapter. Running the ACAP without TLS requires no further setup. diff --git a/app/dockerdwrapperwithcompose.c b/app/dockerdwrapperwithcompose.c index ca3509f..f24419c 100644 --- a/app/dockerdwrapperwithcompose.c +++ b/app/dockerdwrapperwithcompose.c @@ -25,6 +25,13 @@ #include #include +struct settings { + bool use_sdcard; + bool use_tls; + bool use_tcp_socket; + bool use_ipc_socket; +}; + /** * @brief Callback called when the dockerd process exits. */ @@ -48,6 +55,19 @@ static const char *sd_card_path = "/var/spool/storage/SD_DISK"; // True if the dockerd_exited_callback should restart dockerd static bool restart_dockerd = false; +// All ax_parameters the acap has +static const char *ax_parameters[] = {"IPCSocket", + "SDCardSupport", + "TCPSocket", + "UseTLS"}; + +static const char *tls_cert_path = + "/usr/local/packages/dockerdwrapperwithcompose/"; + +static const char *tls_certs[] = {"ca.pem", + "server-cert.pem", + "server-key.pem"}; + /** * @brief Signals handling * @@ -227,13 +247,205 @@ setup_sdcard(void) } /** - * @brief Start a new dockerd process. + * @brief Gets and verifies the SDCardSupport selection * - * @return True if successful, false otherwise + * @param use_sdcard_ret selection to be updated. + * @return True if successful, false otherwise. + */ +static gboolean +get_and_verify_sd_card_selection(bool *use_sdcard_ret) +{ + gboolean return_value = false; + bool use_sdcard = *use_sdcard_ret; + char *use_sd_card_value = get_parameter_value("SDCardSupport"); + char *sd_file_system = NULL; + + if (use_sd_card_value != NULL) { + bool use_sdcard = strcmp(use_sd_card_value, "yes") == 0; + if (use_sdcard) { + // Confirm that the SD card is usable + sd_file_system = get_sd_filesystem(); + if (sd_file_system == NULL) { + syslog(LOG_ERR, + "Couldn't identify the file system of the SD card at %s", + sd_card_path); + goto end; + } + + if (strcmp(sd_file_system, "vfat") == 0 || + strcmp(sd_file_system, "exfat") == 0) { + syslog(LOG_ERR, + "The SD card at %s uses file system %s which does not support " + "Unix file permissions. Please reformat to a file system that " + "support Unix file permissions, such as ext4 or xfs.", + sd_card_path, + sd_file_system); + goto end; + } + + gchar card_path[100]; + g_stpcpy(card_path, sd_card_path); + g_strlcat(card_path, "/dockerd", 100); + + if (access(card_path, F_OK) == 0 && access(card_path, W_OK) != 0) { + syslog( + LOG_ERR, + "The application user does not have write permissions to the SD " + "card directory at %s. Please change the directory permissions or " + "remove the directory.", + card_path); + goto end; + } + + if (!setup_sdcard()) { + syslog(LOG_ERR, "Failed to setup SD card."); + goto end; + } + } + *use_sdcard_ret = use_sdcard; + return_value = true; + } +end: + free(use_sd_card_value); + free(sd_file_system); + return return_value; +} + +/** + * @brief Gets and verifies the UseTLS selection + * + * @param use_tls_ret selection to be updated. + * @return True if successful, false otherwise. + */ +static gboolean +get_and_verify_tls_selection(bool *use_tls_ret) +{ + gboolean return_value = false; + bool use_tls = *use_tls_ret; + char *ca_path = NULL; + char *cert_path = NULL; + char *key_path = NULL; + + char *use_tls_value = get_parameter_value("UseTLS"); + if (use_tls_value != NULL) { + use_tls = strcmp(use_tls_value, "yes") == 0; + if (use_tls) { + char *ca_path = g_strdup_printf("%s%s", tls_cert_path, tls_certs[0]); + char *cert_path = g_strdup_printf("%s%s", tls_cert_path, tls_certs[1]); + char *key_path = g_strdup_printf("%s%s", tls_cert_path, tls_certs[2]); + + bool ca_exists = access(ca_path, F_OK) == 0; + bool cert_exists = access(cert_path, F_OK) == 0; + bool key_exists = access(key_path, F_OK) == 0; + + if (!ca_exists || !cert_exists || !key_exists) { + syslog(LOG_ERR, "One or more TLS certificates missing."); + } + + if (!ca_exists) { + syslog(LOG_ERR, + "Cannot start using TLS, no CA certificate found at %s", + ca_path); + } + if (!cert_exists) { + syslog(LOG_ERR, + "Cannot start using TLS, no server certificate found at %s", + cert_path); + } + if (!key_exists) { + syslog(LOG_ERR, + "Cannot start using TLS, no server key found at %s", + key_path); + } + + if (!ca_exists || !cert_exists || !key_exists) { + goto end; + } + } + *use_tls_ret = use_tls; + return_value = true; + } +end: + free(use_tls_value); + free(ca_path); + free(cert_path); + free(key_path); + return return_value; +} + +/** + * @brief Gets and verifies the TCPSocket selection + * + * @param use_tcp_socket_ret selection to be updated. + * @return True if successful, false otherwise. */ +static gboolean +get_tcp_socket_selection(bool *use_tcp_socket_ret) +{ + gboolean return_value = false; + bool use_tcp_socket = *use_tcp_socket_ret; + char *use_tcp_socket_value = get_parameter_value("TCPSocket"); + if (use_tcp_socket_value != NULL) { + use_tcp_socket = strcmp(use_tcp_socket_value, "yes") == 0; + *use_tcp_socket_ret = use_tcp_socket; + return_value = true; + } + free(use_tcp_socket_value); + return return_value; +} + +/** + * @brief Gets and verifies the IPCSocket selection + * + * @param use_ipc_socket_ret selection to be updated. + * @return True if successful, false otherwise. + */ +static gboolean +get_ipc_socket_selection(bool *use_ipc_socket_ret) +{ + gboolean return_value = false; + bool use_ipc_socket = *use_ipc_socket_ret; + char *use_ipc_socket_value = get_parameter_value("IPCSocket"); + if (use_ipc_socket_value != NULL) { + use_ipc_socket = strcmp(use_ipc_socket_value, "yes") == 0; + *use_ipc_socket_ret = use_ipc_socket; + return_value = true; + } + free(use_ipc_socket_value); + return return_value; +} + +static bool +read_settings(struct settings *settings) +{ + if (!get_and_verify_sd_card_selection(&settings->use_sdcard)) { + syslog(LOG_ERR, "Failed to setup sd_card"); + return false; + } + if (!get_and_verify_tls_selection(&settings->use_tls)) { + syslog(LOG_ERR, "Failed to verify tls selection"); + return false; + } + if (!get_tcp_socket_selection(&settings->use_tcp_socket)) { + syslog(LOG_ERR, "Failed to get tcp socket selection"); + return false; + } + if (!get_ipc_socket_selection(&settings->use_ipc_socket)) { + syslog(LOG_ERR, "Failed to get ipc socket selection"); + return false; + } + return true; +} + +// Return true if dockerd was successfully started. +// Log an error and return false if it failed to start properly. static bool -start_dockerd(void) +start_dockerd(const struct settings *settings) { + const bool use_sdcard = settings->use_sdcard; + const bool use_tls = settings->use_tls; + const bool use_tcp_socket = settings->use_tcp_socket; + const bool use_ipc_socket = settings->use_ipc_socket; GError *error = NULL; bool return_value = false; @@ -246,46 +458,6 @@ start_dockerd(void) guint args_offset = 0; gchar **args_split = NULL; - // Read parameters - char *use_sd_card_value = get_parameter_value("SDCardSupport"); - char *use_tls_value = get_parameter_value("UseTLS"); - char *use_ipc_socket_value = get_parameter_value("IPCSocket"); - char *use_tcp_socket_value = get_parameter_value("TCPSocket"); - if (use_sd_card_value == NULL || use_tls_value == NULL || - use_ipc_socket_value == NULL || use_tcp_socket_value == NULL) { - goto end; - } - bool use_sdcard = strcmp(use_sd_card_value, "yes") == 0; - bool use_tls = strcmp(use_tls_value, "yes") == 0; - bool use_ipc_socket = strcmp(use_ipc_socket_value, "yes") == 0; - bool use_tcp_socket = strcmp(use_tcp_socket_value, "yes") == 0; - - if (use_sdcard) { - // Confirm that the SD card is usable - char *sd_file_system = get_sd_filesystem(); - if (sd_file_system == NULL) { - syslog(LOG_ERR, - "Couldn't identify the file system of the SD card at %s", - sd_card_path); - goto end; - } - - if (strcmp(sd_file_system, "vfat") == 0 || - strcmp(sd_file_system, "exfat") == 0) { - syslog(LOG_ERR, - "The SD card at %s uses file system %s which does not support " - "Unix file permissions. Please reformat to a file system that " - "support Unix file permissions, such as ext4 or xfs.", - sd_card_path, - sd_file_system); - goto end; - } - - if (!setup_sdcard()) { - syslog(LOG_ERR, "Failed to setup SD card."); - goto end; - } - } args_offset += g_snprintf( args + args_offset, args_len - args_offset, @@ -304,29 +476,6 @@ start_dockerd(void) const char *key_path = "/usr/local/packages/dockerdwrapperwithcompose/server-key.pem"; - bool ca_exists = access(ca_path, F_OK) == 0; - bool cert_exists = access(cert_path, F_OK) == 0; - bool key_exists = access(key_path, F_OK) == 0; - - if (!ca_exists) { - syslog(LOG_ERR, - "Cannot start using TLS, no CA certificate found at %s", - ca_path); - } - if (!cert_exists) { - syslog(LOG_ERR, - "Cannot start using TLS, no server certificate found at %s", - cert_path); - } - if (!key_exists) { - syslog(LOG_ERR, - "Cannot start using TLS, no server key found at %s", - key_path); - } - - if (!ca_exists || !cert_exists || !key_exists) { - goto end; - } if (use_tcp_socket) { args_offset += g_snprintf(args + args_offset, args_len - args_offset, @@ -377,7 +526,6 @@ start_dockerd(void) "selected."); goto end; } else { - // By default, API listens on IPC socket even if it's set to 'no' g_strlcat(msg, " without IPC socket.", msg_len); } @@ -395,7 +543,7 @@ start_dockerd(void) &error); if (!result) { syslog(LOG_ERR, - "Could not execv the dockerd process. Return value: %d, error: %s", + "Starting dockerd failed: execv returned: %d, error: %s", result, error->message); goto end; @@ -410,20 +558,21 @@ start_dockerd(void) g_main_loop_quit(loop); goto end; } - return_value = true; end: g_strfreev(args_split); - free(use_sd_card_value); - free(use_tls_value); - free(use_ipc_socket_value); - free(use_tcp_socket_value); g_clear_error(&error); - return return_value; } +static bool +read_settings_and_start_dockerd(void) +{ + struct settings settings = {0}; + return read_settings(&settings) && start_dockerd(&settings); +} + /** * @brief Stop the currently running dockerd process. * @@ -477,7 +626,7 @@ dockerd_process_exited_callback(__attribute__((unused)) GPid pid, __attribute__((unused)) gpointer user_data) { GError *error = NULL; - if (!g_spawn_check_wait_status(status, &error)) { + if (!g_spawn_check_exit_status(status, &error)) { syslog(LOG_ERR, "Dockerd process exited with error: %d", status); g_clear_error(&error); @@ -493,8 +642,7 @@ dockerd_process_exited_callback(__attribute__((unused)) GPid pid, if (restart_dockerd) { restart_dockerd = false; - if (!start_dockerd()) { - syslog(LOG_ERR, "Failed to restart dockerd, exiting."); + if (!read_settings_and_start_dockerd()) { exit_code = -1; g_main_loop_quit(loop); } @@ -505,7 +653,7 @@ dockerd_process_exited_callback(__attribute__((unused)) GPid pid, } /** - * @brief Callback function called when the SDCardSupport parameter + * @brief Callback function called when any of the parameters * changes. Will restart the dockerd process with the new setting. * * @param name Name of the updated parameter. @@ -517,20 +665,18 @@ parameter_changed_callback(const gchar *name, __attribute__((unused)) gpointer data) { const gchar *parname = name += strlen("root.dockerdwrapperwithcompose."); - // bool dockerd_started_correctly = false; - if (strcmp(parname, "SDCardSupport") == 0) { - syslog(LOG_INFO, "SDCardSupport changed to: %s", value); - restart_dockerd = true; - } else if (strcmp(parname, "UseTLS") == 0) { - syslog(LOG_INFO, "UseTLS changed to: %s", value); - restart_dockerd = true; - } else if (strcmp(parname, "TCPSocket") == 0) { - syslog(LOG_INFO, "TCPSocket changed to: %s", value); - restart_dockerd = true; - } else if (strcmp(parname, "IPCSocket") == 0) { - syslog(LOG_INFO, "IPCSocket changed to: %s", value); - restart_dockerd = true; - } else { + + bool unknown_parameter = true; + for (size_t i = 0; i < sizeof(ax_parameters) / sizeof(ax_parameters[0]); + ++i) { + if (strcmp(parname, ax_parameters[i]) == 0) { + syslog(LOG_INFO, "%s changed to: %s", ax_parameters[i], value); + restart_dockerd = true; + unknown_parameter = false; + } + } + + if (unknown_parameter) { syslog(LOG_WARNING, "Parameter %s is not recognized", name); restart_dockerd = false; @@ -559,34 +705,21 @@ setup_axparameter(void) goto end; } - gboolean geresult = ax_parameter_register_callback( - ax_parameter, - "root.dockerdwrapperwithcompose.SDCardSupport", - parameter_changed_callback, - NULL, - &error); + for (size_t i = 0; i < sizeof(ax_parameters) / sizeof(ax_parameters[0]); + ++i) { + char *parameter_path = g_strdup_printf( + "%s.%s", "root.dockerdwrapperwithcompose", ax_parameters[i]); + gboolean geresult = ax_parameter_register_callback( + ax_parameter, parameter_path, parameter_changed_callback, NULL, &error); + free(parameter_path); - if (geresult == FALSE) { - syslog(LOG_ERR, - "Could not register SDCardSupport callback. Error: %s", - error->message); - goto end; - } - - geresult = - ax_parameter_register_callback(ax_parameter, - "root.dockerdwrapperwithcompose.UseTLS", - parameter_changed_callback, - NULL, - &error); - - if (geresult == FALSE) { - syslog(LOG_ERR, - "Could not register UseTLS callback. Error: %s", - error->message); - ax_parameter_unregister_callback( - ax_parameter, "root.dockerdwrapperwithcompose.SDCardSupport"); - goto end; + if (geresult == FALSE) { + syslog(LOG_ERR, + "Could not register %s callback. Error: %s", + ax_parameters[i], + error->message); + goto end; + } } success = true; @@ -615,6 +748,7 @@ main(void) ax_parameter = setup_axparameter(); if (ax_parameter == NULL) { syslog(LOG_ERR, "Error in setup_axparameter: %s", error->message); + exit_code = -1; goto end; } @@ -622,8 +756,7 @@ main(void) loop = g_main_loop_new(NULL, FALSE); loop = g_main_loop_ref(loop); - if (!start_dockerd()) { - syslog(LOG_ERR, "Starting dockerd failed"); + if (!read_settings_and_start_dockerd()) { exit_code = -1; goto end; } @@ -640,13 +773,16 @@ main(void) } if (ax_parameter != NULL) { - ax_parameter_unregister_callback( - ax_parameter, "root.dockerdwrapperwithcompose.SDCardSupport"); - ax_parameter_unregister_callback(ax_parameter, - "root.dockerdwrapperwithcompose.UseTLS"); + for (size_t i = 0; i < sizeof(ax_parameters) / sizeof(ax_parameters[0]); + ++i) { + char *parameter_path = g_strdup_printf( + "%s.%s", "root.dockerdwrapperwithcompose", ax_parameters[i]); + ax_parameter_unregister_callback(ax_parameter, parameter_path); + free(parameter_path); + } ax_parameter_free(ax_parameter); } g_clear_error(&error); return exit_code; -} +} \ No newline at end of file diff --git a/app/manifest.json b/app/manifest.json index 276f7dc..a70270d 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -30,7 +30,7 @@ }, { "name": "UseTLS", - "default": "no", + "default": "yes", "type": "enum:no|No, yes|Yes" }, {