aboutsummaryrefslogtreecommitdiffstats
path: root/apps/settings/lib/SetupChecks/SystemIs64bit.php
blob: 308011c218ec46edccd946698584cdb4569a6224 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<?php

declare(strict_types=1);

/**
 * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
 * SPDX-License-Identifier: AGPL-3.0-or-later
 */

namespace OCA\Settings\SetupChecks;

use OCP\IL10N;
use OCP\IURLGenerator;
use OCP\SetupCheck\ISetupCheck;
use OCP\SetupCheck\SetupResult;

class SystemIs64bit implements ISetupCheck {
	public function __construct(
		private IL10N $l10n,
		private IURLGenerator $urlGenerator,
	) {
	}

	public function getName(): string {
		return $this->l10n->t('Architecture');
	}

	public function getCategory(): string {
		return 'system';
	}

	protected function is64bit(): bool {
		if (PHP_INT_SIZE < 8) {
			return false;
		} else {
			return true;
		}
	}

	public function run(): SetupResult {
		if ($this->is64bit()) {
			return SetupResult::success($this->l10n->t('64-bit'));
		} else {
			return SetupResult::warning(
				$this->l10n->t('It seems like you are running a 32-bit PHP version. Nextcloud needs 64-bit to run well. Please upgrade your OS and PHP to 64-bit!'),
				$this->urlGenerator->linkToDocs('admin-system-requirements')
			);
		}
	}
}
class="n">cpy_str; cpy_str = rspamd_fstring_new_init(msg->body_buf.begin, msg->body_buf.len); rspamd_http_message_set_body_from_fstring_steal(msg, cpy_str); } int rspamd_http_message_write_header(const char *mime_type, gboolean encrypted, char *repbuf, gsize replen, gsize bodylen, gsize enclen, const char *host, struct rspamd_http_connection *conn, struct rspamd_http_message *msg, rspamd_fstring_t **buf, struct rspamd_http_connection_private *priv, struct rspamd_cryptobox_pubkey *peer_key) { char datebuf[64]; int meth_len = 0; const char *conn_type = "close"; if (conn->type == RSPAMD_HTTP_SERVER) { /* Format reply */ if (msg->method < HTTP_SYMBOLS) { rspamd_ftok_t status; rspamd_http_date_format(datebuf, sizeof(datebuf), msg->date); if (mime_type == NULL) { mime_type = encrypted ? "application/octet-stream" : "text/plain"; } if (msg->status == NULL || msg->status->len == 0) { if (msg->code == 200) { RSPAMD_FTOK_ASSIGN(&status, "OK"); } else if (msg->code == 404) { RSPAMD_FTOK_ASSIGN(&status, "Not Found"); } else if (msg->code == 403) { RSPAMD_FTOK_ASSIGN(&status, "Forbidden"); } else if (msg->code >= 500 && msg->code < 600) { RSPAMD_FTOK_ASSIGN(&status, "Internal Server Error"); } else { RSPAMD_FTOK_ASSIGN(&status, "Undefined Error"); } } else { status.begin = msg->status->str; status.len = msg->status->len; } if (encrypted) { /* Internal reply (encrypted) */ if (mime_type) { meth_len = rspamd_snprintf(repbuf, replen, "HTTP/1.1 %d %T\r\n" "Connection: close\r\n" "Server: %s\r\n" "Date: %s\r\n" "Content-Length: %z\r\n" "Content-Type: %s", /* NO \r\n at the end ! */ msg->code, &status, priv->ctx->config.server_hdr, datebuf, bodylen, mime_type); } else { meth_len = rspamd_snprintf(repbuf, replen, "HTTP/1.1 %d %T\r\n" "Connection: close\r\n" "Server: %s\r\n" "Date: %s\r\n" "Content-Length: %z", /* NO \r\n at the end ! */ msg->code, &status, priv->ctx->config.server_hdr, datebuf, bodylen); } enclen += meth_len; /* External reply */ rspamd_printf_fstring(buf, "HTTP/1.1 200 OK\r\n" "Connection: close\r\n" "Server: %s\r\n" "Date: %s\r\n" "Content-Length: %z\r\n" "Content-Type: application/octet-stream\r\n", priv->ctx->config.server_hdr, datebuf, enclen); } else { if (mime_type) { meth_len = rspamd_printf_fstring(buf, "HTTP/1.1 %d %T\r\n" "Connection: close\r\n" "Server: %s\r\n" "Date: %s\r\n" "Content-Length: %z\r\n" "Content-Type: %s\r\n", msg->code, &status, priv->ctx->config.server_hdr, datebuf, bodylen, mime_type); } else { meth_len = rspamd_printf_fstring(buf, "HTTP/1.1 %d %T\r\n" "Connection: close\r\n" "Server: %s\r\n" "Date: %s\r\n" "Content-Length: %z\r\n", msg->code, &status, priv->ctx->config.server_hdr, datebuf, bodylen); } } } else { /* Legacy spamd reply */ if (msg->flags & RSPAMD_HTTP_FLAG_SPAMC) { gsize real_bodylen; goffset eoh_pos; GString tmp; /* Unfortunately, spamc protocol is deadly brain damaged */ tmp.str = (char *) msg->body_buf.begin; tmp.len = msg->body_buf.len; if (rspamd_string_find_eoh(&tmp, &eoh_pos) != -1 && bodylen > eoh_pos) { real_bodylen = bodylen - eoh_pos; } else { real_bodylen = bodylen; } rspamd_printf_fstring(buf, "SPAMD/1.1 0 EX_OK\r\n" "Content-length: %z\r\n", real_bodylen); } else { rspamd_printf_fstring(buf, "RSPAMD/1.3 0 EX_OK\r\n"); } } } else { /* Client request */ if (conn->opts & RSPAMD_HTTP_CLIENT_KEEP_ALIVE) { conn_type = "keep-alive"; } /* Format request */ enclen += RSPAMD_FSTRING_LEN(msg->url) + strlen(http_method_str(msg->method)) + 1; if (host == NULL && msg->host == NULL) { /* Fallback to HTTP/1.0 */ if (encrypted) { rspamd_printf_fstring(buf, "%s %s HTTP/1.0\r\n" "Content-Length: %z\r\n" "Content-Type: application/octet-stream\r\n" "Connection: %s\r\n", "POST", "/post", enclen, conn_type); } else { rspamd_printf_fstring(buf, "%s %V HTTP/1.0\r\n" "Content-Length: %z\r\n" "Connection: %s\r\n", http_method_str(msg->method), msg->url, bodylen, conn_type); if (bodylen > 0) { if (mime_type == NULL) { mime_type = "text/plain"; } rspamd_printf_fstring(buf, "Content-Type: %s\r\n", mime_type); } } } else { /* Normal HTTP/1.1 with Host */ if (host == NULL) { host = msg->host->str; } if (encrypted) { /* TODO: Add proxy support to HTTPCrypt */ if (rspamd_http_message_is_standard_port(msg)) { rspamd_printf_fstring(buf, "%s %s HTTP/1.1\r\n" "Connection: %s\r\n" "Host: %s\r\n" "Content-Length: %z\r\n" "Content-Type: application/octet-stream\r\n", "POST", "/post", conn_type, host, enclen); } else { rspamd_printf_fstring(buf, "%s %s HTTP/1.1\r\n" "Connection: %s\r\n" "Host: %s:%d\r\n" "Content-Length: %z\r\n" "Content-Type: application/octet-stream\r\n", "POST", "/post", conn_type, host, msg->port, enclen); } } else { if (conn->priv->flags & RSPAMD_HTTP_CONN_FLAG_PROXY) { /* Write proxied request */ if ((msg->flags & RSPAMD_HTTP_FLAG_HAS_HOST_HEADER)) { rspamd_printf_fstring(buf, "%s %s://%s:%d/%V HTTP/1.1\r\n" "Connection: %s\r\n" "Content-Length: %z\r\n", http_method_str(msg->method), (conn->opts & RSPAMD_HTTP_CLIENT_SSL) ? "https" : "http", host, msg->port, msg->url, conn_type, bodylen); } else { if (rspamd_http_message_is_standard_port(msg)) { rspamd_printf_fstring(buf, "%s %s://%s:%d/%V HTTP/1.1\r\n" "Connection: %s\r\n" "Host: %s\r\n" "Content-Length: %z\r\n", http_method_str(msg->method), (conn->opts & RSPAMD_HTTP_CLIENT_SSL) ? "https" : "http", host, msg->port, msg->url, conn_type, host, bodylen); } else { rspamd_printf_fstring(buf, "%s %s://%s:%d/%V HTTP/1.1\r\n" "Connection: %s\r\n" "Host: %s:%d\r\n" "Content-Length: %z\r\n", http_method_str(msg->method), (conn->opts & RSPAMD_HTTP_CLIENT_SSL) ? "https" : "http", host, msg->port, msg->url, conn_type, host, msg->port, bodylen); } } } else { /* Unproxied version */ if ((msg->flags & RSPAMD_HTTP_FLAG_HAS_HOST_HEADER)) { rspamd_printf_fstring(buf, "%s %V HTTP/1.1\r\n" "Connection: %s\r\n" "Content-Length: %z\r\n", http_method_str(msg->method), msg->url, conn_type, bodylen); } else { if (rspamd_http_message_is_standard_port(msg)) { rspamd_printf_fstring(buf, "%s %V HTTP/1.1\r\n" "Connection: %s\r\n" "Host: %s\r\n" "Content-Length: %z\r\n", http_method_str(msg->method), msg->url, conn_type, host, bodylen); } else { rspamd_printf_fstring(buf, "%s %V HTTP/1.1\r\n" "Connection: %s\r\n" "Host: %s:%d\r\n" "Content-Length: %z\r\n", http_method_str(msg->method), msg->url, conn_type, host, msg->port, bodylen); } } } if (bodylen > 0) { if (mime_type != NULL) { rspamd_printf_fstring(buf, "Content-Type: %s\r\n", mime_type); } } } } if (encrypted) { GString *b32_key, *b32_id; b32_key = rspamd_keypair_print(priv->local_key, RSPAMD_KEYPAIR_PUBKEY | RSPAMD_KEYPAIR_BASE32); b32_id = rspamd_pubkey_print(peer_key, RSPAMD_KEYPAIR_ID_SHORT | RSPAMD_KEYPAIR_BASE32); /* XXX: add some fuzz here */ rspamd_printf_fstring(&*buf, "Key: %v=%v\r\n", b32_id, b32_key); g_string_free(b32_key, TRUE); g_string_free(b32_id, TRUE); } } return meth_len; } static gboolean rspamd_http_connection_write_message_common(struct rspamd_http_connection *conn, struct rspamd_http_message *msg, const char *host, const char *mime_type, gpointer ud, ev_tstamp timeout, gboolean allow_shared) { struct rspamd_http_connection_private *priv = conn->priv; struct rspamd_http_header *hdr, *hcur; char repbuf[512], *pbody; int i, hdrcount, meth_len = 0, preludelen = 0; gsize bodylen, enclen = 0; rspamd_fstring_t *buf; gboolean encrypted = FALSE; unsigned char nonce[rspamd_cryptobox_MAX_NONCEBYTES], mac[rspamd_cryptobox_MAX_MACBYTES]; unsigned char *np = NULL, *mp = NULL, *meth_pos = NULL; struct rspamd_cryptobox_pubkey *peer_key = NULL; enum rspamd_cryptobox_mode mode; GError *err; conn->ud = ud; priv->msg = msg; priv->timeout = timeout; priv->header = NULL; priv->buf = g_malloc0(sizeof(*priv->buf)); REF_INIT_RETAIN(priv->buf, rspamd_http_privbuf_dtor); priv->buf->data = rspamd_fstring_sized_new(512); buf = priv->buf->data; if ((msg->flags & RSPAMD_HTTP_FLAG_WANT_SSL) && !(conn->opts & RSPAMD_HTTP_CLIENT_SSL)) { err = g_error_new(HTTP_ERROR, 400, "SSL connection requested but not created properly, internal error"); rspamd_http_connection_ref(conn); conn->error_handler(conn, err); rspamd_http_connection_unref(conn); g_error_free(err); return FALSE; } if (priv->peer_key && priv->local_key) { priv->msg->peer_key = priv->peer_key; priv->peer_key = NULL; priv->flags |= RSPAMD_HTTP_CONN_FLAG_ENCRYPTED; } if (msg->peer_key != NULL) { if (priv->local_key == NULL) { /* Automatically generate a temporary keypair */ priv->local_key = rspamd_keypair_new(RSPAMD_KEYPAIR_KEX, RSPAMD_CRYPTOBOX_MODE_25519); } encrypted = TRUE; if (priv->cache) { rspamd_keypair_cache_process(priv->cache, priv->local_key, priv->msg->peer_key); } } if (encrypted && (msg->flags & (RSPAMD_HTTP_FLAG_SHMEM_IMMUTABLE | RSPAMD_HTTP_FLAG_SHMEM))) { /* We cannot use immutable body to encrypt message in place */ allow_shared = FALSE; rspamd_http_detach_shared(msg); } if (allow_shared) { char tmpbuf[64]; if (!(msg->flags & RSPAMD_HTTP_FLAG_SHMEM) || msg->body_buf.c.shared.name == NULL) { allow_shared = FALSE; } else { /* Insert new headers */ rspamd_http_message_add_header(msg, "Shm", msg->body_buf.c.shared.name->shm_name); rspamd_snprintf(tmpbuf, sizeof(tmpbuf), "%d", (int) (msg->body_buf.begin - msg->body_buf.str)); rspamd_http_message_add_header(msg, "Shm-Offset", tmpbuf); rspamd_snprintf(tmpbuf, sizeof(tmpbuf), "%z", msg->body_buf.len); rspamd_http_message_add_header(msg, "Shm-Length", tmpbuf); } } if (priv->ctx->config.user_agent && conn->type == RSPAMD_HTTP_CLIENT) { rspamd_ftok_t srch; khiter_t k; int r; RSPAMD_FTOK_ASSIGN(&srch, "User-Agent"); k = kh_put(rspamd_http_headers_hash, msg->headers, &srch, &r); if (r != 0) { hdr = g_malloc0(sizeof(struct rspamd_http_header)); unsigned int vlen = strlen(priv->ctx->config.user_agent); hdr->combined = rspamd_fstring_sized_new(srch.len + vlen + 4); rspamd_printf_fstring(&hdr->combined, "%T: %*s\r\n", &srch, vlen, priv->ctx->config.user_agent); hdr->name.begin = hdr->combined->str; hdr->name.len = srch.len; hdr->value.begin = hdr->combined->str + srch.len + 2; hdr->value.len = vlen; hdr->prev = hdr; /* for utlists */ kh_value(msg->headers, k) = hdr; /* as we searched using static buffer */ kh_key(msg->headers, k) = &hdr->name; } } if (encrypted) { mode = rspamd_keypair_alg(priv->local_key); if (msg->body_buf.len == 0) { pbody = NULL; bodylen = 0; msg->method = HTTP_GET; } else { pbody = (char *) msg->body_buf.begin; bodylen = msg->body_buf.len; msg->method = HTTP_POST; } if (conn->type == RSPAMD_HTTP_SERVER) { /* * iov[0] = base reply * iov[1] = CRLF * iov[2] = nonce * iov[3] = mac * iov[4] = encrypted reply * iov[6] = encrypted crlf * iov[7..n] = encrypted headers * iov[n + 1] = encrypted crlf * [iov[n + 2] = encrypted body] */ priv->outlen = 7; enclen = rspamd_cryptobox_nonce_bytes(mode) + rspamd_cryptobox_mac_bytes(mode) + 4 + /* 2 * CRLF */ bodylen; } else { /* * iov[0] = base request * iov[1] = CRLF * iov[2] = nonce * iov[3] = mac * iov[4] = encrypted method + space * iov[5] = encrypted url * iov[7] = encrypted prelude * iov[8..n] = encrypted headers * iov[n + 1] = encrypted crlf * [iov[n + 2] = encrypted body] */ priv->outlen = 8; if (bodylen > 0) { if (mime_type != NULL) { preludelen = rspamd_snprintf(repbuf, sizeof(repbuf), "%s\r\n" "Content-Length: %z\r\n" "Content-Type: %s\r\n" "\r\n", ENCRYPTED_VERSION, bodylen, mime_type); } else { preludelen = rspamd_snprintf(repbuf, sizeof(repbuf), "%s\r\n" "Content-Length: %z\r\n" "" "\r\n", ENCRYPTED_VERSION, bodylen); } } else { preludelen = rspamd_snprintf(repbuf, sizeof(repbuf), "%s\r\n\r\n", ENCRYPTED_VERSION); } enclen = rspamd_cryptobox_nonce_bytes(mode) + rspamd_cryptobox_mac_bytes(mode) + preludelen + /* version [content-length] + 2 * CRLF */ bodylen; } if (bodylen > 0) { priv->outlen++; } } else { if (msg->method < HTTP_SYMBOLS) { if (msg->body_buf.len == 0 || allow_shared) { pbody = NULL; bodylen = 0; priv->outlen = 2; if (msg->method == HTTP_INVALID) { msg->method = HTTP_GET; } } else { pbody = (char *) msg->body_buf.begin; bodylen = msg->body_buf.len; priv->outlen = 3; if (msg->method == HTTP_INVALID) { msg->method = HTTP_POST; } } } else if (msg->body_buf.len > 0) { allow_shared = FALSE; pbody = (char *) msg->body_buf.begin; bodylen = msg->body_buf.len; priv->outlen = 2; } else { /* Invalid body for spamc method */ abort(); } } peer_key = msg->peer_key; priv->wr_total = bodylen + 2; hdrcount = 0; if (msg->method < HTTP_SYMBOLS) { kh_foreach_value (msg->headers, hdr, { DL_FOREACH (hdr, hcur) { /* <name: value\r\n> */ priv->wr_total += hcur->combined->len; enclen += hcur->combined->len; priv->outlen ++; hdrcount ++; } }); } /* Allocate iov */ priv->out = g_malloc0(sizeof(struct iovec) * priv->outlen); priv->wr_pos = 0; meth_len = rspamd_http_message_write_header(mime_type, encrypted, repbuf, sizeof(repbuf), bodylen, enclen, host, conn, msg, &buf, priv, peer_key); priv->wr_total += buf->len; /* Setup external request body */ priv->out[0].iov_base = buf->str; priv->out[0].iov_len = buf->len; /* Buf will be used eventually for encryption */ if (encrypted) { int meth_offset, nonce_offset, mac_offset; mode = rspamd_keypair_alg(priv->local_key); ottery_rand_bytes(nonce, rspamd_cryptobox_nonce_bytes(mode)); memset(mac, 0, rspamd_cryptobox_mac_bytes(mode)); meth_offset = buf->len; if (conn->type == RSPAMD_HTTP_SERVER) { buf = rspamd_fstring_append(buf, repbuf, meth_len); } else { meth_len = strlen(http_method_str(msg->method)) + 1; /* + space */ buf = rspamd_fstring_append(buf, http_method_str(msg->method), meth_len - 1); buf = rspamd_fstring_append(buf, " ", 1); } nonce_offset = buf->len; buf = rspamd_fstring_append(buf, nonce, rspamd_cryptobox_nonce_bytes(mode)); mac_offset = buf->len; buf = rspamd_fstring_append(buf, mac, rspamd_cryptobox_mac_bytes(mode)); /* Need to be encrypted */ if (conn->type == RSPAMD_HTTP_SERVER) { buf = rspamd_fstring_append(buf, "\r\n\r\n", 4); } else { buf = rspamd_fstring_append(buf, repbuf, preludelen); } meth_pos = buf->str + meth_offset; np = buf->str + nonce_offset; mp = buf->str + mac_offset; } /* During previous writes, buf might be reallocated and changed */ priv->buf->data = buf; if (encrypted) { /* Finish external HTTP request */ priv->out[1].iov_base = "\r\n"; priv->out[1].iov_len = 2; /* Encrypt the real request */ rspamd_http_connection_encrypt_message(conn, msg, priv, pbody, bodylen, meth_pos, meth_len, preludelen, hdrcount, np, mp, peer_key); } else { i = 1; if (msg->method < HTTP_SYMBOLS) { kh_foreach_value (msg->headers, hdr, { DL_FOREACH (hdr, hcur) { priv->out[i].iov_base = hcur->combined->str; priv->out[i++].iov_len = hcur->combined->len; } }); priv->out[i].iov_base = "\r\n"; priv->out[i++].iov_len = 2; } else { /* No CRLF for compatibility reply */ priv->wr_total -= 2; } if (pbody != NULL) { priv->out[i].iov_base = pbody; priv->out[i++].iov_len = bodylen; } } priv->flags &= ~RSPAMD_HTTP_CONN_FLAG_RESETED; if ((priv->flags & RSPAMD_HTTP_CONN_FLAG_PROXY) && (conn->opts & RSPAMD_HTTP_CLIENT_SSL)) { /* We need to disable SSL flag! */ err = g_error_new(HTTP_ERROR, 400, "cannot use proxy for SSL connections"); rspamd_http_connection_ref(conn); conn->error_handler(conn, err); rspamd_http_connection_unref(conn); g_error_free(err); return FALSE; } rspamd_ev_watcher_stop(priv->ctx->event_loop, &priv->ev); if (conn->opts & RSPAMD_HTTP_CLIENT_SSL) { gpointer ssl_ctx = (msg->flags & RSPAMD_HTTP_FLAG_SSL_NOVERIFY) ? priv->ctx->ssl_ctx_noverify : priv->ctx->ssl_ctx; if (!ssl_ctx) { err = g_error_new(HTTP_ERROR, 400, "ssl message requested " "with no ssl ctx"); rspamd_http_connection_ref(conn); conn->error_handler(conn, err); rspamd_http_connection_unref(conn); g_error_free(err); return FALSE; } else { if (!priv->ssl) { priv->ssl = rspamd_ssl_connection_new(ssl_ctx, priv->ctx->event_loop, !(msg->flags & RSPAMD_HTTP_FLAG_SSL_NOVERIFY), conn->log_tag); g_assert(priv->ssl != NULL); if (!rspamd_ssl_connect_fd(priv->ssl, conn->fd, host, &priv->ev, priv->timeout, rspamd_http_event_handler, rspamd_http_ssl_err_handler, conn)) { err = g_error_new(HTTP_ERROR, 400, "ssl connection error: ssl error=%s, errno=%s", ERR_error_string(ERR_get_error(), NULL), strerror(errno)); rspamd_http_connection_ref(conn); conn->error_handler(conn, err); rspamd_http_connection_unref(conn); g_error_free(err); return FALSE; } } else { /* Just restore SSL handlers */ rspamd_ssl_connection_restore_handlers(priv->ssl, rspamd_http_event_handler, rspamd_http_ssl_err_handler, conn, EV_WRITE); } } } else { rspamd_ev_watcher_init(&priv->ev, conn->fd, EV_WRITE, rspamd_http_event_handler, conn); rspamd_ev_watcher_start(priv->ctx->event_loop, &priv->ev, priv->timeout); } return TRUE; } gboolean rspamd_http_connection_write_message(struct rspamd_http_connection *conn, struct rspamd_http_message *msg, const char *host, const char *mime_type, gpointer ud, ev_tstamp timeout) { return rspamd_http_connection_write_message_common(conn, msg, host, mime_type, ud, timeout, FALSE); } gboolean rspamd_http_connection_write_message_shared(struct rspamd_http_connection *conn, struct rspamd_http_message *msg, const char *host, const char *mime_type, gpointer ud, ev_tstamp timeout) { return rspamd_http_connection_write_message_common(conn, msg, host, mime_type, ud, timeout, TRUE); } void rspamd_http_connection_set_max_size(struct rspamd_http_connection *conn, gsize sz) { conn->max_size = sz; } void rspamd_http_connection_set_key(struct rspamd_http_connection *conn, struct rspamd_cryptobox_keypair *key) { struct rspamd_http_connection_private *priv = conn->priv; g_assert(key != NULL); priv->local_key = rspamd_keypair_ref(key); } void rspamd_http_connection_own_socket(struct rspamd_http_connection *conn) { struct rspamd_http_connection_private *priv = conn->priv; priv->flags |= RSPAMD_HTTP_CONN_OWN_SOCKET; } const struct rspamd_cryptobox_pubkey * rspamd_http_connection_get_peer_key(struct rspamd_http_connection *conn) { struct rspamd_http_connection_private *priv = conn->priv; if (priv->peer_key) { return priv->peer_key; } else if (priv->msg) { return priv->msg->peer_key; } return NULL; } gboolean rspamd_http_connection_is_encrypted(struct rspamd_http_connection *conn) { struct rspamd_http_connection_private *priv = conn->priv; if (priv->peer_key != NULL) { return TRUE; } else if (priv->msg) { return priv->msg->peer_key != NULL; } return FALSE; } GHashTable * rspamd_http_message_parse_query(struct rspamd_http_message *msg) { GHashTable *res; rspamd_fstring_t *key = NULL, *value = NULL; rspamd_ftok_t *key_tok = NULL, *value_tok = NULL; const char *p, *c, *end; struct http_parser_url u; enum { parse_key, parse_eqsign, parse_value, parse_ampersand } state = parse_key; res = g_hash_table_new_full(rspamd_ftok_icase_hash, rspamd_ftok_icase_equal, rspamd_fstring_mapped_ftok_free, rspamd_fstring_mapped_ftok_free); if (msg->url && msg->url->len > 0) { http_parser_parse_url(msg->url->str, msg->url->len, TRUE, &u); if (u.field_set & (1 << UF_QUERY)) { p = msg->url->str + u.field_data[UF_QUERY].off; c = p; end = p + u.field_data[UF_QUERY].len; while (p <= end) { switch (state) { case parse_key: if ((p == end || *p == '&') && p > c) { /* We have a single parameter without a value */ key = rspamd_fstring_new_init(c, p - c); key_tok = rspamd_ftok_map(key); key_tok->len = rspamd_url_decode(key->str, key->str, key->len); value = rspamd_fstring_new_init("", 0); value_tok = rspamd_ftok_map(value); g_hash_table_replace(res, key_tok, value_tok); state = parse_ampersand; } else if (*p == '=' && p > c) { /* We have something like key=value */ key = rspamd_fstring_new_init(c, p - c); key_tok = rspamd_ftok_map(key); key_tok->len = rspamd_url_decode(key->str, key->str, key->len); state = parse_eqsign; } else { p++; } break; case parse_eqsign: if (*p != '=') { c = p; state = parse_value; } else { p++; } break; case parse_value: if ((p == end || *p == '&') && p >= c) { g_assert(key != NULL); if (p > c) { value = rspamd_fstring_new_init(c, p - c); value_tok = rspamd_ftok_map(value); value_tok->len = rspamd_url_decode(value->str, value->str, value->len); /* Detect quotes for value */ if (value_tok->begin[0] == '"') { memmove(value->str, value->str + 1, value_tok->len - 1); value_tok->len--; } if (value_tok->begin[value_tok->len - 1] == '"') { value_tok->len--; } } else { value = rspamd_fstring_new_init("", 0); value_tok = rspamd_ftok_map(value); } g_hash_table_replace(res, key_tok, value_tok); key = value = NULL; key_tok = value_tok = NULL; state = parse_ampersand; } else { p++; } break; case parse_ampersand: if (p != end && *p != '&') { c = p; state = parse_key; } else { p++; } break; } } } if (state != parse_ampersand && key != NULL) { rspamd_fstring_free(key); } } return res; } struct rspamd_http_message * rspamd_http_message_ref(struct rspamd_http_message *msg) { REF_RETAIN(msg); return msg; } void rspamd_http_message_unref(struct rspamd_http_message *msg) { REF_RELEASE(msg); } void rspamd_http_connection_disable_encryption(struct rspamd_http_connection *conn) { struct rspamd_http_connection_private *priv; priv = conn->priv; if (priv) { if (priv->local_key) { rspamd_keypair_unref(priv->local_key); } if (priv->peer_key) { rspamd_pubkey_unref(priv->peer_key); } priv->local_key = NULL; priv->peer_key = NULL; priv->flags &= ~RSPAMD_HTTP_CONN_FLAG_ENCRYPTED; } }