1 /*
2   Copyright 2021 Northern.tech AS
3 
4   This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
5 
6   This program is free software; you can redistribute it and/or modify it
7   under the terms of the GNU General Public License as published by the
8   Free Software Foundation; version 3.
9 
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14 
15   You should have received a copy of the GNU General Public License
16   along with this program; if not, write to the Free Software
17   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
18 
19   To the extent this program is licensed as part of the Enterprise
20   versions of CFEngine, the applicable Commercial Open Source License
21   (COSL) may apply to this file if you as a licensee so wish it. See
22   included file COSL.txt.
23 */
24 
25 
26 #include <server_tls.h>
27 #include <server_common.h>
28 #include <protocol.h> // ParseProtocolVersionNetwork()
29 
30 #include <openssl/err.h>                                   /* ERR_get_error */
31 
32 #include <crypto.h>                                        /* DecryptString */
33 #include <conversion.h>
34 #include <signals.h>
35 #include <item_lib.h>                 /* IsMatchItemIn */
36 #include <lastseen.h>                 /* LastSaw1 */
37 #include <net.h>                      /* SendTransaction,ReceiveTransaction */
38 #include <tls_generic.h>              /* TLSSend */
39 #include <cf-serverd-enterprise-stubs.h>
40 #include <connection_info.h>
41 #include <regex.h>                                       /* StringMatchFull */
42 #include <known_dirs.h>
43 #include <file_lib.h>                                           /* IsDirReal */
44 
45 #include "server_access.h"          /* access_CheckResource, acl_CheckExact */
46 
47 
48 static SSL_CTX *SSLSERVERCONTEXT = NULL;
49 
50 #define MAX_ACCEPT_RETRIES 5
51 
52 /**
53  * @param[in]  priv_key private key to use (or %NULL to use the global PRIVKEY)
54  * @param[in]  pub_key public key to use (or %NULL to use the global PUBKEY)
55  * @param[out] ssl_ctx place to store the SSL context (or %NULL to use the
56  *                     global SSL_CTX)
57  * @warning Make sure you've called CryptoInitialize() first!
58  */
ServerTLSInitialize(RSA * priv_key,RSA * pub_key,SSL_CTX ** ssl_ctx)59 bool ServerTLSInitialize(RSA *priv_key, RSA *pub_key, SSL_CTX **ssl_ctx)
60 {
61     int ret;
62 
63     if (priv_key == NULL)
64     {
65         /* private key not specified, use the global one */
66         priv_key = PRIVKEY;
67     }
68     if (pub_key == NULL)
69     {
70         /* public key not specified, use the global one */
71         pub_key = PUBKEY;
72     }
73 
74     if (priv_key == NULL || pub_key == NULL)
75     {
76         Log(LOG_LEVEL_ERR, "Public/private key pair not loaded,"
77             " please create one using cf-key");
78         return false;
79     }
80 
81     if (!TLSGenericInitialize())
82     {
83         return false;
84     }
85 
86     if (ssl_ctx == NULL)
87     {
88         ssl_ctx = &SSLSERVERCONTEXT;
89     }
90     assert(*ssl_ctx == NULL);
91     *ssl_ctx = SSL_CTX_new(SSLv23_server_method());
92     if (*ssl_ctx == NULL)
93     {
94         Log(LOG_LEVEL_ERR, "SSL_CTX_new: %s",
95             TLSErrorString(ERR_get_error()));
96         return false;
97     }
98 
99     TLSSetDefaultOptions(*ssl_ctx, SERVER_ACCESS.allowtlsversion);
100 
101     /*
102      * CFEngine is not a web server so it does not need to support many
103      * ciphers. It only allows a safe but very common subset by default,
104      * extensible via "allowciphers" in body server control. By default
105      * the server side allows:
106      *
107      *     AES256-GCM-SHA384: most high-grade RSA-based cipher from TLSv1.2
108      *     AES256-SHA: most backwards compatible but high-grade, from SSLv3
109      *     TLS_AES_256_GCM_SHA384: most high-grade RSA-based cipher from TLSv1.3
110      *
111      * Client side is using the OpenSSL's defaults by default.
112      */
113     const char *cipher_list = SERVER_ACCESS.allowciphers;
114     if (cipher_list == NULL)
115     {
116 #ifdef SSL_OP_NO_TLSv1_3        /* defined if TLS 1.3 is supported */
117         cipher_list = "AES256-GCM-SHA384:AES256-SHA:TLS_AES_256_GCM_SHA384";
118 #else
119         cipher_list = "AES256-GCM-SHA384:AES256-SHA";
120 #endif
121     }
122 
123     if (!TLSSetCipherList(*ssl_ctx, cipher_list))
124     {
125         goto err;
126     }
127 
128     /* Create cert into memory and load it into SSL context. */
129     X509 *cert = TLSGenerateCertFromPrivKey(priv_key);
130     if (cert == NULL)
131     {
132         Log(LOG_LEVEL_ERR,
133             "Failed to generate in-memory certificate from private key");
134         goto err;
135     }
136 
137     SSL_CTX_use_certificate(*ssl_ctx, cert);
138     X509_free(cert);
139 
140     ret = SSL_CTX_use_RSAPrivateKey(*ssl_ctx, priv_key);
141     if (ret != 1)
142     {
143         Log(LOG_LEVEL_ERR, "Failed to use RSA private key: %s",
144             TLSErrorString(ERR_get_error()));
145         goto err;
146     }
147 
148     /* Verify cert consistency. */
149     ret = SSL_CTX_check_private_key(*ssl_ctx);
150     if (ret != 1)
151     {
152         Log(LOG_LEVEL_ERR, "Inconsistent key and TLS cert: %s",
153             TLSErrorString(ERR_get_error()));
154         goto err;
155     }
156 
157     return true;
158 
159   err:
160     SSL_CTX_free(*ssl_ctx);
161     *ssl_ctx = NULL;
162     return false;
163 }
164 
165 /**
166  * @param[in,out] priv_key private key to deinitalize (or %NULL to use the
167  *                         global PRIVKEY)
168  * @param[in,out] pub_key public key to deinitialize (or %NULL to use the
169  *                        global PUBKEY)
170  * @param[in,out] ssl_ctx the SSL context to deinitialize (or %NULL to use the
171  *                        global SSL_CTX)
172  */
ServerTLSDeInitialize(RSA ** priv_key,RSA ** pub_key,SSL_CTX ** ssl_ctx)173 void ServerTLSDeInitialize(RSA **priv_key, RSA **pub_key, SSL_CTX **ssl_ctx)
174 {
175     if (priv_key == NULL)
176     {
177         priv_key = &PRIVKEY;
178     }
179     if (pub_key == NULL)
180     {
181         pub_key = &PUBKEY;
182     }
183     if (ssl_ctx == NULL)
184     {
185         ssl_ctx = &SSLSERVERCONTEXT;
186     }
187 
188     if (*pub_key)
189     {
190         RSA_free(*pub_key);
191         *pub_key = NULL;
192     }
193 
194     if (*priv_key)
195     {
196         RSA_free(*priv_key);
197         *priv_key = NULL;
198     }
199 
200     if (*ssl_ctx != NULL)
201     {
202         SSL_CTX_free(*ssl_ctx);
203         *ssl_ctx = NULL;
204     }
205 }
206 
207 /**
208  * @brief Set the connection type to CLASSIC or TLS.
209 
210  * It is performed by peeking into the TLS connection to read the first bytes,
211  * and if it's a CAUTH protocol command use the old protocol loop, else use
212  * the TLS protocol loop.
213  * This must be the first thing we run on an accepted connection.
214  *
215  * @return true for success, false otherwise.
216  */
ServerTLSPeek(ConnectionInfo * conn_info)217 bool ServerTLSPeek(ConnectionInfo *conn_info)
218 {
219     assert(conn_info != NULL);
220 
221     assert(SSLSERVERCONTEXT != NULL);
222     assert(PRIVKEY != NULL);
223     assert(PUBKEY  != NULL);
224 
225     assert(ConnectionInfoProtocolVersion(conn_info) == CF_PROTOCOL_UNDEFINED);
226 
227     const int peek_size = CF_INBAND_OFFSET + sizeof("CAUTH");
228 
229     char buf[peek_size];
230     ssize_t got = recv(ConnectionInfoSocket(conn_info), buf, sizeof(buf), MSG_PEEK);
231     assert(got <= peek_size);
232     if (got < 0)
233     {
234         assert(got == -1);
235         Log(LOG_LEVEL_ERR, "TCP receive error: %s", GetErrorStr());
236         return false;
237     }
238     else if (got == 0)
239     {
240         Log(LOG_LEVEL_INFO,
241             "Peer closed TCP connection without sending data!");
242         return false;
243     }
244     else if (got < peek_size)
245     {
246         Log(LOG_LEVEL_INFO,
247             "Peer sent only %zd bytes! Considering the protocol as Classic",
248             got);
249         ConnectionInfoSetProtocolVersion(conn_info, CF_PROTOCOL_CLASSIC);
250     }
251     else if (memcmp(&buf[CF_INBAND_OFFSET], "CAUTH", strlen("CAUTH")) == 0)
252     {
253         Log(LOG_LEVEL_VERBOSE,
254             "Peeked CAUTH in TCP stream, considering the protocol as Classic");
255         ConnectionInfoSetProtocolVersion(conn_info, CF_PROTOCOL_CLASSIC);
256     }
257     else                                   /* got==peek_size && not "CAUTH" */
258     {
259         Log(LOG_LEVEL_VERBOSE,
260             "Peeked nothing important in TCP stream, considering the protocol as TLS");
261         ConnectionInfoSetProtocolVersion(conn_info, CF_PROTOCOL_TLS);
262     }
263     LogRaw(LOG_LEVEL_DEBUG, "Peeked data: ", buf, got);
264 
265     return true;
266 }
267 
268 /**
269  * 1. Send "CFE_v%d" server hello.
270  * 2. Receive two lines: One "CFE_v%d" with the protocol version the client
271  *    wishes to have, and one "IDENTITY USERNAME=blah ..." with identification
272  *    information for the client.
273  *
274  * @note For Identification dialog to end successfully, one "OK WELCOME" line
275  *       must be sent right after this function, after identity is verified.
276  *
277  * @TODO More protocol identity. E.g.
278  *       IDENTITY USERNAME=xxx HOSTNAME=xxx CUSTOMNAME=xxx
279  *
280  * @retval true if protocol version was successfully negotiated and IDENTITY
281  *         command was parsed correctly. Identity fields (only #username for
282  *         now) have the respective string values, or they are empty if field
283  *         was not on IDENTITY line.  #conn_info->protocol has been updated
284  *         with the negotiated protocol version.
285  * @retval false in case of error.
286  */
ServerIdentificationDialog(ConnectionInfo * conn_info,char * username,size_t username_size)287 bool ServerIdentificationDialog(ConnectionInfo *conn_info,
288                                 char *username, size_t username_size)
289 {
290     int ret;
291     char input[1024] = "";
292 
293     /* Send "CFE_v%d cf-serverd version". */
294     char version_string[CF_MAXVARSIZE];
295     int len = snprintf(version_string, sizeof(version_string),
296                        "CFE_v%d cf-serverd %s\n",
297                        CF_PROTOCOL_LATEST, VERSION);
298 
299     ret = TLSSend(conn_info->ssl, version_string, len);
300     if (ret != len)
301     {
302         Log(LOG_LEVEL_NOTICE, "Connection was hung up!");
303         return false;
304     }
305 
306     /* Receive CFE_v%d ... \n IDENTITY USERNAME=... */
307     int input_len = TLSRecvLines(conn_info->ssl, input, sizeof(input));
308     if (input_len <= 0)
309     {
310         Log(LOG_LEVEL_NOTICE,
311             "Client closed connection early! He probably does not trust our key...");
312         return false;
313     }
314 
315     const ProtocolVersion protocol = ParseProtocolVersionNetwork(input);
316     if (ProtocolIsUndefined(protocol))
317     {
318         Log(LOG_LEVEL_NOTICE,
319             "Protocol version negotiation failed! Received: %s",
320             input);
321         return false;
322     }
323 
324     /* This is already inside TLS code, so TLS is required at this point*/
325     if (ProtocolIsClassic(protocol))
326     {
327         Log(LOG_LEVEL_NOTICE,
328             "Client advertises disallowed protocol version: %d",
329             protocol);
330         return false;
331     }
332 
333     if (ProtocolIsTooNew(protocol))
334     {
335         Log(LOG_LEVEL_NOTICE,
336             "Client attempted a protocol version which is too new for us: %d",
337             protocol);
338         return false;
339     }
340 
341     assert(ProtocolIsKnown(protocol));
342 
343     /* Did we receive 2nd line or do we need to receive again? */
344     const char id_line[] = "\nIDENTITY ";
345     char *line2 = memmem(input, input_len, id_line, strlen(id_line));
346     if (line2 == NULL)
347     {
348         /* Wait for 2nd line to arrive. */
349         input_len = TLSRecvLines(conn_info->ssl, input, sizeof(input));
350         if (input_len <= 0)
351         {
352             Log(LOG_LEVEL_NOTICE,
353                 "Client closed connection during identification dialog!");
354             return false;
355         }
356         line2 = input;
357     }
358     else
359     {
360         line2++;                                               /* skip '\n' */
361     }
362 
363     /***** Parse all IDENTITY fields from line2 *****/
364 
365     char word1[1024], word2[1024];
366     int line2_pos = 0, chars_read = 0;
367 
368     /* Reset all identity variables, we'll set them according to fields
369      * on IDENTITY line. For now only "username" setting exists... */
370     username[0] = '\0';
371 
372     /* Assert sscanf() is safe to use. */
373     nt_static_assert(sizeof(word1) >= sizeof(input));
374     nt_static_assert(sizeof(word2) >= sizeof(input));
375 
376     ret = sscanf(line2, "IDENTITY %[^=]=%s%n", word1, word2, &chars_read);
377     while (ret >= 2)
378     {
379         /* Found USERNAME identity setting */
380         if (strcmp(word1, "USERNAME") == 0)
381         {
382             if ((strlen(word2) < username_size) && (IsUserNameValid(word2) == true))
383             {
384                 strcpy(username, word2);
385             }
386             else
387             {
388                 Log(LOG_LEVEL_NOTICE, "Received invalid IDENTITY: %s=%s",
389                     word1, word2);
390                 return false;
391             }
392             Log(LOG_LEVEL_VERBOSE, "Setting IDENTITY: %s=%s",
393                 word1, word2);
394         }
395         /* ... else if (strcmp()) for other acceptable IDENTITY parameters. */
396         else
397         {
398             Log(LOG_LEVEL_VERBOSE, "Received unknown IDENTITY parameter: %s=%s",
399                 word1, word2);
400         }
401 
402         line2_pos += chars_read;
403         ret = sscanf(&line2[line2_pos], " %[^=]=%s%n", word1, word2, &chars_read);
404     }
405 
406     /* Version client and server agreed on. */
407     assert(ProtocolIsKnown(protocol));
408     conn_info->protocol = protocol;
409 
410     return true;
411 }
412 
ServerSendWelcome(const ServerConnectionState * conn)413 bool ServerSendWelcome(const ServerConnectionState *conn)
414 {
415     char s[1024] = "OK WELCOME";
416     size_t len = strlen(s);
417     int ret;
418 
419     /* "OK WELCOME" is the important part. The rest is just extra verbosity. */
420     if (conn->username[0] != '\0')
421     {
422         ret = snprintf(&s[len], sizeof(s) - len, " %s=%s",
423                            "USERNAME", conn->username);
424         if (ret < 0)
425         {
426             Log(LOG_LEVEL_ERR,
427                 "Unexpected failure from snprintf (%d - %s) while "
428                 "constructing OK WELCOME message (ServerSendWelcome)",
429                 errno, GetErrorStr());
430             return false;
431         }
432         else if ((size_t) ret >= sizeof(s) - len)
433         {
434             Log(LOG_LEVEL_NOTICE, "Sending OK WELCOME message truncated: %s", s);
435             return false;
436         }
437         len += ret;
438     }
439 
440     /* Overwrite the terminating '\0', we don't need it anyway. */
441     s[len] = '\n';
442     len++;
443 
444     ret = TLSSend(conn->conn_info->ssl, s, len);
445     if (ret == -1)
446     {
447         return false;
448     }
449 
450     return true;
451 }
452 
453 /**
454  * @brief Accept a TLS connection and authenticate and identify.
455  *
456  * Doesn't include code for verifying key and lastseen
457  *
458  * @param conn    connection state
459  * @param ssl_ctx SSL context to use for the session (or %NULL to use the
460  *                default SSLSERVERCONTEXT)
461  *
462  * @see ServerTLSSessionEstablish
463  * @return true for success false otherwise
464  */
BasicServerTLSSessionEstablish(ServerConnectionState * conn,SSL_CTX * ssl_ctx)465 bool BasicServerTLSSessionEstablish(ServerConnectionState *conn, SSL_CTX *ssl_ctx)
466 {
467     if (conn->conn_info->status == CONNECTIONINFO_STATUS_ESTABLISHED)
468     {
469         return true;
470     }
471     if (ssl_ctx == NULL)
472     {
473         ssl_ctx = SSLSERVERCONTEXT;
474     }
475     assert(ConnectionInfoSSL(conn->conn_info) == NULL);
476     SSL *ssl = SSL_new(ssl_ctx);
477     if (ssl == NULL)
478     {
479         Log(LOG_LEVEL_ERR, "SSL_new: %s",
480             TLSErrorString(ERR_get_error()));
481         return false;
482     }
483     ConnectionInfoSetSSL(conn->conn_info, ssl);
484 
485     /* Pass conn_info inside the ssl struct for TLSVerifyCallback(). */
486     SSL_set_ex_data(ssl, CONNECTIONINFO_SSL_IDX, conn->conn_info);
487 
488     /* Now we are letting OpenSSL take over the open socket. */
489     SSL_set_fd(ssl, ConnectionInfoSocket(conn->conn_info));
490 
491     int remaining_tries = MAX_ACCEPT_RETRIES;
492     int ret = -1;
493     bool should_retry = true;
494     while ((ret < 0) && should_retry)
495     {
496         ret = SSL_accept(ssl);
497         if (ret < 0)
498         {
499             int code = TLSLogError(ssl, LOG_LEVEL_VERBOSE, "SSL accept failed", ret);
500             should_retry = ((remaining_tries > 0) &&
501                             ((code == SSL_ERROR_WANT_READ) || (code == SSL_ERROR_WANT_WRITE)));
502 
503         }
504         if ((ret < 0) && should_retry)
505         {
506             sleep(1);
507             remaining_tries--;
508         }
509     }
510     if (ret <= 0)
511     {
512         TLSLogError(ssl, LOG_LEVEL_ERR,
513                     "Failed to accept TLS connection", ret);
514         return false;
515     }
516 
517     Log(LOG_LEVEL_VERBOSE, "TLS version negotiated: %8s; Cipher: %s,%s",
518         SSL_get_version(ssl),
519         SSL_get_cipher_name(ssl),
520         SSL_get_cipher_version(ssl));
521 
522     return true;
523 }
524 
525 /**
526  * @brief Accept a TLS connection and authenticate and identify.
527  *
528  * This function uses trustkeys to trust new keys and updates lastseen
529  *
530  * @param conn    connection state
531  * @param ssl_ctx SSL context to use for the session (or %NULL to use the
532  *                default SSLSERVERCONTEXT)
533  *
534  * @see BasicServerTLSSessionEstablish
535  * @note Various fields in #conn are set, like username and keyhash.
536  * @return true for success false otherwise
537  */
ServerTLSSessionEstablish(ServerConnectionState * conn,SSL_CTX * ssl_ctx)538 bool ServerTLSSessionEstablish(ServerConnectionState *conn, SSL_CTX *ssl_ctx)
539 {
540     if (conn->conn_info->status == CONNECTIONINFO_STATUS_ESTABLISHED)
541     {
542         return true;
543     }
544 
545     bool established = BasicServerTLSSessionEstablish(conn, ssl_ctx);
546     if (!established)
547     {
548         return false;
549     }
550 
551     Log(LOG_LEVEL_VERBOSE, "TLS session established, checking trust...");
552 
553     /* Send/Receive "CFE_v%d" version string, agree on version, receive
554        identity (username) of peer. */
555     char username[sizeof(conn->username)] = "";
556     bool id_success = ServerIdentificationDialog(conn->conn_info,
557                                                  username, sizeof(username));
558     if (!id_success)
559     {
560         return false;
561     }
562 
563     /* We *now* (maybe a bit late) verify the key that the client sent us in
564      * the TLS handshake, since we need the username to do so. TODO in the
565      * future store keys irrelevant of username, so that we can match them
566      * before IDENTIFY. */
567     int ret = TLSVerifyPeer(conn->conn_info, conn->ipaddr, username);
568     if (ret == -1)                                      /* error */
569     {
570         return false;
571     }
572 
573     if (ret == 1)                                    /* trusted key */
574     {
575         Log(LOG_LEVEL_VERBOSE,
576             "%s: Client is TRUSTED, public key MATCHES stored one.",
577             KeyPrintableHash(ConnectionInfoKey(conn->conn_info)));
578     }
579 
580     if (ret == 0)                                  /* untrusted key */
581     {
582         if ((SERVER_ACCESS.trustkeylist != NULL) &&
583             (IsMatchItemIn(SERVER_ACCESS.trustkeylist, conn->ipaddr)))
584         {
585             Log(LOG_LEVEL_VERBOSE,
586                 "Peer was found in \"trustkeysfrom\" list");
587             Log(LOG_LEVEL_NOTICE, "Trusting new key: %s",
588                 KeyPrintableHash(ConnectionInfoKey(conn->conn_info)));
589 
590             SavePublicKey(username, KeyPrintableHash(conn->conn_info->remote_key),
591                           KeyRSA(ConnectionInfoKey(conn->conn_info)));
592         }
593         else
594         {
595             Log(LOG_LEVEL_NOTICE,
596                 "TRUST FAILED, peer presented an untrusted key, dropping connection!");
597             Log(LOG_LEVEL_VERBOSE,
598                 "Add peer to \"trustkeysfrom\" if you really want to start trusting this new key.");
599             return false;
600         }
601     }
602 
603     /* All checks succeeded, set conn->uid (conn->sid for Windows)
604      * according to the received USERNAME identity. */
605     SetConnIdentity(conn, username);
606 
607     /* No CAUTH, SAUTH in non-classic protocol. */
608     conn->user_data_set = true;
609     conn->rsa_auth = true;
610 
611     LastSaw1(conn->ipaddr, KeyPrintableHash(ConnectionInfoKey(conn->conn_info)),
612              LAST_SEEN_ROLE_ACCEPT);
613 
614     ServerSendWelcome(conn);
615     return true;
616 }
617 
618 //*******************************************************************
619 // COMMANDS
620 //*******************************************************************
621 
GetCommandNew(char * str)622 ProtocolCommandNew GetCommandNew(char *str)
623 {
624     int i;
625     for (i = 0; PROTOCOL_NEW[i] != NULL; i++)
626     {
627         int cmdlen = strlen(PROTOCOL_NEW[i]);
628         if ((strncmp(str, PROTOCOL_NEW[i], cmdlen) == 0) &&
629             (str[cmdlen] == ' ' || str[cmdlen] == '\0'))
630         {
631             return i;
632         }
633     }
634     assert (i == PROTOCOL_COMMAND_BAD);
635     return i;
636 }
637 
638 
639 /**
640  * Currently this function returns false when we want the connection
641  * closed, and true, when we want to proceed further with requests.
642  *
643  * @TODO So we need this function to return more than true/false, because now
644  * we return true even when access is denied! E.g. return -1 for error, 0 on
645  * success, 1 on access denied. It can be an option if connection will close
646  * on denial.
647  */
BusyWithNewProtocol(EvalContext * ctx,ServerConnectionState * conn)648 bool BusyWithNewProtocol(EvalContext *ctx, ServerConnectionState *conn)
649 {
650     assert(conn != NULL);
651 
652     /* The CF_BUFEXT extra space is there to ensure we're not *reading* out of
653      * bounds in commands that carry extra binary arguments, like MD5. */
654     char recvbuffer[CF_BUFSIZE + CF_BUFEXT] = { 0 };
655     /* This size is the max we can SendTransaction(). */
656     char sendbuffer[CF_BUFSIZE - CF_INBAND_OFFSET] = { 0 };
657     char filename[CF_BUFSIZE + 1];      /* +1 for appending slash sometimes */
658     ServerFileGetState get_args = { 0 };
659 
660     /* We already encrypt because of the TLS layer, no need to encrypt more. */
661     const int encrypted = 0;
662 
663     /* Legacy stuff only for old protocol. */
664     assert(conn->rsa_auth == true);
665     assert(conn->user_data_set == true);
666 
667     /* Receive up to CF_BUFSIZE - 1 bytes. */
668     const int received = ReceiveTransaction(conn->conn_info,
669                                             recvbuffer, NULL);
670 
671     if (received == -1)
672     {
673         /* Already Log()ged in case of error. */
674         return false;
675     }
676     if (received > CF_BUFSIZE - 1)
677     {
678         UnexpectedError("Received transaction of size %d", received);
679         return false;
680     }
681 
682     if (strlen(recvbuffer) == 0)
683     {
684         Log(LOG_LEVEL_WARNING,
685             "Got NULL transmission (of size %d)", received);
686         return true;
687     }
688     /* Don't process request if we're signalled to exit. */
689     if (IsPendingTermination())
690     {
691         Log(LOG_LEVEL_VERBOSE, "Server must exit, closing connection");
692         return false;
693     }
694 
695     /* TODO break recvbuffer here: command, param1, param2 etc. */
696 
697     switch (GetCommandNew(recvbuffer))
698     {
699     case PROTOCOL_COMMAND_EXEC:
700     {
701         const size_t EXEC_len = strlen(PROTOCOL_NEW[PROTOCOL_COMMAND_EXEC]);
702         /* Assert recvbuffer starts with EXEC. */
703         assert(strncmp(PROTOCOL_NEW[PROTOCOL_COMMAND_EXEC],
704                        recvbuffer, EXEC_len) == 0);
705 
706         char *args = &recvbuffer[EXEC_len];
707         args += strspn(args, " \t");                       /* bypass spaces */
708 
709         Log(LOG_LEVEL_VERBOSE, "%14s %7s %s",
710             "Received:", "EXEC", args);
711 
712         bool b = DoExec2(ctx, conn, args,
713                          sendbuffer, sizeof(sendbuffer));
714 
715         /* In the end we might keep the connection open (return true) to be
716          * ready for next requests, but we must always send the TERMINATOR
717          * string so that the client can close the connection at will. */
718         Terminate(conn->conn_info);
719 
720         return b;
721     }
722     case PROTOCOL_COMMAND_VERSION:
723 
724         snprintf(sendbuffer, sizeof(sendbuffer), "OK: %s", Version());
725         SendTransaction(conn->conn_info, sendbuffer, 0, CF_DONE);
726         return true;
727 
728     case PROTOCOL_COMMAND_GET:
729     {
730         int ret = sscanf(recvbuffer, "GET %d %[^\n]",
731                          &(get_args.buf_size), filename);
732 
733         if (ret != 2 ||
734             get_args.buf_size <= 0 || get_args.buf_size > CF_BUFSIZE)
735         {
736             goto protocol_error;
737         }
738 
739         Log(LOG_LEVEL_VERBOSE, "%14s %7s %s",
740             "Received:", "GET", filename);
741 
742         /* TODO batch all the following in one function since it's very
743          * similar in all of GET, OPENDIR and STAT. */
744 
745         size_t zret = ShortcutsExpand(filename, sizeof(filename),
746                                      SERVER_ACCESS.path_shortcuts,
747                                      conn->ipaddr, conn->revdns,
748                                      KeyPrintableHash(ConnectionInfoKey(conn->conn_info)));
749         if (zret == (size_t) -1)
750         {
751             goto protocol_error;
752         }
753 
754         zret = PreprocessRequestPath(filename, sizeof(filename));
755         if (zret == (size_t) -1)
756         {
757             RefuseAccess(conn, recvbuffer);
758             return true;
759         }
760 
761         PathRemoveTrailingSlash(filename, strlen(filename));
762 
763         Log(LOG_LEVEL_VERBOSE, "%14s %7s %s",
764             "Translated to:", "GET", filename);
765 
766         if (acl_CheckPath(paths_acl, filename,
767                           conn->ipaddr, conn->revdns,
768                           KeyPrintableHash(ConnectionInfoKey(conn->conn_info)))
769             == false)
770         {
771             Log(LOG_LEVEL_INFO, "access denied to GET: %s", filename);
772             RefuseAccess(conn, recvbuffer);
773             return true;
774         }
775 
776         memset(sendbuffer, 0, sizeof(sendbuffer));
777 
778         if (get_args.buf_size >= CF_BUFSIZE)
779         {
780             get_args.buf_size = 2048;
781         }
782 
783         /* TODO eliminate! */
784         get_args.conn = conn;
785         get_args.encrypt = false;
786         get_args.replybuff = sendbuffer;
787         get_args.replyfile = filename;
788 
789         CfGetFile(&get_args);
790 
791         return true;
792     }
793     case PROTOCOL_COMMAND_OPENDIR:
794     {
795         memset(filename, 0, sizeof(filename));
796         int ret = sscanf(recvbuffer, "OPENDIR %[^\n]", filename);
797         if (ret != 1)
798         {
799             goto protocol_error;
800         }
801 
802         Log(LOG_LEVEL_VERBOSE, "%14s %7s %s",
803             "Received:", "OPENDIR", filename);
804 
805         /* sizeof()-1 because we need one extra byte for
806            appending '/' afterwards. */
807         size_t zret = ShortcutsExpand(filename, sizeof(filename) - 1,
808                                       SERVER_ACCESS.path_shortcuts,
809                                       conn->ipaddr, conn->revdns,
810                                       KeyPrintableHash(ConnectionInfoKey(conn->conn_info)));
811         if (zret == (size_t) -1)
812         {
813             goto protocol_error;
814         }
815 
816         zret = PreprocessRequestPath(filename, sizeof(filename) - 1);
817         if (zret == (size_t) -1)
818         {
819             RefuseAccess(conn, recvbuffer);
820             return true;
821         }
822 
823         /* OPENDIR *must* be directory. */
824         PathAppendTrailingSlash(filename, strlen(filename));
825 
826         Log(LOG_LEVEL_VERBOSE, "%14s %7s %s",
827             "Translated to:", "OPENDIR", filename);
828 
829         if (acl_CheckPath(paths_acl, filename,
830                           conn->ipaddr, conn->revdns,
831                           KeyPrintableHash(ConnectionInfoKey(conn->conn_info)))
832             == false)
833         {
834             Log(LOG_LEVEL_INFO, "access denied to OPENDIR: %s", filename);
835             RefuseAccess(conn, recvbuffer);
836             return true;
837         }
838 
839         CfOpenDirectory(conn, sendbuffer, filename);
840         return true;
841     }
842     case PROTOCOL_COMMAND_SYNCH:
843     {
844         long time_no_see = 0;
845         memset(filename, 0, sizeof(filename));
846         int ret = sscanf(recvbuffer, "SYNCH %ld STAT %[^\n]",
847                          &time_no_see, filename);
848 
849         if (ret != 2 || filename[0] == '\0')
850         {
851             goto protocol_error;
852         }
853 
854         time_t tloc = time(NULL);
855         if (tloc == -1)
856         {
857             /* Should never happen. */
858             Log(LOG_LEVEL_ERR, "Couldn't read system clock. (time: %s)", GetErrorStr());
859             SendTransaction(conn->conn_info, "BAD: clocks out of synch", 0, CF_DONE);
860             return true;
861         }
862 
863         time_t trem = (time_t) time_no_see;
864         int drift = (int) (tloc - trem);
865 
866         Log(LOG_LEVEL_VERBOSE, "%14s %7s %s",
867             "Received:", "STAT", filename);
868 
869         /* sizeof()-1 because we need one extra byte for
870            appending '/' afterwards. */
871         size_t zret = ShortcutsExpand(filename, sizeof(filename) - 1,
872                                       SERVER_ACCESS.path_shortcuts,
873                                       conn->ipaddr, conn->revdns,
874                                       KeyPrintableHash(ConnectionInfoKey(conn->conn_info)));
875         if (zret == (size_t) -1)
876         {
877             goto protocol_error;
878         }
879 
880         zret = PreprocessRequestPath(filename, sizeof(filename) - 1);
881         if (zret == (size_t) -1)
882         {
883             RefuseAccess(conn, recvbuffer);
884             return true;
885         }
886 
887         if (IsDirReal(filename))
888         {
889             PathAppendTrailingSlash(filename, strlen(filename));
890         }
891         else
892         {
893             PathRemoveTrailingSlash(filename, strlen(filename));
894         }
895 
896         Log(LOG_LEVEL_VERBOSE, "%14s %7s %s",
897             "Translated to:", "STAT", filename);
898 
899         if (acl_CheckPath(paths_acl, filename,
900                           conn->ipaddr, conn->revdns,
901                           KeyPrintableHash(ConnectionInfoKey(conn->conn_info)))
902             == false)
903         {
904             Log(LOG_LEVEL_INFO, "access denied to STAT: %s", filename);
905             RefuseAccess(conn, recvbuffer);
906             return true;
907         }
908 
909         Log(LOG_LEVEL_DEBUG, "Clocks were off by %ld",
910             (long) tloc - (long) trem);
911 
912         if (DENYBADCLOCKS && (drift * drift > CLOCK_DRIFT * CLOCK_DRIFT))
913         {
914             snprintf(sendbuffer, sizeof(sendbuffer),
915                      "BAD: Clocks are too far unsynchronized %ld/%ld",
916                      (long) tloc, (long) trem);
917             Log(LOG_LEVEL_INFO, "denybadclocks %s", sendbuffer);
918             SendTransaction(conn->conn_info, sendbuffer, 0, CF_DONE);
919             return true;
920         }
921 
922         StatFile(conn, sendbuffer, filename);
923 
924         return true;
925     }
926     case PROTOCOL_COMMAND_MD5:
927     {
928         int ret = sscanf(recvbuffer, "MD5 %[^\n]", filename);
929         if (ret != 1)
930         {
931             goto protocol_error;
932         }
933 
934         Log(LOG_LEVEL_VERBOSE, "%14s %7s %s",
935             "Received:", "MD5", filename);
936 
937         /* TODO batch all the following in one function since it's very
938          * similar in all of GET, OPENDIR and STAT. */
939 
940         size_t zret = ShortcutsExpand(filename, sizeof(filename),
941                                      SERVER_ACCESS.path_shortcuts,
942                                      conn->ipaddr, conn->revdns,
943                                      KeyPrintableHash(ConnectionInfoKey(conn->conn_info)));
944         if (zret == (size_t) -1)
945         {
946             goto protocol_error;
947         }
948 
949         zret = PreprocessRequestPath(filename, sizeof(filename));
950         if (zret == (size_t) -1)
951         {
952             RefuseAccess(conn, recvbuffer);
953             return true;
954         }
955 
956         PathRemoveTrailingSlash(filename, strlen(filename));
957 
958         Log(LOG_LEVEL_VERBOSE, "%14s %7s %s",
959             "Translated to:", "MD5", filename);
960 
961         if (acl_CheckPath(paths_acl, filename,
962                           conn->ipaddr, conn->revdns,
963                           KeyPrintableHash(ConnectionInfoKey(conn->conn_info)))
964             == false)
965         {
966             Log(LOG_LEVEL_INFO, "access denied to file: %s", filename);
967             RefuseAccess(conn, recvbuffer);
968             return true;
969         }
970 
971         assert(CF_DEFAULT_DIGEST_LEN <= EVP_MAX_MD_SIZE);
972         unsigned char digest[EVP_MAX_MD_SIZE + 1];
973 
974         assert(CF_BUFSIZE + CF_SMALL_OFFSET + (size_t) CF_DEFAULT_DIGEST_LEN
975                <= sizeof(recvbuffer));
976         memcpy(digest, recvbuffer + strlen(recvbuffer) + CF_SMALL_OFFSET,
977                CF_DEFAULT_DIGEST_LEN);
978 
979         CompareLocalHash(filename, digest, sendbuffer);
980         SendTransaction(conn->conn_info, sendbuffer, 0, CF_DONE);
981 
982         return true;
983     }
984     case PROTOCOL_COMMAND_VAR:
985     {
986         char var[256];
987         int ret = sscanf(recvbuffer, "VAR %255[^\n]", var);
988         if (ret != 1)
989         {
990             goto protocol_error;
991         }
992 
993         /* TODO if this is literals_acl, then when should I check vars_acl? */
994         if (acl_CheckExact(literals_acl, var,
995                            conn->ipaddr, conn->revdns,
996                            KeyPrintableHash(ConnectionInfoKey(conn->conn_info)))
997             == false)
998         {
999             Log(LOG_LEVEL_INFO, "access denied to variable: %s", var);
1000             RefuseAccess(conn, recvbuffer);
1001             return true;
1002         }
1003 
1004         GetServerLiteral(ctx, conn, sendbuffer, recvbuffer, encrypted);
1005         return true;
1006     }
1007     case PROTOCOL_COMMAND_CONTEXT:
1008     {
1009         char client_regex[256];
1010         int ret = sscanf(recvbuffer, "CONTEXT %255[^\n]", client_regex);
1011         if (ret != 1)
1012         {
1013             goto protocol_error;
1014         }
1015 
1016         Log(LOG_LEVEL_VERBOSE, "%14s %7s %s",
1017             "Received:", "CONTEXT", client_regex);
1018 
1019         /* WARNING: this comes from legacy code and must be killed if we care
1020          * about performance. We should not accept regular expressions from
1021          * the client, but this will break backwards compatibility.
1022          *
1023          * I replicated the code in raw form here to emphasize complexity,
1024          * it's the only *slow* command currently in the protocol.  */
1025 
1026         Item *persistent_classes = ListPersistentClasses();
1027         Item *matched_classes = NULL;
1028 
1029         /* For all persistent classes */
1030         for (Item *ip = persistent_classes; ip != NULL; ip = ip->next)
1031         {
1032             const char *class_name = ip->name;
1033 
1034             /* Does this class match the regex the client sent? */
1035             if (StringMatchFull(client_regex, class_name))
1036             {
1037                 /* Is this class allowed to be given to the specific
1038                  * host, according to the regexes in the ACLs? */
1039                 if (acl_CheckRegex(classes_acl, class_name,
1040                                    conn->ipaddr, conn->revdns,
1041                                    KeyPrintableHash(ConnectionInfoKey(conn->conn_info)),
1042                                    NULL)
1043                     == true)
1044                 {
1045                     Log(LOG_LEVEL_DEBUG, "Access granted to class: %s",
1046                         class_name);
1047                     PrependItem(&matched_classes, class_name, NULL);
1048                 }
1049             }
1050         }
1051 
1052         if (matched_classes == NULL)
1053         {
1054             Log(LOG_LEVEL_INFO,
1055                 "No allowed classes for remoteclassesmatching: %s",
1056                 client_regex);
1057             RefuseAccess(conn, recvbuffer);
1058             return true;
1059         }
1060 
1061         ReplyServerContext(conn, encrypted, matched_classes);
1062         return true;
1063     }
1064     case PROTOCOL_COMMAND_QUERY:
1065     {
1066         char query[256], name[128];
1067         int ret1 = sscanf(recvbuffer, "QUERY %255[^\n]", query);
1068         int ret2 = sscanf(recvbuffer, "QUERY %127s", name);
1069         if (ret1 != 1 || ret2 != 1)
1070         {
1071             goto protocol_error;
1072         }
1073 
1074         const char *hostkey = KeyPrintableHash(
1075             ConnectionInfoKey(conn->conn_info));
1076         const bool access_to_query = acl_CheckExact(
1077             query_acl, name, conn->ipaddr, conn->revdns, hostkey);
1078 
1079         if (!access_to_query)
1080         {
1081             Log(LOG_LEVEL_INFO, "access denied to query: %s", query);
1082             RefuseAccess(conn, recvbuffer);
1083             return true;
1084         }
1085 
1086         if (GetServerQuery(conn, recvbuffer, encrypted))
1087         {
1088             return true;
1089         }
1090 
1091         break;
1092     }
1093     case PROTOCOL_COMMAND_COOKIE:
1094     {
1095         if (ConnectionInfoProtocolVersion(conn->conn_info) < CF_PROTOCOL_COOKIE)
1096         {
1097             goto protocol_error;
1098         }
1099 
1100         const char *hostkey = KeyPrintableHash(
1101             ConnectionInfoKey(conn->conn_info));
1102         const bool access_to_query_delta = acl_CheckExact(
1103             query_acl, "delta", conn->ipaddr, conn->revdns, hostkey);
1104 
1105         if (!access_to_query_delta)
1106         {
1107             Log(LOG_LEVEL_INFO, "access denied to cookie query: %s", recvbuffer);
1108             RefuseAccess(conn, recvbuffer);
1109             return true;
1110         }
1111 
1112         if (ReturnCookies(conn))
1113         {
1114             return true;
1115         }
1116 
1117         break;
1118     }
1119     case PROTOCOL_COMMAND_CALL_ME_BACK:
1120         /* Server side, handing the collect call off to cf-hub. */
1121 
1122         if (acl_CheckExact(query_acl, "collect_calls",
1123                            conn->ipaddr, conn->revdns,
1124                            KeyPrintableHash(ConnectionInfoKey(conn->conn_info)))
1125             == false)
1126         {
1127             Log(LOG_LEVEL_INFO,
1128                 "access denied to Call-Collect, check the ACL for class: collect_calls");
1129             return false;
1130         }
1131 
1132         ReceiveCollectCall(conn);
1133         /* On success that returned true; otherwise, it did all
1134          * relevant Log()ging.  Either way, we're no longer busy with
1135          * it and our caller can close the connection: */
1136         return false;
1137 
1138     case PROTOCOL_COMMAND_BAD:
1139 
1140         Log(LOG_LEVEL_WARNING, "Unexpected protocol command: %s", recvbuffer);
1141     }
1142 
1143     /* We should only reach this point if something went really bad, and
1144      * close connection. In all other cases (like access denied) connection
1145      * shouldn't be closed.
1146      */
1147 
1148 protocol_error:
1149     strcpy(sendbuffer, "BAD: Request denied");
1150     SendTransaction(conn->conn_info, sendbuffer, 0, CF_DONE);
1151     Log(LOG_LEVEL_INFO,
1152         "Closing connection due to illegal request: %s", recvbuffer);
1153     return false;
1154 }
1155