Skip to content

Commit 609de65

Browse files
committed
bad: root-monitor: authenticated save
1 parent 1d78368 commit 609de65

2 files changed

Lines changed: 180 additions & 23 deletions

File tree

plugins/acme-client/protocol_lws_acme_client_core.c

Lines changed: 123 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,51 @@
4646
#include <fcntl.h>
4747
#include "lws-acme-client.h"
4848

49+
#if !defined(WIN32)
50+
#include <sys/socket.h>
51+
#include <sys/un.h>
52+
53+
static int
54+
acme_ipc_save_payload(const char *uds_path, const char *req, const char *domain, const char *filename, const char *payload, size_t payload_len)
55+
{
56+
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
57+
if (fd < 0) return 1;
58+
struct sockaddr_un addr;
59+
memset(&addr, 0, sizeof(addr));
60+
addr.sun_family = AF_UNIX;
61+
strncpy(addr.sun_path, uds_path, sizeof(addr.sun_path) - 1);
62+
if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
63+
close(fd);
64+
return 1;
65+
}
66+
67+
char header[512];
68+
int hlen = lws_snprintf(header, sizeof(header), "{\"req\":\"%s\",\"domain\":\"%s\",\"subdomain\":\"%s\",\"zone\":\"", req, domain, filename);
69+
write(fd, header, (size_t)hlen);
70+
71+
for (size_t i = 0; i < payload_len; i++) {
72+
char c = payload[i];
73+
if (c == '\n') { write(fd, "\\n", 2); }
74+
else if (c == '\r') { write(fd, "\\r", 2); }
75+
else if (c == '"') { write(fd, "\\\"", 2); }
76+
else if (c == '\\') { write(fd, "\\\\", 2); }
77+
else { write(fd, &c, 1); }
78+
}
79+
write(fd, "\"}\n", 3);
80+
81+
char resp[256];
82+
read(fd, resp, sizeof(resp));
83+
close(fd);
84+
return 0;
85+
}
86+
#else
87+
static int
88+
acme_ipc_save_payload(const char *uds_path, const char *req, const char *domain, const char *filename, const char *payload, size_t payload_len)
89+
{
90+
return 1;
91+
}
92+
#endif
93+
4994
typedef enum {
5095
ACME_STATE_DIRECTORY, /* get the directory JSON using GET + parse */
5196
ACME_STATE_NEW_NONCE, /* get the replay nonce */
@@ -706,9 +751,42 @@ lws_acme_load_create_auth_keys(struct per_vhost_data__lws_acme_client *vhd,
706751
lwsl_notice("...keypair generated\n");
707752

708753
if (lws_jwk_save(&vhd->jwk, vhd->active_cert->pvop[LWS_TLS_SET_AUTH_PATH])) {
709-
lwsl_vhost_warn(vhd->vhost, "unable to save %s",
710-
vhd->active_cert->pvop[LWS_TLS_SET_AUTH_PATH]);
711-
return 1;
754+
lwsl_vhost_notice(vhd->vhost, "falling back to ACME footprint IPC to save %s", vhd->active_cert->pvop[LWS_TLS_SET_AUTH_PATH]);
755+
char tmp_path[256];
756+
lws_snprintf(tmp_path, sizeof(tmp_path), "/tmp/lws-acme-auth-%d.jwk", getpid());
757+
if (!lws_jwk_save(&vhd->jwk, tmp_path)) {
758+
int fd = open(tmp_path, O_RDONLY);
759+
int success = 0;
760+
if (fd >= 0) {
761+
struct stat st;
762+
if (!fstat(fd, &st) && st.st_size > 0) {
763+
char *buf = malloc((size_t)st.st_size);
764+
if (buf && read(fd, buf, (size_t)st.st_size) == st.st_size) {
765+
const char *fp = vhd->active_cert->pvop[LWS_TLS_SET_AUTH_PATH];
766+
const char *fn = strrchr(fp, '/');
767+
if (fn) fn++; else fn = fp;
768+
int r = acme_ipc_save_payload("/var/run/lws-dnssec-monitor.sock",
769+
"save_auth_key",
770+
vhd->active_cert->pvop[LWS_TLS_REQ_ELEMENT_COMMON_NAME],
771+
fn,
772+
buf, (size_t)st.st_size);
773+
if (!r) success = 1;
774+
}
775+
if (buf) free(buf);
776+
}
777+
close(fd);
778+
}
779+
unlink(tmp_path);
780+
if (!success) {
781+
lwsl_vhost_warn(vhd->vhost, "unable to save %s via footprint IPC",
782+
vhd->active_cert->pvop[LWS_TLS_SET_AUTH_PATH]);
783+
return 1;
784+
}
785+
} else {
786+
lwsl_vhost_warn(vhd->vhost, "unable to save %s",
787+
vhd->active_cert->pvop[LWS_TLS_SET_AUTH_PATH]);
788+
return 1;
789+
}
712790
}
713791

714792
return 0;
@@ -1775,15 +1853,21 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,
17751853
#endif
17761854
, 0600);
17771855
if (fd_cert < 0) {
1778-
lwsl_vhost_err(vhd->vhost, "unable to create cert file %s", cert_ts);
1779-
goto failed;
1780-
}
1781-
1782-
n = lws_plat_write_cert(vhd->vhost, 0, fd_cert, ac->buf, (size_t)ac->cpos);
1783-
close(fd_cert);
1784-
if (n) {
1785-
lwsl_vhost_err(vhd->vhost, "unable to write ACME cert!");
1786-
goto failed;
1856+
lwsl_vhost_notice(vhd->vhost, "falling back to IPC footprint to save %s", cert_ts);
1857+
const char *fn = strrchr(cert_ts, '/');
1858+
if (fn) fn++; else fn = cert_ts;
1859+
int r = acme_ipc_save_payload("/var/run/lws-dnssec-monitor.sock", "save_cert", vhd->active_cert->pvop[LWS_TLS_REQ_ELEMENT_COMMON_NAME], fn, ac->buf, (size_t)ac->cpos);
1860+
if (r) {
1861+
lwsl_vhost_err(vhd->vhost, "unable to create cert file %s", cert_ts);
1862+
goto failed;
1863+
}
1864+
} else {
1865+
n = lws_plat_write_cert(vhd->vhost, 0, fd_cert, ac->buf, (size_t)ac->cpos);
1866+
close(fd_cert);
1867+
if (n) {
1868+
lwsl_vhost_err(vhd->vhost, "unable to write ACME cert!");
1869+
goto failed;
1870+
}
17871871
}
17881872

17891873
fd_key = lws_open(key_ts, LWS_O_WRONLY | LWS_O_CREAT | LWS_O_TRUNC
@@ -1792,25 +1876,42 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason,
17921876
#endif
17931877
, 0600);
17941878
if (fd_key < 0) {
1795-
lwsl_vhost_err(vhd->vhost, "unable to create key file %s", key_ts);
1796-
goto failed;
1797-
}
1798-
1799-
n = lws_plat_write_cert(vhd->vhost, 1, fd_key, ac->alloc_privkey_pem, ac->len_privkey_pem);
1800-
close(fd_key);
1801-
if (n) {
1802-
lwsl_vhost_err(vhd->vhost, "unable to write ACME key!");
1803-
goto failed;
1879+
lwsl_vhost_notice(vhd->vhost, "falling back to IPC footprint to save %s", key_ts);
1880+
const char *fn = strrchr(key_ts, '/');
1881+
if (fn) fn++; else fn = key_ts;
1882+
int r = acme_ipc_save_payload("/var/run/lws-dnssec-monitor.sock", "save_key", vhd->active_cert->pvop[LWS_TLS_REQ_ELEMENT_COMMON_NAME], fn, ac->alloc_privkey_pem, ac->len_privkey_pem);
1883+
if (r) {
1884+
lwsl_vhost_err(vhd->vhost, "unable to create key file %s", key_ts);
1885+
goto failed;
1886+
}
1887+
} else {
1888+
n = lws_plat_write_cert(vhd->vhost, 1, fd_key, ac->alloc_privkey_pem, ac->len_privkey_pem);
1889+
close(fd_key);
1890+
if (n) {
1891+
lwsl_vhost_err(vhd->vhost, "unable to write ACME key!");
1892+
goto failed;
1893+
}
18041894
}
18051895

18061896
fd_full = lws_open(full_ts, LWS_O_WRONLY | LWS_O_CREAT | LWS_O_TRUNC
18071897
#ifdef WIN32
18081898
| O_BINARY
18091899
#endif
18101900
, 0600);
1811-
if (fd_full >= 0) {
1901+
if (fd_full < 0) {
1902+
lwsl_vhost_notice(vhd->vhost, "falling back to IPC footprint to save %s", full_ts);
1903+
const char *fn = strrchr(full_ts, '/');
1904+
if (fn) fn++; else fn = full_ts;
1905+
int r = acme_ipc_save_payload("/var/run/lws-dnssec-monitor.sock", "save_cert", vhd->active_cert->pvop[LWS_TLS_REQ_ELEMENT_COMMON_NAME], fn, ac->buf, (size_t)cpos_fullchain);
1906+
if (r) {
1907+
lwsl_vhost_err(vhd->vhost, "unable to create fullchain file %s", full_ts);
1908+
}
1909+
} else {
18121910
n = lws_plat_write_cert(vhd->vhost, 0, fd_full, ac->buf, (size_t)cpos_fullchain);
18131911
close(fd_full);
1912+
if (n) {
1913+
lwsl_vhost_err(vhd->vhost, "unable to write ACME fullchain cert!");
1914+
}
18141915
}
18151916

18161917
/* Symlink update */

plugins/protocol_lws_dht_dnssec_monitor/protocol_lws_dht_dnssec_monitor.c

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -681,6 +681,59 @@ handle_req_delete_tls(struct vhd *vhd, struct pss *root_pss, struct monitor_req_
681681
root_pss->tx_len = lws_ptr_diff_size_t(tx, (char *)&root_pss->tx[LWS_PRE]);
682682
}
683683

684+
static void
685+
handle_req_save_acme_file(struct vhd *vhd, struct pss *root_pss, struct monitor_req_args *a, const char *dir_suffix)
686+
{
687+
char *tx = (char *)&root_pss->tx[LWS_PRE];
688+
char *tx_end = tx + 65536 - 1;
689+
char d_path[1024];
690+
691+
if (!a->zone_buf || !a->domain[0] || !a->subdomain[0]) {
692+
tx += lws_snprintf(tx, lws_ptr_diff_size_t(tx_end, tx), "{\"req\":\"%s\",\"status\":\"error\",\"msg\":\"Missing payload, domain, or filename\"}\n", a->req);
693+
goto done;
694+
}
695+
696+
if (strchr(a->domain, '/') || strstr(a->domain, "..") || strchr(a->domain, '\\') ||
697+
strchr(a->subdomain, '/') || strstr(a->subdomain, "..") || strchr(a->subdomain, '\\')) {
698+
tx += lws_snprintf(tx, lws_ptr_diff_size_t(tx_end, tx), "{\"req\":\"%s\",\"status\":\"error\",\"msg\":\"Path traversal\"}\n", a->req);
699+
goto done;
700+
}
701+
702+
lws_snprintf(d_path, sizeof(d_path), "%s/domains/%s/%s/%s", vhd->base_dir, a->domain, dir_suffix, a->subdomain);
703+
704+
int fd = open(d_path, O_CREAT | O_WRONLY | O_TRUNC, 0600);
705+
if (fd >= 0) {
706+
if (write(fd, a->zone_buf, (size_t)a->zone_len) == (ssize_t)a->zone_len) {
707+
tx += lws_snprintf(tx, lws_ptr_diff_size_t(tx_end, tx), "{\"req\":\"%s\",\"status\":\"ok\"}\n", a->req);
708+
} else {
709+
tx += lws_snprintf(tx, lws_ptr_diff_size_t(tx_end, tx), "{\"req\":\"%s\",\"status\":\"error\",\"msg\":\"Partial write failure\"}\n", a->req);
710+
}
711+
close(fd);
712+
} else {
713+
tx += lws_snprintf(tx, lws_ptr_diff_size_t(tx_end, tx), "{\"req\":\"%s\",\"status\":\"error\",\"msg\":\"Could not open file for writing\"}\n", a->req);
714+
}
715+
done:
716+
root_pss->tx_len = lws_ptr_diff_size_t(tx, (char *)&root_pss->tx[LWS_PRE]);
717+
}
718+
719+
static void
720+
handle_req_save_auth_key(struct vhd *vhd, struct pss *root_pss, struct monitor_req_args *a)
721+
{
722+
handle_req_save_acme_file(vhd, root_pss, a, "");
723+
}
724+
725+
static void
726+
handle_req_save_cert(struct vhd *vhd, struct pss *root_pss, struct monitor_req_args *a)
727+
{
728+
handle_req_save_acme_file(vhd, root_pss, a, "certs/crt");
729+
}
730+
731+
static void
732+
handle_req_save_key(struct vhd *vhd, struct pss *root_pss, struct monitor_req_args *a)
733+
{
734+
handle_req_save_acme_file(vhd, root_pss, a, "certs/key");
735+
}
736+
684737
typedef void (*monitor_req_handler_t)(struct vhd *vhd, struct pss *root_pss, struct monitor_req_args *a);
685738

686739
static const struct monitor_req_map {
@@ -695,7 +748,10 @@ static const struct monitor_req_map {
695748
{ "update_zone", handle_req_update_zone },
696749
{ "get_tls", handle_req_get_tls },
697750
{ "create_tls", handle_req_create_tls },
698-
{ "delete_tls", handle_req_delete_tls }
751+
{ "delete_tls", handle_req_delete_tls },
752+
{ "save_auth_key", handle_req_save_auth_key },
753+
{ "save_cert", handle_req_save_cert },
754+
{ "save_key", handle_req_save_key }
699755
};
700756

701757
static void

0 commit comments

Comments
 (0)