cfengine  3.15.4
About: CFEngine is a configuration management system for configuring and maintaining Unix-like computers (using an own high level policy language). Community version.
  Fossies Dox: cfengine-3.15.4.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

server_classic.c
Go to the documentation of this file.
1 /*
2  Copyright 2019 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 #include <platform.h>
25 
26 #include <openssl/bn.h> /* BN_* */
27 #include <openssl/err.h> /* ERR_get_error */
28 #include <libcrypto-compat.h>
29 
30 #include <cf3.defs.h>
31 #include <item_lib.h> /* IsMatchItemIn */
32 #include <matching.h> /* IsRegexItemIn */
33 #include <net.h> /* ReceiveTransaction,SendTransaction */
34 #include <signals.h>
35 #include <string_lib.h> /* ToLowerStrInplace */
36 #include <regex.h> /* StringMatchFull */
37 #include <lastseen.h> /* LastSaw1 */
38 #include <hash.h> /* HashString */
39 #include <crypto.h> /* HavePublicKey */
40 #include <cf-serverd-enterprise-stubs.h> /* ReceiveCollectCall */
41 #include <tls_generic.h>
42 
43 #include "server.h" /* ServerConnectionState */
44 #include "server_common.h" /* ListPersistentClasses */
45 
46 
47 /* Functionality needed exclusively for the classic protocol. */
48 
49 
50 //*******************************************************************
51 // COMMANDS
52 //*******************************************************************
53 
54 typedef enum
55 {
78 
79 static const char *PROTOCOL_CLASSIC[] =
80 {
81  "EXEC",
82  "AUTH", /* old protocol */
83  "GET",
84  "OPENDIR",
85  "SYNCH",
86  "CLASSES",
87  "MD5",
88  "SMD5",
89  "CAUTH",
90  "SAUTH",
91  "SSYNCH",
92  "SGET",
93  "VERSION",
94  "SOPENDIR",
95  "VAR",
96  "SVAR",
97  "CONTEXT",
98  "SCONTEXT",
99  "SQUERY",
100  "SCALLBACK",
101  NULL
102 };
103 
105 {
106  int i;
107  for (i = 0; PROTOCOL_CLASSIC[i] != NULL; i++)
108  {
109  int cmdlen = strlen(PROTOCOL_CLASSIC[i]);
110  if ((strncmp(str, PROTOCOL_CLASSIC[i], cmdlen) == 0) &&
111  (str[cmdlen] == ' ' || str[cmdlen] == '\0'))
112  {
113  return i;
114  }
115  }
116  assert (i == PROTOCOL_COMMAND_BAD);
117  return i;
118 }
119 
120 
121 /* 'resolved' argument needs to be at least CF_BUFSIZE long */
122 static bool ResolveFilename(const char *req_path, char *res_path)
123 {
124 
125 #if !defined _WIN32
126  if (realpath(req_path, res_path) == NULL)
127  {
128  return false;
129  }
130 #else
131  memset(res_path, 0, CF_BUFSIZE);
132  CompressPath(res_path, CF_BUFSIZE, req_path);
133 #endif
134 
135  /* Adjust for forward slashes */
136  MapName(res_path);
137 
138 /* NT has case-insensitive path names */
139 #ifdef __MINGW32__
140  int i;
141 
142  for (i = 0; i < strlen(res_path); i++)
143  {
144  res_path[i] = ToLower(res_path[i]);
145  }
146 #endif /* __MINGW32__ */
147 
148  return true;
149 }
150 
151 static bool PathMatch(const char *stem, const char *request)
152 {
153  const size_t stemlen = strlen(stem);
154  if (strcmp(stem, FILE_SEPARATOR_STR) == 0)
155  {
156  /* Matches everything: */
157  return true;
158  }
159 
160  if (strcmp(stem, request) == 0)
161  {
162  /* An exact match is a match: */
163  return true;
164  }
165 
166  /* Otherwise, match only if stem names a parent directory of request: */
167  return (strlen(request) > stemlen &&
168  request[stemlen] == FILE_SEPARATOR &&
169  strncmp(stem, request, stemlen) == 0);
170 }
171 
172 static bool AccessControl(EvalContext *ctx, const char *req_path, ServerConnectionState *conn, int encrypt)
173 {
174  bool access = false;
175  char transrequest[CF_BUFSIZE];
176  struct stat statbuf;
177  char translated_req_path[CF_BUFSIZE];
178  char transpath[CF_BUFSIZE];
179 
180 /*
181  * /var/cfengine -> $workdir translation.
182  */
183  TranslatePath(translated_req_path, req_path);
184 
185  if (ResolveFilename(translated_req_path, transrequest))
186  {
187  Log(LOG_LEVEL_VERBOSE, "Filename %s is resolved to %s", translated_req_path, transrequest);
188  }
189  else if ((lstat(translated_req_path, &statbuf) == -1) && !S_ISLNK(statbuf.st_mode))
190  {
191  Log(LOG_LEVEL_INFO, "Couldn't resolve (realpath: %s) filename: %s",
192  GetErrorStr(), translated_req_path);
193  return false; /* can't continue without transrequest */
194  }
195  else
196  {
197  Log(LOG_LEVEL_VERBOSE, "Requested file is a dead symbolic link (filename: %s)", translated_req_path);
198  strlcpy(transrequest, translated_req_path, CF_BUFSIZE);
199  }
200 
201  if (lstat(transrequest, &statbuf) == -1)
202  {
203  Log(LOG_LEVEL_INFO, "Couldn't stat (lstat: %s) filename: %s",
204  GetErrorStr(), transrequest);
205  return false;
206  }
207 
208  Log(LOG_LEVEL_DEBUG, "AccessControl, match (%s,%s) encrypt request = %d", transrequest, conn->hostname, encrypt);
209 
210  if (SERVER_ACCESS.admit == NULL)
211  {
212  Log(LOG_LEVEL_INFO, "cf-serverd access list is empty, no files are visible");
213  return false;
214  }
215 
216  conn->maproot = false;
217 
218  for (Auth *ap = SERVER_ACCESS.admit; ap != NULL; ap = ap->next)
219  {
220  Log(LOG_LEVEL_DEBUG, "Examining rule in access list (%s,%s)", transrequest, ap->path);
221 
222  /* TODO MapName when constructing this list. */
223  strlcpy(transpath, ap->path, CF_BUFSIZE);
224  MapName(transpath);
225 
226  if (PathMatch(transpath, transrequest))
227  {
228  Log(LOG_LEVEL_VERBOSE, "Found a matching rule in access list (%s in %s)", transrequest, transpath);
229 
230  if (stat(transpath, &statbuf) == -1)
231  {
233  "Warning cannot stat file object %s in admit/grant, or access list refers to dangling link",
234  transpath);
235  continue;
236  }
237 
238  if (!encrypt && ap->encrypt)
239  {
240  Log(LOG_LEVEL_ERR, "File %s requires encrypt connection...will not serve", transpath);
241  access = false;
242  }
243  else
244  {
245  Log(LOG_LEVEL_DEBUG, "Checking whether to map root privileges..");
246 
247  if (IsMatchItemIn(ap->maproot, conn->ipaddr) ||
248  IsRegexItemIn(ctx, ap->maproot, conn->hostname))
249  {
250  conn->maproot = true;
251  Log(LOG_LEVEL_VERBOSE, "Mapping root privileges to access non-root files");
252  }
253 
254  if (IsMatchItemIn(ap->accesslist, conn->ipaddr) ||
255  IsRegexItemIn(ctx, ap->accesslist, conn->hostname))
256  {
257  access = true;
258  Log(LOG_LEVEL_DEBUG, "Access granted to host: %s", conn->ipaddr);
259  }
260  }
261  break;
262  }
263  }
264 
265  for (Auth *dp = SERVER_ACCESS.deny; dp != NULL; dp = dp->next)
266  {
267  strlcpy(transpath, dp->path, CF_BUFSIZE);
268  MapName(transpath);
269 
270  if (PathMatch(transpath, transrequest))
271  {
272  if ((IsMatchItemIn(dp->accesslist, conn->ipaddr)) ||
273  (IsRegexItemIn(ctx, dp->accesslist, conn->hostname)))
274  {
275  access = false;
277  "Host '%s' in deny list, explicitly denying access to '%s' in '%s'",
278  conn->ipaddr, transrequest, transpath);
279  break;
280  }
281  }
282  }
283 
284  if (access)
285  {
286  Log(LOG_LEVEL_VERBOSE, "Host %s granted access to %s", conn->hostname, req_path);
287 
288  if (encrypt && LOGENCRYPT)
289  {
290  /* Log files that were marked as requiring encryption */
291  Log(LOG_LEVEL_INFO, "Host %s granted access to %s", conn->hostname, req_path);
292  }
293  }
294  else
295  {
296  Log(LOG_LEVEL_INFO, "Host %s denied access to %s", conn->hostname, req_path);
297  }
298 
299  return access;
300 }
301 
302 /* Checks the "varadmit" legacy ACL. */
303 static int LiteralAccessControl(EvalContext *ctx, char *in, ServerConnectionState *conn, int encrypt)
304 {
305  Auth *ap;
306  int access = false;
307  char name[CF_BUFSIZE];
308 
309  name[0] = '\0';
310 
311  if (strncmp(in, "VAR", 3) == 0)
312  {
313  sscanf(in, "VAR %255[^\n]", name);
314  }
315  else if (strncmp(in, "CALL_ME_BACK", strlen("CALL_ME_BACK")) == 0)
316  {
317  sscanf(in, "CALL_ME_BACK %255[^\n]", name);
318  }
319  else
320  {
321  sscanf(in, "QUERY %128s", name);
322  }
323 
324  conn->maproot = false;
325 
326  for (ap = SERVER_ACCESS.varadmit; ap != NULL; ap = ap->next)
327  {
328  Log(LOG_LEVEL_VERBOSE, "Examining rule in access list (%s,%s)?", name, ap->path);
329 
330  if (strcmp(ap->path, name) == 0) /* exact match */
331  {
332  Log(LOG_LEVEL_VERBOSE, "Found a matching rule in access list (%s in %s)", name, ap->path);
333 
334  if ((!ap->literal) && (!ap->variable))
335  {
337  "Variable/query '%s' requires a literal server item...cannot set variable directly by path",
338  ap->path);
339  access = false;
340  break;
341  }
342 
343  if (!encrypt && ap->encrypt)
344  {
345  Log(LOG_LEVEL_ERR, "Variable %s requires encrypt connection...will not serve", name);
346  access = false;
347  break;
348  }
349  else
350  {
351  Log(LOG_LEVEL_DEBUG, "Checking whether to map root privileges");
352 
353  if ((IsMatchItemIn(ap->maproot, conn->ipaddr)) ||
354  (IsRegexItemIn(ctx, ap->maproot, conn->hostname)))
355  {
356  conn->maproot = true;
357  Log(LOG_LEVEL_VERBOSE, "Mapping root privileges");
358  }
359  else
360  {
361  Log(LOG_LEVEL_VERBOSE, "No root privileges granted");
362  }
363 
364  if ((IsMatchItemIn(ap->accesslist, conn->ipaddr))
365  || (IsRegexItemIn(ctx, ap->accesslist, conn->hostname)))
366  {
367  access = true;
368  Log(LOG_LEVEL_DEBUG, "Access privileges - match found");
369  }
370  }
371  }
372  }
373 
374  for (ap = SERVER_ACCESS.vardeny; ap != NULL; ap = ap->next)
375  {
376  if (strcmp(ap->path, name) == 0)
377  {
378  if ((IsMatchItemIn(ap->accesslist, conn->ipaddr))
379  || (IsRegexItemIn(ctx, ap->accesslist, conn->hostname)))
380  {
381  access = false;
382  Log(LOG_LEVEL_VERBOSE, "Host %s explicitly denied access to %s", conn->hostname, name);
383  break;
384  }
385  }
386  }
387 
388  if (access)
389  {
390  Log(LOG_LEVEL_VERBOSE, "Host %s granted access to literal '%s'", conn->hostname, name);
391 
392  if (encrypt && LOGENCRYPT)
393  {
394  /* Log files that were marked as requiring encryption */
395  Log(LOG_LEVEL_INFO, "Host %s granted access to literal '%s'", conn->hostname, name);
396  }
397  }
398  else
399  {
400  Log(LOG_LEVEL_VERBOSE, "Host %s denied access to literal '%s'", conn->hostname, name);
401  }
402 
403  return access;
404 }
405 
406 /* Checks the "varadmit" legacy ACL. */
407 static Item *ContextAccessControl(EvalContext *ctx, char *in, ServerConnectionState *conn, int encrypt)
408 {
409  Auth *ap;
410  int access = false;
411  char client_regex[CF_BUFSIZE];
412  Item *ip, *matches = NULL;
413 
414  int ret = sscanf(in, "CONTEXT %255[^\n]", client_regex);
415  Item *persistent_classes = ListPersistentClasses();
416  if (ret != 1 || persistent_classes == NULL)
417  {
418  return NULL;
419  }
420 
421  for (ip = persistent_classes; ip != NULL; ip = ip->next)
422  {
423  /* Does the class match the regex that the agent requested? */
424  if (StringMatchFull(client_regex, ip->name))
425  {
426  for (ap = SERVER_ACCESS.varadmit; ap != NULL; ap = ap->next)
427  {
428  /* Does the class match any of the regex in ACLs? */
429  if (StringMatchFull(ap->path, ip->name))
430  {
432  "Found a matching rule in access list (%s in %s)",
433  ip->name, ap->path);
434 
435  if (!ap->classpattern)
436  {
438  "Context %s requires a literal server item... "
439  "cannot set variable directly by path",
440  ap->path);
441  access = false;
442  continue;
443  }
444 
445  if (!encrypt && ap->encrypt)
446  {
448  "Context %s requires encrypt connection... "
449  "will not serve",
450  ip->name);
451  access = false;
452  break;
453  }
454  else
455  {
457  "Checking whether to map root privileges");
458 
459  if ((IsMatchItemIn(ap->maproot, conn->ipaddr))
460  || (IsRegexItemIn(ctx, ap->maproot, conn->hostname)))
461  {
462  conn->maproot = true;
464  "Mapping root privileges");
465  }
466  else
467  {
469  "No root privileges granted");
470  }
471 
472  if ((IsMatchItemIn(ap->accesslist, conn->ipaddr))
473  || (IsRegexItemIn(ctx, ap->accesslist, conn->hostname)))
474  {
475  access = true;
477  "Access privileges - match found");
478  }
479  }
480  }
481  }
482 
483  for (ap = SERVER_ACCESS.vardeny; ap != NULL; ap = ap->next)
484  {
485  if (strcmp(ap->path, ip->name) == 0)
486  {
487  if ((IsMatchItemIn(ap->accesslist, conn->ipaddr))
488  || (IsRegexItemIn(ctx, ap->accesslist, conn->hostname)))
489  {
490  access = false;
492  "Host %s explicitly denied access to context %s",
493  conn->hostname, ip->name);
494  break;
495  }
496  }
497  }
498 
499  if (access)
500  {
502  "Host %s granted access to context '%s'",
503  conn->hostname, ip->name);
504  AppendItem(&matches, ip->name, NULL);
505 
506  if (encrypt && LOGENCRYPT)
507  {
508  /* Log files that were marked as requiring encryption */
510  "Host %s granted access to context '%s'",
511  conn->hostname, ip->name);
512  }
513  }
514  else
515  {
517  "Host %s denied access to context '%s'",
518  conn->hostname, ip->name);
519  }
520  }
521  }
522 
523  DeleteItemList(persistent_classes);
524  return matches;
525 }
526 
527 static int cfscanf(char *in, int len1, int len2, char *out1, char *out2, char *out3)
528 {
529  int len3 = 0;
530  char *sp;
531 
532  sp = in;
533  memcpy(out1, sp, len1);
534  out1[len1] = '\0';
535 
536  sp += len1 + 1;
537  memcpy(out2, sp, len2);
538 
539  sp += len2 + 1;
540  len3 = strlen(sp);
541  memcpy(out3, sp, len3);
542  out3[len3] = '\0';
543 
544  return (len1 + len2 + len3 + 2);
545 }
546 
547 static void SetConnectionData(ServerConnectionState *conn, char *buf)
548 {
549  char ipstring[CF_MAXVARSIZE], fqname[CF_MAXVARSIZE], username[CF_MAXVARSIZE];
550 
551  Log(LOG_LEVEL_DEBUG, "Connecting host identifies itself as '%s'", buf);
552 
553  memset(ipstring, 0, CF_MAXVARSIZE);
554  memset(fqname, 0, CF_MAXVARSIZE);
555  memset(username, 0, CF_MAXVARSIZE);
556 
557  sscanf(buf, "%255s %255s %255s", ipstring, fqname, username);
558 
559  /* The "ipstring" that the client sends is currently *ignored* as
560  * conn->ipaddr is always set from the connecting socket address. */
561 
562  Log(LOG_LEVEL_DEBUG, "(ipstring=[%s],fqname=[%s],username=[%s],socket=[%s])",
563  ipstring, fqname, username, conn->ipaddr);
564 
565  ToLowerStrInplace(fqname);
566 
567  strlcpy(conn->hostname, fqname, CF_MAXVARSIZE);
568 
569  SetConnIdentity(conn, username);
570 }
571 
572 static bool CheckStoreKey(ServerConnectionState *conn, RSA *key)
573 {
574  RSA *savedkey;
575 
576  const char *udigest = KeyPrintableHash(ConnectionInfoKey(conn->conn_info));
577  assert(udigest != NULL);
578 
579  if ((savedkey = HavePublicKey(conn->username, conn->ipaddr, udigest)))
580  {
582  "A public key was already known from %s/%s - no trust required",
583  conn->hostname, conn->ipaddr);
584 
585  const BIGNUM *key_n, *key_e, *savedkey_n, *savedkey_e;
586  RSA_get0_key(key, &key_n, &key_e, NULL);
587  RSA_get0_key(savedkey, &savedkey_n, &savedkey_e, NULL);
588 
589  if ((BN_cmp(savedkey_e, key_e) == 0) && (BN_cmp(savedkey_n, key_n) == 0))
590  {
592  "The public key identity was confirmed as %s@%s",
593  conn->username, conn->hostname);
594  SendTransaction(conn->conn_info, "OK: key accepted", 0, CF_DONE);
595  RSA_free(savedkey);
596  return true;
597  }
598  }
599 
600  /* Finally, if we're still here then the key is new (not in ppkeys
601  * directory): Allow access only if host is listed in "trustkeysfrom" body
602  * server control option. */
603 
604  if ((SERVER_ACCESS.trustkeylist != NULL) &&
606  {
608  "Host %s/%s was found in the list of hosts to trust",
609  conn->hostname, conn->ipaddr);
611  "OK: unknown key was accepted on trust", 0, CF_DONE);
612  SavePublicKey(conn->username, udigest, key);
613  return true;
614  }
615  else
616  {
618  "No previous key found, and unable to accept this one on trust");
620  "BAD: key could not be accepted on trust",
621  0, CF_DONE);
622  return false;
623  }
624 }
625 
626 static bool AuthenticationDialogue(ServerConnectionState *conn, char *recvbuffer, int recvlen)
627 {
628  unsigned char digest[EVP_MAX_MD_SIZE + 1] = { 0 };
629 
630  if (PRIVKEY == NULL || PUBKEY == NULL)
631  {
632  Log(LOG_LEVEL_ERR, "No public/private key pair is loaded,"
633  " please create one using cf-key");
634  return false;
635  }
636 
637  int PRIVKEY_size = RSA_size(PRIVKEY);
638  int digestLen;
639  HashMethod digestType;
640 
641  if (FIPS_MODE)
642  {
643  digestType = CF_DEFAULT_DIGEST;
644  digestLen = CF_DEFAULT_DIGEST_LEN;
645  }
646  else
647  {
648  digestType = HASH_METHOD_MD5;
649  digestLen = CF_MD5_LEN;
650  }
651 
652 /* parameters received in SAUTH command */
653 char iscrypt, enterprise_field;
654 
655 /* proposition C1 - SAUTH command */
656 {
657  char sauth[10] = { 0 };
658  unsigned int crypt_len; /* received encrypted challenge length */
659  unsigned int challenge_len; /* challenge length after decryption */
660 
661  int nparam = sscanf(recvbuffer, "%9s %c %u %u %c",
662  sauth, &iscrypt, &crypt_len,
663  &challenge_len, &enterprise_field);
664 
665  if (nparam >= 1 && strcmp(sauth, "SAUTH") != 0)
666  {
667  Log(LOG_LEVEL_ERR, "Authentication failure: "
668  "was expecting SAUTH command but got '%s'",
669  sauth);
670  return false;
671  }
672 
673  if (nparam != 5 && nparam != 4)
674  {
675  Log(LOG_LEVEL_ERR, "Authentication failure: "
676  "peer sent only %d arguments to SAUTH command",
677  nparam - 1);
678  return false;
679  }
680 
681  /* CFEngine 2 had no enterprise/community differentiation. */
682  if (nparam == 4)
683  {
685  "Peer sent only 4 parameters, "
686  "assuming it is a legacy community client");
687  enterprise_field = 'c';
688  }
689 
690  if ((challenge_len == 0) || (crypt_len == 0))
691  {
693  "Authentication failure: received unexpected challenge length "
694  "(%u that decrypts to %u bytes)",
695  challenge_len, crypt_len);
696  return false;
697  }
698 
699  if (crypt_len > CF_NONCELEN * 2)
700  {
701  Log(LOG_LEVEL_ERR, "Authentication failure: "
702  "received encrypted challenge is too long "
703  "(%d bytes)", crypt_len);
704  return false;
705  }
706 
707  if (challenge_len > CF_NONCELEN * 2)
708  {
709  Log(LOG_LEVEL_ERR, "Authentication failure: "
710  "received challenge is too long (%u bytes)",
711  challenge_len);
712  return false;
713  }
714 
716  "Challenge encryption = %c, challenge_len = %u, crypt_len = %u",
717  iscrypt, challenge_len, crypt_len);
718 
719  char *challenge;
720  char decrypted_challenge[PRIVKEY_size];
721 
722  if (iscrypt == 'y') /* challenge came encrypted */
723  {
724  if (recvlen < CF_RSA_PROTO_OFFSET + crypt_len)
725  {
726  Log(LOG_LEVEL_ERR, "Authentication failure: peer sent only %d "
727  "bytes as encrypted challenge but claims to have sent %u bytes",
728  recvlen - CF_RSA_PROTO_OFFSET, crypt_len);
729  }
730 
731  int ret = RSA_private_decrypt(crypt_len, recvbuffer + CF_RSA_PROTO_OFFSET,
732  decrypted_challenge, PRIVKEY, RSA_PKCS1_PADDING);
733  if (ret < 0)
734  {
735  Log(LOG_LEVEL_ERR, "Authentication failure: "
736  "private decrypt of received challenge failed (%s)",
739  "Probably the client has wrong public key for this server");
740  return false;
741  }
742  if (ret != challenge_len)
743  {
744  Log(LOG_LEVEL_ERR, "Authentication failure: "
745  "private decrypt of received challenge (%u bytes) "
746  "resulted in %d bytes instead of promised %u bytes",
747  crypt_len, ret, challenge_len);
748  return false;
749  }
750 
751  challenge = decrypted_challenge;
752  }
753  else /* challenge came unencrypted */
754  {
755  if (challenge_len != crypt_len)
756  {
758  "Authentication failure: peer sent illegal challenge "
759  "(challenge_len %u != crypt_len %u)",
760  challenge_len, crypt_len);
761  return false;
762  }
763 
764  if (recvlen < CF_RSA_PROTO_OFFSET + challenge_len)
765  {
767  "Authentication failure: peer sent only %d "
768  "bytes as challenge but claims to have sent %u bytes",
769  recvlen - CF_RSA_PROTO_OFFSET, challenge_len);
770  return false;
771  }
772 
773  challenge = &recvbuffer[CF_RSA_PROTO_OFFSET];
774  }
775 
776 /* Client's ID is now established by key or trusted, reply with digest */
777  HashString(challenge, challenge_len, digest, digestType);
778 }
779 
780 BIGNUM *newkey_n, *newkey_e;
781 
782 /* proposition C2 - Receive client's public key modulus */
783 {
784 
785  int len_n = ReceiveTransaction(conn->conn_info, recvbuffer, NULL);
786  if (len_n == -1)
787  {
788  Log(LOG_LEVEL_ERR, "Authentication failure: "
789  "error while receiving public key modulus");
790  return false;
791  }
792 
793  if ((newkey_n = BN_mpi2bn(recvbuffer, len_n, NULL)) == NULL)
794  {
795  Log(LOG_LEVEL_ERR, "Authentication failure: "
796  "private decrypt of received public key modulus failed "
797  "(%s)", CryptoLastErrorString());
798  return false;
799  }
800 }
801 
802 /* proposition C3 - Receive client's public key exponent. */
803 {
804  int len_e = ReceiveTransaction(conn->conn_info, recvbuffer, NULL);
805  if (len_e == -1)
806  {
807  Log(LOG_LEVEL_ERR, "Authentication failure: "
808  "error while receiving public key exponent");
809  return false;
810  }
811 
812  if ((newkey_e = BN_mpi2bn(recvbuffer, len_e, NULL)) == NULL)
813  {
814  Log(LOG_LEVEL_ERR, "Authentication failure: "
815  "private decrypt of received public key exponent failed "
816  "(%s)", CryptoLastErrorString());
817  BN_free(newkey_n);
818  return false;
819  }
820 }
821 
822 RSA *newkey = RSA_new();
823 if (newkey == NULL)
824 {
825  Log(LOG_LEVEL_ERR, "Failed to allocate RSA key: %s",
826  TLSErrorString(ERR_get_error()));
827  BN_free(newkey_n);
828  BN_free(newkey_e);
829  return false;
830 }
831 if (RSA_set0_key(newkey, newkey_n, newkey_e, NULL) != 1)
832 {
833  Log(LOG_LEVEL_ERR, "Failed to set RSA key: %s",
834  TLSErrorString(ERR_get_error()));
835  BN_free(newkey_n);
836  BN_free(newkey_e);
837  RSA_free(newkey);
838  return false;
839 }
840 
841 /* Compute and store hash of the client's public key. */
842 {
843  Key *key = KeyNew(newkey, CF_DEFAULT_DIGEST);
844  conn->conn_info->remote_key = key;
845 
846  Log(LOG_LEVEL_VERBOSE, "Peer's identity is: %s",
847  KeyPrintableHash(key));
848 
849  LastSaw1(conn->ipaddr, KeyPrintableHash(key),
851 
852  /* Do we want to trust the received key? */
853  if (!CheckStoreKey(conn, newkey)) /* conceals proposition S1 */
854  {
855  return false;
856  }
857 }
858 
859 /* proposition S2 - reply with digest of challenge. */
860 {
861  Log(LOG_LEVEL_DEBUG, "Sending challenge response");
862  SendTransaction(conn->conn_info, digest, digestLen, CF_DONE);
863 }
864 
865 /* proposition S3 - send counter-challenge */
866 {
867  BIGNUM *counter_challenge_BN = BN_new();
868  if (counter_challenge_BN == NULL)
869  {
870  Log(LOG_LEVEL_ERR, "Authentication failure: "
871  "cannot allocate BIGNUM structure for counter-challenge");
872  return false;
873  }
874 
875  BN_rand(counter_challenge_BN, CF_NONCELEN, 0, 0);
876 
877  char counter_challenge[CF_BUFSIZE];
878  int counter_challenge_len = BN_bn2mpi(counter_challenge_BN, counter_challenge);
879  BN_free(counter_challenge_BN);
880 
881  /* Compute counter-challenge digest. */
882  HashString(counter_challenge, counter_challenge_len, digest, digestType);
883 
884  /* Encryption buffer is always RSA_size(key) and buffer needs 11 bytes,
885  * see RSA_public_encrypt manual. */
886  int encrypted_len = RSA_size(newkey);
887  char encrypted_counter_challenge[encrypted_len];
888  assert(counter_challenge_len < encrypted_len - 11);
889 
890  int ret = RSA_public_encrypt(counter_challenge_len, counter_challenge,
891  encrypted_counter_challenge, newkey,
892  RSA_PKCS1_PADDING);
893  if (ret != encrypted_len)
894  {
895  if (ret == -1)
896  {
897  Log(LOG_LEVEL_ERR, "Authentication failure: "
898  "public encryption of counter-challenge failed "
899  "(%s)", CryptoLastErrorString());
900  }
901  else
902  {
903  Log(LOG_LEVEL_ERR, "Authentication failure: "
904  "public encryption of counter-challenge failed "
905  "(result length %d but should be %d)",
906  ret, encrypted_len);
907  }
908  return false;
909  }
910 
911  Log(LOG_LEVEL_DEBUG, "Sending counter-challenge");
912  SendTransaction(conn->conn_info, encrypted_counter_challenge,
913  encrypted_len, CF_DONE);
914 }
915 
916 /* proposition S4, S5 - If the client doesn't have our public key, send it. */
917 {
918  if (iscrypt != 'y')
919  {
920  Log(LOG_LEVEL_DEBUG, "Sending server's public key");
921 
922  char bignum_buf[CF_BUFSIZE] = { 0 };
923 
924  const BIGNUM *n, *e;
925  RSA_get0_key(PUBKEY, &n, &e, NULL);
926 
927  /* proposition S4 - conditional */
928  int len_n = BN_bn2mpi(n, bignum_buf);
929  SendTransaction(conn->conn_info, bignum_buf, len_n, CF_DONE);
930 
931  /* proposition S5 - conditional */
932  int len_e = BN_bn2mpi(e, bignum_buf);
933  SendTransaction(conn->conn_info, bignum_buf, len_e, CF_DONE);
934  }
935 }
936 
937 /* proposition C4 - Receive counter-challenge response. */
938 {
939  char recv_buf[CF_BUFSIZE] = { 0 };
940 
941  int recv_len = ReceiveTransaction(conn->conn_info, recv_buf, NULL);
942  if (recv_len < digestLen)
943  {
944  if (recv_len == -1)
945  {
946  Log(LOG_LEVEL_ERR, "Authentication failure: "
947  "error receiving counter-challenge response; "
948  "maybe the client does not trust our key?");
949  }
950  else /* 0 < recv_len < expected_len */
951  {
952  Log(LOG_LEVEL_ERR, "Authentication failure: "
953  "error receiving counter-challenge response, "
954  "only got %d out of %d bytes",
955  recv_len, digestLen);
956  }
957  return false;
958  }
959 
960  if (HashesMatch(digest, recv_buf, digestType))
961  {
963  "Authentication of client %s/%s achieved",
964  conn->hostname, conn->ipaddr);
965  }
966  else
967  {
968  Log(LOG_LEVEL_ERR, "Authentication failure: "
969  "counter-challenge response was incorrect");
970  return false;
971  }
972 }
973 
974 /* proposition C5 - Receive session key */
975 {
976  Log(LOG_LEVEL_DEBUG, "Receiving session key from client...");
977 
978  char session_key[CF_BUFSIZE] = { 0 };
979  int session_key_size = CfSessionKeySize(enterprise_field);
980  int keylen = ReceiveTransaction(conn->conn_info, session_key, NULL);
981 
983  "Received encrypted session key of %d bytes, "
984  "should decrypt to %d bytes",
985  keylen, session_key_size);
986 
987  if (keylen == -1)
988  {
989  Log(LOG_LEVEL_ERR, "Authentication failure: "
990  "error receiving session key");
991  return false;
992  }
993 
994  if (keylen > CF_BUFSIZE / 2)
995  {
996  Log(LOG_LEVEL_ERR, "Authentication failure: "
997  "session key received is too long (%d bytes)",
998  keylen);
999  return false;
1000  }
1001 
1002  conn->session_key = xmalloc(session_key_size);
1003  conn->encryption_type = enterprise_field;
1004 
1005  if (keylen == CF_BLOWFISHSIZE) /* Support the old non-ecnrypted for upgrade */
1006  {
1007  memcpy(conn->session_key, session_key, session_key_size);
1008  }
1009  else
1010  {
1011  char decrypted_session_key[PRIVKEY_size];
1012  int ret = RSA_private_decrypt(keylen, session_key,
1013  decrypted_session_key, PRIVKEY,
1014  RSA_PKCS1_PADDING);
1015  if (ret != session_key_size)
1016  {
1017  if (ret < 0)
1018  {
1019  Log(LOG_LEVEL_ERR, "Authentication failure: "
1020  "private decrypt of session key failed "
1021  "(%s)", CryptoLastErrorString());
1022  }
1023  else
1024  {
1025  Log(LOG_LEVEL_ERR, "Authentication failure: "
1026  "session key decrypts to invalid size, "
1027  "expected %d but got %d bytes",
1028  session_key_size, ret);
1029  }
1030  return false;
1031  }
1032 
1033  memcpy(conn->session_key, decrypted_session_key, session_key_size);
1034  }
1035 }
1036 
1037 return true;
1038 }
1039 
1040 
1041 
1043 {
1044  time_t tloc, trem = 0;
1045  char recvbuffer[CF_BUFSIZE + CF_BUFEXT], check[CF_BUFSIZE];
1046  char sendbuffer[CF_BUFSIZE] = { 0 };
1047  char filename[CF_BUFSIZE], buffer[CF_BUFSIZE], out[CF_BUFSIZE];
1048  long time_no_see = 0;
1049  unsigned int len = 0;
1050  int drift, plainlen, received, encrypted = 0;
1051  size_t zret;
1052  ServerFileGetState get_args;
1053  Item *classes;
1054 
1055  memset(recvbuffer, 0, CF_BUFSIZE + CF_BUFEXT);
1056  memset(&get_args, 0, sizeof(get_args));
1057 
1058  received = ReceiveTransaction(conn->conn_info, recvbuffer, NULL);
1059  if (received == -1)
1060  {
1061  return false;
1062  }
1063 
1064  if (strlen(recvbuffer) == 0)
1065  {
1066  Log(LOG_LEVEL_WARNING, "Got NULL transmission, skipping!");
1067  return true;
1068  }
1069 
1070  /* Don't process request if we're signalled to exit. */
1071  if (IsPendingTermination())
1072  {
1073  Log(LOG_LEVEL_VERBOSE, "Server must exit, closing connection");
1074  return false;
1075  }
1076 
1077  ProtocolCommandClassic command = GetCommandClassic(recvbuffer);
1078 
1079  switch (command)
1080  {
1081  /* Plain text authentication; this MUST be the first command client
1082  using classic protocol is sending. */
1084  SetConnectionData(conn, (char *) (recvbuffer + strlen("CAUTH ")));
1085 
1086  if (!IsUserNameValid(conn->username))
1087  {
1088  Log(LOG_LEVEL_INFO, "Client is sending wrong username: %s",
1089  conn->username);
1090  RefuseAccess(conn, recvbuffer);
1091  return false;
1092  }
1093 
1094  /* This is used only for forcing correct state of state machine while
1095  connecting and authenticating user using classic protocol. */
1096  conn->user_data_set = true;
1097 
1098  return true;
1099 
1100  /* This MUST be exactly second command client using classic protocol is
1101  sending. This is where key agreement takes place. */
1103  /* First command was omitted by client; this is protocol violation. */
1104  if (!conn->user_data_set)
1105  {
1107  "Client is not verified; rejecting connection");
1108  RefuseAccess(conn, recvbuffer);
1109  return false;
1110  }
1111 
1112  conn->rsa_auth = AuthenticationDialogue(conn, recvbuffer, received);
1113  if (!conn->rsa_auth)
1114  {
1115  Log(LOG_LEVEL_INFO, "Auth dialogue error");
1116  RefuseAccess(conn, recvbuffer);
1117  return false;
1118  }
1119 
1120  return true;
1121 
1122  default:
1123  break;
1124  }
1125 
1126  /* At this point we should have both user_data_set and rsa_auth set to
1127  perform any operation. We can check only for second one as without
1128  first it won't be set up. */
1129  if (!conn->rsa_auth)
1130  {
1132  "REFUSAL due to no RSA authentication (command: %d)",
1133  command);
1134  RefuseAccess(conn, recvbuffer);
1135  return false;
1136  }
1137 
1138  /* We have to have key at this point. */
1139  assert(conn->session_key);
1140 
1141  /* At this point we can safely do next switch and make sure user is
1142  * authenticated. */
1143  switch (command)
1144  {
1145  case PROTOCOL_COMMAND_EXEC:
1146  {
1147  const size_t EXEC_len = strlen(PROTOCOL_CLASSIC[PROTOCOL_COMMAND_EXEC]);
1148  /* Assert recvbuffer starts with EXEC. */
1149  assert(strncmp(PROTOCOL_CLASSIC[PROTOCOL_COMMAND_EXEC],
1150  recvbuffer, EXEC_len) == 0);
1151 
1152  char *args = &recvbuffer[EXEC_len];
1153  args += strspn(args, " \t"); /* bypass spaces */
1154 
1155  Log(LOG_LEVEL_VERBOSE, "%14s %7s %s",
1156  "Received:", "EXEC", args);
1157 
1158  bool b = DoExec2(ctx, conn, args,
1159  sendbuffer, sizeof(sendbuffer));
1160 
1161  /* In the end we might keep the connection open (return true) to be
1162  * ready for next requests, but we must always send the TERMINATOR
1163  * string so that the client can close the connection at will. */
1164  Terminate(conn->conn_info);
1165 
1166  return b;
1167  }
1169  snprintf(sendbuffer, sizeof(sendbuffer), "OK: %s", Version());
1170  SendTransaction(conn->conn_info, sendbuffer, 0, CF_DONE);
1171  return conn->user_data_set;
1172 
1173  case PROTOCOL_COMMAND_GET:
1174  memset(filename, 0, CF_BUFSIZE);
1175  sscanf(recvbuffer, "GET %d %[^\n]", &(get_args.buf_size), filename);
1176 
1177  if ((get_args.buf_size < 0) || (get_args.buf_size > CF_BUFSIZE))
1178  {
1179  Log(LOG_LEVEL_INFO, "GET buffer out of bounds");
1180  RefuseAccess(conn, recvbuffer);
1181  return false;
1182  }
1183 
1184  zret = ShortcutsExpand(filename, sizeof(filename),
1186  conn->ipaddr, conn->hostname,
1188 
1189  if (zret == (size_t) -1)
1190  {
1191  Log(LOG_LEVEL_VERBOSE, "Expanding filename (%s) made it too long (>= %zu)", filename, sizeof(filename));
1192  return false;
1193  }
1194 
1195  if (!AccessControl(ctx, filename, conn, false))
1196  {
1197  Log(LOG_LEVEL_INFO, "Access denied to get object");
1198  RefuseAccess(conn, recvbuffer);
1199  return true;
1200  }
1201 
1202  memset(sendbuffer, 0, sizeof(sendbuffer));
1203 
1204  if (get_args.buf_size >= CF_BUFSIZE)
1205  {
1206  get_args.buf_size = 2048;
1207  }
1208 
1209  get_args.conn = conn;
1210  get_args.encrypt = false;
1211  get_args.replybuff = sendbuffer;
1212  get_args.replyfile = filename;
1213 
1214  CfGetFile(&get_args);
1215 
1216  return true;
1217 
1219  memset(buffer, 0, CF_BUFSIZE);
1220  sscanf(recvbuffer, "SGET %u %d", &len, &(get_args.buf_size));
1221 
1222  if (received != len + CF_PROTO_OFFSET)
1223  {
1224  Log(LOG_LEVEL_INFO, "Protocol error SGET");
1225  RefuseAccess(conn, recvbuffer);
1226  return false;
1227  }
1228 
1229  plainlen = DecryptString(buffer, sizeof(buffer),
1230  recvbuffer + CF_PROTO_OFFSET, len,
1231  conn->encryption_type, conn->session_key);
1232 
1233  cfscanf(buffer, strlen("GET"), strlen("dummykey"), check, sendbuffer, filename);
1234 
1235  if (strcmp(check, "GET") != 0)
1236  {
1237  Log(LOG_LEVEL_INFO, "SGET/GET problem");
1238  RefuseAccess(conn, recvbuffer);
1239  return true;
1240  }
1241 
1242  if ((get_args.buf_size < 0) || (get_args.buf_size > 8192))
1243  {
1244  Log(LOG_LEVEL_INFO, "SGET bounding error");
1245  RefuseAccess(conn, recvbuffer);
1246  return false;
1247  }
1248 
1249  if (get_args.buf_size >= CF_BUFSIZE)
1250  {
1251  get_args.buf_size = 2048;
1252  }
1253 
1254  zret = ShortcutsExpand(filename, sizeof(filename),
1256  conn->ipaddr, conn->hostname,
1258 
1259  if (zret == (size_t) -1)
1260  {
1261  Log(LOG_LEVEL_VERBOSE, "Expanding filename (%s) made it too long (>= %zu)", filename, sizeof(filename));
1262  return false;
1263  }
1264 
1265  Log(LOG_LEVEL_DEBUG, "Confirm decryption, and thus validity of caller");
1266  Log(LOG_LEVEL_DEBUG, "SGET '%s' with blocksize %d", filename, get_args.buf_size);
1267 
1268  if (!AccessControl(ctx, filename, conn, true))
1269  {
1270  Log(LOG_LEVEL_INFO, "Access control error");
1271  RefuseAccess(conn, recvbuffer);
1272  return false;
1273  }
1274 
1275  memset(sendbuffer, 0, sizeof(sendbuffer));
1276 
1277  get_args.conn = conn;
1278  get_args.encrypt = true;
1279  get_args.replybuff = sendbuffer;
1280  get_args.replyfile = filename;
1281 
1282  CfEncryptGetFile(&get_args);
1283  return true;
1284 
1286  memset(buffer, 0, CF_BUFSIZE);
1287  sscanf(recvbuffer, "SOPENDIR %u", &len);
1288 
1289  if ((len >= sizeof(out)) || (received != (len + CF_PROTO_OFFSET)))
1290  {
1291  Log(LOG_LEVEL_INFO, "Protocol error OPENDIR: %d", len);
1292  RefuseAccess(conn, recvbuffer);
1293  return false;
1294  }
1295 
1296  memcpy(out, recvbuffer + CF_PROTO_OFFSET, len);
1297 
1298  plainlen = DecryptString(recvbuffer, sizeof(recvbuffer),
1299  out, len,
1300  conn->encryption_type, conn->session_key);
1301 
1302  if (strncmp(recvbuffer, "OPENDIR", 7) != 0)
1303  {
1304  Log(LOG_LEVEL_INFO, "Opendir failed to decrypt");
1305  RefuseAccess(conn, recvbuffer);
1306  return true;
1307  }
1308 
1309  memset(filename, 0, CF_BUFSIZE);
1310  sscanf(recvbuffer, "OPENDIR %[^\n]", filename);
1311 
1312  zret = ShortcutsExpand(filename, sizeof(filename),
1314  conn->ipaddr, conn->hostname,
1316 
1317  if (zret == (size_t) -1)
1318  {
1319  Log(LOG_LEVEL_VERBOSE, "Expanding filename (%s) made it too long (>= %zu)", filename, sizeof(filename));
1320  return false;
1321  }
1322 
1323  if (!AccessControl(ctx, filename, conn, true)) /* opendir don't care about privacy */
1324  {
1325  Log(LOG_LEVEL_INFO, "Access error");
1326  RefuseAccess(conn, recvbuffer);
1327  return false;
1328  }
1329 
1330  CfSecOpenDirectory(conn, sendbuffer, filename);
1331  return true;
1332 
1334  memset(filename, 0, CF_BUFSIZE);
1335  sscanf(recvbuffer, "OPENDIR %[^\n]", filename);
1336 
1337  zret = ShortcutsExpand(filename, sizeof(filename),
1339  conn->ipaddr, conn->hostname,
1341 
1342  if (zret == (size_t) -1)
1343  {
1344  Log(LOG_LEVEL_VERBOSE, "Expanding filename (%s) made it too long (>= %zu)", filename, sizeof(filename));
1345  return false;
1346  }
1347 
1348  if (!AccessControl(ctx, filename, conn, false)) /* opendir don't care about privacy */
1349  {
1350  Log(LOG_LEVEL_INFO, "DIR access error");
1351  RefuseAccess(conn, recvbuffer);
1352  return false;
1353  }
1354 
1355  CfOpenDirectory(conn, sendbuffer, filename);
1356  return true;
1357 
1359  memset(buffer, 0, CF_BUFSIZE);
1360  sscanf(recvbuffer, "SSYNCH %u", &len);
1361 
1362  if ((len >= sizeof(out)) || (received != (len + CF_PROTO_OFFSET)))
1363  {
1364  Log(LOG_LEVEL_INFO, "Protocol error SSYNCH: %d", len);
1365  RefuseAccess(conn, recvbuffer);
1366  return false;
1367  }
1368 
1369  memcpy(out, recvbuffer + CF_PROTO_OFFSET, len);
1370 
1371  plainlen = DecryptString(recvbuffer, sizeof(recvbuffer),
1372  out, len,
1373  conn->encryption_type, conn->session_key);
1374 
1375  if (plainlen < 0)
1376  {
1377  DebugBinOut((char *) conn->session_key, 32, "Session key");
1378  Log(LOG_LEVEL_ERR, "Bad decrypt (%d)", len);
1379  }
1380 
1381  if (strncmp(recvbuffer, "SYNCH", 5) != 0)
1382  {
1383  Log(LOG_LEVEL_INFO, "No synch");
1384  RefuseAccess(conn, recvbuffer);
1385  return true;
1386  }
1387 
1388  /* roll through, no break */
1389 
1390  case PROTOCOL_COMMAND_SYNC:
1391  memset(filename, 0, CF_BUFSIZE);
1392  sscanf(recvbuffer, "SYNCH %ld STAT %[^\n]", &time_no_see, filename);
1393 
1394  trem = (time_t) time_no_see;
1395 
1396  if (filename[0] == '\0')
1397  {
1398  break;
1399  }
1400 
1401  if ((tloc = time((time_t *) NULL)) == -1)
1402  {
1403  Log(LOG_LEVEL_INFO, "Couldn't read system clock. (time: %s)", GetErrorStr());
1404  SendTransaction(conn->conn_info, "BAD: clocks out of synch", 0, CF_DONE);
1405  return true;
1406  }
1407 
1408  drift = (int) (tloc - trem);
1409 
1410  zret = ShortcutsExpand(filename, sizeof(filename),
1412  conn->ipaddr, conn->hostname,
1414 
1415  if (zret == (size_t) -1)
1416  {
1417  Log(LOG_LEVEL_VERBOSE, "Expanding filename (%s) made it too long (>= %zu)", filename, sizeof(filename));
1418  return false;
1419  }
1420 
1421  if (!AccessControl(ctx, filename, conn, true))
1422  {
1423  Log(LOG_LEVEL_INFO, "Access control in sync");
1424  RefuseAccess(conn, recvbuffer);
1425  return true;
1426  }
1427 
1428  if (DENYBADCLOCKS && (drift * drift > CLOCK_DRIFT * CLOCK_DRIFT))
1429  {
1430  snprintf(sendbuffer, sizeof(sendbuffer),
1431  "BAD: Clocks are too far unsynchronized %ld/%ld",
1432  (long) tloc, (long) trem);
1433  SendTransaction(conn->conn_info, sendbuffer, 0, CF_DONE);
1434  return true;
1435  }
1436  else
1437  {
1438  Log(LOG_LEVEL_DEBUG, "Clocks were off by %ld", (long) tloc - (long) trem);
1439  StatFile(conn, sendbuffer, filename);
1440  }
1441 
1442  return true;
1443 
1445  sscanf(recvbuffer, "SMD5 %u", &len);
1446 
1447  if ((len >= sizeof(out)) || (received != (len + CF_PROTO_OFFSET)))
1448  {
1449  Log(LOG_LEVEL_INFO, "Decryption error");
1450  RefuseAccess(conn, recvbuffer);
1451  return true;
1452  }
1453 
1454  memcpy(out, recvbuffer + CF_PROTO_OFFSET, len);
1455  plainlen = DecryptString(recvbuffer, sizeof(recvbuffer),
1456  out, len,
1457  conn->encryption_type, conn->session_key);
1458 
1459  if (strncmp(recvbuffer, "MD5", 3) != 0)
1460  {
1461  Log(LOG_LEVEL_INFO, "MD5 protocol error");
1462  RefuseAccess(conn, recvbuffer);
1463  return false;
1464  }
1465 
1466  encrypted = true;
1467  /* roll through, no break */
1468 
1469  case PROTOCOL_COMMAND_MD5:
1470 
1471  memset(filename, 0, sizeof(filename));
1472  sscanf(recvbuffer, "MD5 %[^\n]", filename);
1473 
1474  zret = ShortcutsExpand(filename, sizeof(filename),
1476  conn->ipaddr, conn->hostname,
1478 
1479  if (zret == (size_t) -1)
1480  {
1481  Log(LOG_LEVEL_VERBOSE, "Expanding filename (%s) made it too long (>= %zu)", filename, sizeof(filename));
1482  return false;
1483  }
1484 
1485  if (!AccessControl(ctx, filename, conn, encrypted))
1486  {
1487  Log(LOG_LEVEL_INFO, "Access denied to get object");
1488  RefuseAccess(conn, recvbuffer);
1489  return true;
1490  }
1491 
1492  assert(CF_DEFAULT_DIGEST_LEN <= EVP_MAX_MD_SIZE);
1493  unsigned char digest[EVP_MAX_MD_SIZE + 1];
1494 
1496  <= sizeof(recvbuffer));
1497  memcpy(digest, recvbuffer + strlen(recvbuffer) + CF_SMALL_OFFSET,
1499 
1500  CompareLocalHash(filename, digest, sendbuffer);
1501  SendTransaction(conn->conn_info, sendbuffer, 0, CF_DONE);
1502 
1503  return true;
1504 
1506  sscanf(recvbuffer, "SVAR %u", &len);
1507 
1508  if ((len >= sizeof(out)) || (received != (len + CF_PROTO_OFFSET)))
1509  {
1510  Log(LOG_LEVEL_INFO, "Decrypt error SVAR");
1511  RefuseAccess(conn, "decrypt error SVAR");
1512  return true;
1513  }
1514 
1515  memcpy(out, recvbuffer + CF_PROTO_OFFSET, len);
1516  plainlen = DecryptString(recvbuffer, sizeof(recvbuffer),
1517  out, len,
1518  conn->encryption_type, conn->session_key);
1519  encrypted = true;
1520 
1521  if (strncmp(recvbuffer, "VAR", 3) != 0)
1522  {
1523  Log(LOG_LEVEL_INFO, "VAR protocol defect");
1524  RefuseAccess(conn, "decryption failure");
1525  return false;
1526  }
1527 
1528  /* roll through, no break */
1529 
1530  case PROTOCOL_COMMAND_VAR:
1531  if (!LiteralAccessControl(ctx, recvbuffer, conn, encrypted))
1532  {
1533  Log(LOG_LEVEL_INFO, "Literal access failure");
1534  RefuseAccess(conn, recvbuffer);
1535  return false;
1536  }
1537 
1538  GetServerLiteral(ctx, conn, sendbuffer, recvbuffer, encrypted);
1539  return true;
1540 
1542  sscanf(recvbuffer, "SCONTEXT %u", &len);
1543 
1544  if ((len >= sizeof(out)) || (received != (len + CF_PROTO_OFFSET)))
1545  {
1546  Log(LOG_LEVEL_INFO, "Decrypt error SCONTEXT, len,received = %d,%d", len, received);
1547  RefuseAccess(conn, "decrypt error SCONTEXT");
1548  return true;
1549  }
1550 
1551  memcpy(out, recvbuffer + CF_PROTO_OFFSET, len);
1552  plainlen = DecryptString(recvbuffer, sizeof(recvbuffer),
1553  out, len,
1554  conn->encryption_type, conn->session_key);
1555  encrypted = true;
1556 
1557  if (strncmp(recvbuffer, "CONTEXT", 7) != 0)
1558  {
1559  Log(LOG_LEVEL_INFO, "CONTEXT protocol defect...");
1560  RefuseAccess(conn, "Decryption failed?");
1561  return false;
1562  }
1563 
1564  /* roll through, no break */
1565 
1567  if ((classes = ContextAccessControl(ctx, recvbuffer, conn, encrypted)) == NULL)
1568  {
1569  Log(LOG_LEVEL_INFO, "Context access failure on %s", recvbuffer);
1570  RefuseAccess(conn, recvbuffer);
1571  return false;
1572  }
1573 
1574  ReplyServerContext(conn, encrypted, classes);
1575  return true;
1576 
1578  sscanf(recvbuffer, "SQUERY %u", &len);
1579 
1580  if ((len >= sizeof(out)) || (received != (len + CF_PROTO_OFFSET)))
1581  {
1582  Log(LOG_LEVEL_INFO, "Decrypt error SQUERY");
1583  RefuseAccess(conn, "decrypt error SQUERY");
1584  return true;
1585  }
1586 
1587  memcpy(out, recvbuffer + CF_PROTO_OFFSET, len);
1588  plainlen = DecryptString(recvbuffer, sizeof(recvbuffer),
1589  out, len,
1590  conn->encryption_type, conn->session_key);
1591 
1592  if (strncmp(recvbuffer, "QUERY", 5) != 0)
1593  {
1594  Log(LOG_LEVEL_INFO, "QUERY protocol defect");
1595  RefuseAccess(conn, "decryption failure");
1596  return false;
1597  }
1598 
1599  if (!LiteralAccessControl(ctx, recvbuffer, conn, true))
1600  {
1601  Log(LOG_LEVEL_INFO, "Query access failure");
1602  RefuseAccess(conn, recvbuffer);
1603  return false;
1604  }
1605 
1606  if (GetServerQuery(conn, recvbuffer, true)) /* always encrypt */
1607  {
1608  return true;
1609  }
1610 
1611  break;
1612 
1614  sscanf(recvbuffer, "SCALLBACK %u", &len);
1615 
1616  if ((len >= sizeof(out)) || (received != (len + CF_PROTO_OFFSET)))
1617  {
1618  Log(LOG_LEVEL_INFO, "Decrypt error CALL_ME_BACK");
1619  return true;
1620  }
1621 
1622  memcpy(out, recvbuffer + CF_PROTO_OFFSET, len);
1623  plainlen = DecryptString(recvbuffer, sizeof(recvbuffer),
1624  out, len,
1625  conn->encryption_type, conn->session_key);
1626 
1627  if (strncmp(recvbuffer, "CALL_ME_BACK collect_calls", strlen("CALL_ME_BACK collect_calls")) != 0)
1628  {
1629  Log(LOG_LEVEL_INFO, "CALL_ME_BACK protocol defect");
1630  return false;
1631  }
1632 
1633  if (!LiteralAccessControl(ctx, recvbuffer, conn, true))
1634  {
1635  Log(LOG_LEVEL_INFO, "Query access failure");
1636  return false;
1637  }
1638 
1639  ReceiveCollectCall(conn);
1640  /* On success that returned true; otherwise, it did all
1641  * relevant Log()ging. Either way, we're no longer busy with
1642  * it and our caller can close the connection: */
1643  return false;
1644 
1647  case PROTOCOL_COMMAND_AUTH:
1649  case PROTOCOL_COMMAND_BAD:
1650  Log(LOG_LEVEL_WARNING, "Unexpected protocol command");
1651  }
1652 
1653  strcpy(sendbuffer, "BAD: Request denied");
1654  SendTransaction(conn->conn_info, sendbuffer, 0, CF_DONE);
1655  Log(LOG_LEVEL_INFO, "Closing connection due to request: %s", recvbuffer);
1656  return false;
1657 }
void * xmalloc(size_t size)
Definition: alloc-mini.c:46
bool ReceiveCollectCall(ServerConnectionState *conn)
#define CF_NONCELEN
Definition: cf3.defs.h:55
#define CF_SMALL_OFFSET
Definition: cf3.defs.h:107
HashMethod CF_DEFAULT_DIGEST
Definition: cf3globals.c:88
bool FIPS_MODE
Definition: cf3globals.c:36
int CF_DEFAULT_DIGEST_LEN
Definition: cf3globals.c:89
#define CF_RSA_PROTO_OFFSET
Definition: cfnet.h:49
#define CF_DONE
Definition: cfnet.h:45
#define CF_PROTO_OFFSET
Definition: cfnet.h:50
const Key * ConnectionInfoKey(const ConnectionInfo *info)
RSA key.
RSA * HavePublicKey(const char *username, const char *ipaddress, const char *digest)
Search for a key:
Definition: crypto.c:344
void DebugBinOut(char *buffer, int len, char *comment)
Definition: crypto.c:726
const char * CryptoLastErrorString()
Definition: crypto.c:65
bool SavePublicKey(const char *user, const char *digest, const RSA *key)
Definition: crypto.c:429
int DecryptString(char *out, size_t out_size, const char *in, int cipherlen, char type, unsigned char *key)
Definition: crypto.c:675
#define CF_BUFSIZE
Definition: definitions.h:50
#define CF_MAXVARSIZE
Definition: definitions.h:36
#define CF_BLOWFISHSIZE
Definition: definitions.h:34
void TranslatePath(char *new, const char *old)
int CfSessionKeySize(char type)
char * MapName(char *s)
Definition: file_lib.c:441
#define FILE_SEPARATOR_STR
Definition: file_lib.h:103
#define FILE_SEPARATOR
Definition: file_lib.h:102
bool CompressPath(char *dest, size_t dest_size, const char *src)
Definition: files_names.c:556
const char * Version(void)
#define NULL
Definition: getopt1.c:56
bool HashesMatch(const unsigned char digest1[EVP_MAX_MD_SIZE+1], const unsigned char digest2[EVP_MAX_MD_SIZE+1], HashMethod type)
Definition: hash.c:594
void HashString(const char *const buffer, const int len, unsigned char digest[EVP_MAX_MD_SIZE+1], HashMethod type)
Definition: hash.c:478
HashMethod
Definition: hash_method.h:36
@ HASH_METHOD_MD5
Definition: hash_method.h:37
@ CF_MD5_LEN
Definition: hash_method.h:50
void AppendItem(Item **liststart, const char *itemstring, const char *classes)
Definition: item_lib.c:415
void DeleteItemList(Item *item)
Definition: item_lib.c:808
bool IsMatchItemIn(const Item *list, const char *item)
Definition: item_lib.c:780
const char * KeyPrintableHash(const Key *key)
Printable hash of the key.
Definition: key.c:84
Key * KeyNew(RSA *rsa, HashMethod method)
Creates a new Key structure.
Definition: key.c:37
void LastSaw1(const char *ipaddress, const char *hashstr, LastSeenRole role)
Same as LastSaw() but the digest parameter is the hash as a "SHA=..." string, to avoid converting twi...
Definition: lastseen.c:83
@ LAST_SEEN_ROLE_ACCEPT
Definition: lastseen.h:39
void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
const char * GetErrorStr(void)
Definition: logging.c:275
void Log(LogLevel level, const char *fmt,...)
Definition: logging.c:409
@ LOG_LEVEL_ERR
Definition: logging.h:42
@ LOG_LEVEL_DEBUG
Definition: logging.h:47
@ LOG_LEVEL_WARNING
Definition: logging.h:43
@ LOG_LEVEL_VERBOSE
Definition: logging.h:46
@ LOG_LEVEL_INFO
Definition: logging.h:45
bool IsRegexItemIn(const EvalContext *ctx, const Item *list, const char *regex)
Definition: matching.c:235
int ReceiveTransaction(ConnectionInfo *conn_info, char *buffer, int *more)
Definition: net.c:149
int SendTransaction(ConnectionInfo *conn_info, const char *buffer, int len, char status)
Definition: net.c:61
int lstat(const char *file_name, struct stat *buf)
#define S_ISLNK(m)
Definition: platform.h:919
bool StringMatchFull(const char *regex, const char *str)
Definition: regex.c:106
bool DENYBADCLOCKS
Definition: server.c:72
ServerAccess SERVER_ACCESS
Definition: server.c:79
bool LOGENCRYPT
Definition: server.c:74
#define CLOCK_DRIFT
Definition: server.h:147
static int cfscanf(char *in, int len1, int len2, char *out1, char *out2, char *out3)
static const char * PROTOCOL_CLASSIC[]
static bool PathMatch(const char *stem, const char *request)
static int LiteralAccessControl(EvalContext *ctx, char *in, ServerConnectionState *conn, int encrypt)
static void SetConnectionData(ServerConnectionState *conn, char *buf)
bool BusyWithClassicConnection(EvalContext *ctx, ServerConnectionState *conn)
static bool AccessControl(EvalContext *ctx, const char *req_path, ServerConnectionState *conn, int encrypt)
static bool AuthenticationDialogue(ServerConnectionState *conn, char *recvbuffer, int recvlen)
static ProtocolCommandClassic GetCommandClassic(char *str)
static bool CheckStoreKey(ServerConnectionState *conn, RSA *key)
static Item * ContextAccessControl(EvalContext *ctx, char *in, ServerConnectionState *conn, int encrypt)
static bool ResolveFilename(const char *req_path, char *res_path)
ProtocolCommandClassic
@ PROTOCOL_COMMAND_MD5_SECURE
@ PROTOCOL_COMMAND_CONTEXT
@ PROTOCOL_COMMAND_CONTEXT_SECURE
@ PROTOCOL_COMMAND_QUERY_SECURE
@ PROTOCOL_COMMAND_OPENDIR
@ PROTOCOL_COMMAND_EXEC
@ PROTOCOL_COMMAND_MD5
@ PROTOCOL_COMMAND_AUTH
@ PROTOCOL_COMMAND_AUTH_SECURE
@ PROTOCOL_COMMAND_SYNC_SECURE
@ PROTOCOL_COMMAND_VERSION
@ PROTOCOL_COMMAND_GET
@ PROTOCOL_COMMAND_SYNC
@ PROTOCOL_COMMAND_OPENDIR_SECURE
@ PROTOCOL_COMMAND_VAR
@ PROTOCOL_COMMAND_CONTEXTS
@ PROTOCOL_COMMAND_CALL_ME_BACK
@ PROTOCOL_COMMAND_AUTH_PLAIN
@ PROTOCOL_COMMAND_BAD
@ PROTOCOL_COMMAND_GET_SECURE
@ PROTOCOL_COMMAND_VAR_SECURE
Item * ListPersistentClasses()
Definition: server_common.c:96
int StatFile(ServerConnectionState *conn, char *sendbuffer, char *ofilename)
bool CompareLocalHash(const char *filename, const char digest[EVP_MAX_MD_SIZE+1], char sendbuffer[sizeof("CFD_FALSE")])
void CfGetFile(ServerFileGetState *args)
void SetConnIdentity(ServerConnectionState *conn, const char *username)
bool DoExec2(const EvalContext *ctx, ServerConnectionState *conn, char *exec_args, char *sendbuf, size_t sendbuf_size)
size_t ShortcutsExpand(char *path, size_t path_size, const StringMap *shortcuts, const char *ipaddr, const char *hostname, const char *key)
void Terminate(ConnectionInfo *connection)
void CfEncryptGetFile(ServerFileGetState *args)
int CfSecOpenDirectory(ServerConnectionState *conn, char *sendbuffer, char *dirname)
void ReplyServerContext(ServerConnectionState *conn, int encrypted, Item *classes)
bool IsUserNameValid(const char *username)
Definition: server_common.c:71
bool GetServerQuery(ServerConnectionState *conn, char *recvbuffer, int encrypt)
void GetServerLiteral(EvalContext *ctx, ServerConnectionState *conn, char *sendbuffer, char *recvbuffer, int encrypted)
int CfOpenDirectory(ServerConnectionState *conn, char *sendbuffer, char *oldDirname)
void RefuseAccess(ServerConnectionState *conn, char *errmesg)
Definition: server_common.c:61
#define CF_BUFEXT
Definition: server_common.h:30
bool IsPendingTermination(void)
Definition: signals.c:35
char ToLower(char ch)
Definition: string_lib.c:119
void ToLowerStrInplace(char *str)
Definition: string_lib.c:162
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:34
Definition: server.h:44
Auth * next
Definition: server.h:54
Item * accesslist
Definition: server.h:50
int variable
Definition: server.h:48
int literal
Definition: server.h:46
int classpattern
Definition: server.h:47
Item * maproot
Definition: server.h:51
int encrypt
Definition: server.h:52
char * path
Definition: server.h:45
Definition: item_lib.h:33
Item * next
Definition: item_lib.h:38
char * name
Definition: item_lib.h:34
Definition: key.c:32
Item * trustkeylist
Definition: server.h:66
Auth * deny
Definition: server.h:74
Auth * varadmit
Definition: server.h:78
StringMap * path_shortcuts
Definition: server.h:87
Auth * vardeny
Definition: server.h:80
Auth * admit
Definition: server.h:72
char username[1024]
Definition: server.h:107
char hostname[1024]
Definition: server.h:113
unsigned char * session_key
Definition: server.h:119
ConnectionInfo * conn_info
Definition: server.h:94
ServerConnectionState * conn
Definition: server.h:129
char * replyfile
Definition: server.h:133
char * replybuff
Definition: server.h:132
RSA * PRIVKEY
Definition: cf3globals.c:72
RSA * PUBKEY
Definition: tls_client.c:44
const char * TLSErrorString(intmax_t errcode)
Definition: tls_generic.c:87