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)  

file_lib.c
Go to the documentation of this file.
1 /*
2  Copyright 2020 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 #include <platform.h>
26 #include <file_lib.h>
27 #include <misc_lib.h>
28 #include <dir.h>
29 #include <logging.h>
30 
31 #include <alloc.h>
32 #include <definitions.h> /* CF_PERMS_DEFAULT */
33 #include <libgen.h>
34 #include <logging.h>
35 #include <string_lib.h> /* memcchr */
36 #include <path.h>
37 
38 #ifndef __MINGW32__
39 #include <glob.h>
40 #else
41 #include <windows.h> /* LockFileEx and friends */
42 #endif
43 
44 #define SYMLINK_MAX_DEPTH 32
45 
46 bool FileCanOpen(const char *path, const char *modes)
47 {
48  FILE *test = NULL;
49 
50  if ((test = fopen(path, modes)) != NULL)
51  {
52  fclose(test);
53  return true;
54  }
55  else
56  {
57  return false;
58  }
59 }
60 
61 #define READ_BUFSIZE 4096
62 
63 Writer *FileRead(const char *filename, size_t max_size, bool *truncated)
64 {
65  int fd = safe_open(filename, O_RDONLY);
66  if (fd == -1)
67  {
68  return NULL;
69  }
70 
71  Writer *w = FileReadFromFd(fd, max_size, truncated);
72  close(fd);
73  return w;
74 }
75 
76 ssize_t ReadFileStreamToBuffer(FILE *file, size_t max_bytes, char *buf)
77 {
78  size_t bytes_read = 0;
79  size_t n = 0;
80  while (bytes_read < max_bytes)
81  {
82  n = fread(buf + bytes_read, 1, max_bytes - bytes_read, file);
83  if (ferror(file) && !feof(file))
84  {
85  return FILE_ERROR_READ;
86  }
87  else if (n == 0)
88  {
89  break;
90  }
91  bytes_read += n;
92  }
93  if (ferror(file))
94  {
95  return FILE_ERROR_READ;
96  }
97  return bytes_read;
98 }
99 
100 bool File_Copy(const char *src, const char *dst)
101 {
102  assert(src != NULL);
103  assert(dst != NULL);
104 
105  Log(LOG_LEVEL_INFO, "Copying: '%s' -> '%s'", src, dst);
106 
107  FILE *in = safe_fopen(src, "r");
108  if (in == NULL)
109  {
110  Log(LOG_LEVEL_ERR, "Could not open '%s' (%s)", src, strerror(errno));
111  return false;
112  }
113 
114  FILE *out = safe_fopen_create_perms(dst, "w", CF_PERMS_DEFAULT);
115  if (out == NULL)
116  {
117  Log(LOG_LEVEL_ERR, "Could not open '%s' (%s)", dst, strerror(errno));
118  fclose(in);
119  return false;
120  }
121 
122  size_t bytes_in = 0;
123  size_t bytes_out = 0;
124  bool ret = true;
125  do
126  {
127 #define BUFSIZE 1024
128  char buf[BUFSIZE] = {0};
129 
130  bytes_in = fread(buf, sizeof(char), sizeof(buf), in);
131  bytes_out = fwrite(buf, sizeof(char), bytes_in, out);
132  while (bytes_out < bytes_in && !ferror(out))
133  {
134  bytes_out += fwrite(
135  buf + bytes_out, sizeof(char), bytes_in - bytes_out, out);
136  }
137  } while (!feof(in) && !ferror(in) && !ferror(out) &&
138  bytes_in == bytes_out);
139 
140  if (ferror(in))
141  {
142  Log(LOG_LEVEL_ERR, "Error encountered while reading '%s'", src);
143  ret = false;
144  }
145  else if (ferror(out))
146  {
147  Log(LOG_LEVEL_ERR, "Error encountered while writing '%s'", dst);
148  ret = false;
149  }
150  else if (bytes_in != bytes_out)
151  {
152  Log(LOG_LEVEL_ERR, "Did not copy the whole file");
153  ret = false;
154  }
155 
156  const int i = fclose(in);
157  if (i != 0)
158  {
160  "Error encountered while closing '%s' (%s)",
161  src,
162  strerror(errno));
163  ret = false;
164  }
165  const int o = fclose(out);
166  if (o != 0)
167  {
169  "Error encountered while closing '%s' (%s)",
170  dst,
171  strerror(errno));
172  ret = false;
173  }
174  return ret;
175 }
176 
177 bool File_CopyToDir(const char *src, const char *dst_dir)
178 {
179  assert(src != NULL);
180  assert(dst_dir != NULL);
181  assert(StringEndsWith(dst_dir, FILE_SEPARATOR_STR));
182 
183  const char *filename = Path_Basename(src);
184  if (filename == NULL)
185  {
186  Log(LOG_LEVEL_ERR, "Cannot find filename in '%s'", src);
187  return false;
188  }
189 
190  char dst[PATH_MAX] = {0};
191  const int s = snprintf(dst, PATH_MAX, "%s%s", dst_dir, filename);
192  if (s >= PATH_MAX)
193  {
194  Log(LOG_LEVEL_ERR, "Copy destination path too long: '%s...'", dst);
195  return false;
196  }
197 
198  if (!File_Copy(src, dst))
199  {
200  Log(LOG_LEVEL_ERR, "Copying '%s' failed", filename);
201  return false;
202  }
203 
204  return true;
205 }
206 
207 Writer *FileReadFromFd(int fd, size_t max_size, bool *truncated)
208 {
209  if (truncated)
210  {
211  *truncated = false;
212  }
213 
214  Writer *w = StringWriter();
215  for (;;)
216  {
217  char buf[READ_BUFSIZE];
218  /* Reading more data than needed is deliberate. It is a truncation detection. */
219  ssize_t read_ = read(fd, buf, READ_BUFSIZE);
220 
221  if (read_ == 0)
222  {
223  /* Done. */
224  return w;
225  }
226  else if (read_ < 0)
227  {
228  if (errno != EINTR)
229  {
230  /* Something went wrong. */
231  WriterClose(w);
232  return NULL;
233  }
234  /* Else: interrupted - try again. */
235  }
236  else if (read_ + StringWriterLength(w) > max_size)
237  {
238  WriterWriteLen(w, buf, max_size - StringWriterLength(w));
239  /* Reached limit - stop. */
240  if (truncated)
241  {
242  *truncated = true;
243  }
244  return w;
245  }
246  else /* Filled buffer; copy and ask for more. */
247  {
248  WriterWriteLen(w, buf, read_);
249  }
250  }
251 }
252 
253 ssize_t FullWrite(int desc, const char *ptr, size_t len)
254 {
255  ssize_t total_written = 0;
256 
257  while (len > 0)
258  {
259  int written = write(desc, ptr, len);
260 
261  if (written < 0)
262  {
263  if (errno == EINTR)
264  {
265  continue;
266  }
267 
268  return written;
269  }
270 
271  total_written += written;
272  ptr += written;
273  len -= written;
274  }
275 
276  return total_written;
277 }
278 
279 ssize_t FullRead(int fd, char *ptr, size_t len)
280 {
281  ssize_t total_read = 0;
282 
283  while (len > 0)
284  {
285  ssize_t bytes_read = read(fd, ptr, len);
286 
287  if (bytes_read < 0)
288  {
289  if (errno == EINTR)
290  {
291  continue;
292  }
293 
294  return -1;
295  }
296 
297  if (bytes_read == 0)
298  {
299  return total_read;
300  }
301 
302  total_read += bytes_read;
303  ptr += bytes_read;
304  len -= bytes_read;
305  }
306 
307  return total_read;
308 }
309 
310 /**
311  * @note difference with files_names.h:IsDir() is that this doesn't
312  * follow symlinks, so a symlink is never a directory...
313  */
314 bool IsDirReal(const char *path)
315 {
316  struct stat s;
317 
318  if (lstat(path, &s) == -1)
319  {
320  return false; // Error
321  }
322 
323  return (S_ISDIR(s.st_mode) != 0);
324 }
325 
326 #ifndef __MINGW32__
328 {
329  return NewLineMode_Unix;
330 }
331 #endif // !__MINGW32__
332 
333 bool IsAbsoluteFileName(const char *f)
334 {
335  int off = 0;
336 
337 // Check for quoted strings
338 
339  for (off = 0; f[off] == '\"'; off++)
340  {
341  }
342 
343 #ifdef _WIN32
344  if (IsFileSep(f[off]) && IsFileSep(f[off + 1]))
345  {
346  return true;
347  }
348 
349  if (isalpha(f[off]) && f[off + 1] == ':' && IsFileSep(f[off + 2]))
350  {
351  return true;
352  }
353 #endif
354  if (IsFileSep(f[off]))
355  {
356  return true;
357  }
358 
359  return false;
360 }
361 
362 /* We assume that s is at least MAX_FILENAME large.
363  * MapName() is thread-safe, but the argument is modified. */
364 
365 #ifdef _WIN32
366 # if defined(__MINGW32__)
367 
368 char *MapNameCopy(const char *s)
369 {
370  char *str = xstrdup(s);
371 
372  char *c = str;
373  while ((c = strchr(c, '/')))
374  {
375  *c = '\\';
376  }
377 
378  return str;
379 }
380 
381 char *MapName(char *s)
382 {
383  char *c = s;
384 
385  while ((c = strchr(c, '/')))
386  {
387  *c = '\\';
388  }
389  return s;
390 }
391 
392 # elif defined(__CYGWIN__)
393 
394 char *MapNameCopy(const char *s)
395 {
396  Writer *w = StringWriter();
397 
398  /* c:\a\b -> /cygdrive/c\a\b */
399  if (s[0] && isalpha(s[0]) && s[1] == ':')
400  {
401  WriterWriteF(w, "/cygdrive/%c", s[0]);
402  s += 2;
403  }
404 
405  for (; *s; s++)
406  {
407  /* a//b//c -> a/b/c */
408  /* a\\b\\c -> a\b\c */
409  if (IsFileSep(*s) && IsFileSep(*(s + 1)))
410  {
411  continue;
412  }
413 
414  /* a\b\c -> a/b/c */
415  WriterWriteChar(w, *s == '\\' ? '/' : *s);
416  }
417 
418  return StringWriterClose(w);
419 }
420 
421 char *MapName(char *s)
422 {
423  char *ret = MapNameCopy(s);
424 
425  if (strlcpy(s, ret, MAX_FILENAME) >= MAX_FILENAME)
426  {
427  FatalError(ctx, "Expanded path (%s) is longer than MAX_FILENAME ("
428  TO_STRING(MAX_FILENAME) ") characters",
429  ret);
430  }
431  free(ret);
432 
433  return s;
434 }
435 
436 # else/* !__MINGW32__ && !__CYGWIN__ */
437 # error Unknown NT-based compilation environment
438 # endif/* __MINGW32__ || __CYGWIN__ */
439 #else /* !_WIN32 */
440 
441 char *MapName(char *s)
442 {
443  return s;
444 }
445 
446 char *MapNameCopy(const char *s)
447 {
448  return xstrdup(s);
449 }
450 
451 #endif /* !_WIN32 */
452 
453 char *MapNameForward(char *s)
454 /* Like MapName(), but maps all slashes to forward */
455 {
456  while ((s = strchr(s, '\\')))
457  {
458  *s = '/';
459  }
460  return s;
461 }
462 
463 
464 #ifdef TEST_SYMLINK_ATOMICITY
465 void switch_symlink_hook();
466 #define TEST_SYMLINK_SWITCH_POINT switch_symlink_hook();
467 #else
468 #define TEST_SYMLINK_SWITCH_POINT
469 #endif
470 
471 Seq *ListDir(const char *dir, const char *extension)
472 {
473  Dir *dirh = DirOpen(dir);
474  if (dirh == NULL)
475  {
476  return NULL;
477  }
478 
479  Seq *contents = SeqNew(10, free);
480 
481  const struct dirent *dirp;
482 
483  while ((dirp = DirRead(dirh)) != NULL)
484  {
485  const char *name = dirp->d_name;
486  if (extension == NULL || StringEndsWithCase(name, extension, true))
487  {
488  SeqAppend(contents, Path_JoinAlloc(dir, name));
489  }
490  }
491  DirClose(dirh);
492 
493  return contents;
494 }
495 
496 mode_t SetUmask(mode_t new_mask)
497 {
498  const mode_t old_mask = umask(new_mask);
499  Log(LOG_LEVEL_DEBUG, "Set umask to %o, was %o", new_mask, old_mask);
500  return old_mask;
501 }
502 void RestoreUmask(mode_t old_mask)
503 {
504  umask(old_mask);
505  Log(LOG_LEVEL_DEBUG, "Restored umask to %o", old_mask);
506 }
507 
508 /**
509  * Opens a file safely, with default (strict) permissions on creation.
510  * See safe_open_create_perms for more documentation.
511  *
512  * @param pathname The path to open.
513  * @param flags Same flags as for system open().
514  * @return Same errors as open().
515  */
516 int safe_open(const char *pathname, int flags)
517 {
518  return safe_open_create_perms(pathname, flags, CF_PERMS_DEFAULT);
519 }
520 
521 /**
522  * Opens a file safely. It will follow symlinks, but only if the symlink is
523  * trusted, that is, if the owner of the symlink and the owner of the target are
524  * the same, or if the owner of the symlink is either root or the user running
525  * the current process. All components are checked, even symlinks encountered in
526  * earlier parts of the path name.
527  *
528  * It should always be used when opening a file or directory that is not
529  * guaranteed to be owned by root.
530  *
531  * safe_open and safe_fopen both default to secure (0600) file creation perms.
532  * The _create_perms variants allow you to explicitly set different permissions.
533  *
534  * @param pathname The path to open
535  * @param flags Same flags as for system open()
536  * @param create_perms Permissions for file, only relevant on file creation
537  * @return Same errors as open()
538  * @see safe_fopen_create_perms()
539  * @see safe_open()
540  */
542  const char *const pathname, int flags, const mode_t create_perms)
543 {
544  if (flags & O_TRUNC)
545  {
546  /* Undefined behaviour otherwise, according to the standard. */
547  assert((flags & O_RDWR) || (flags & O_WRONLY));
548  }
549 
550  if (!pathname)
551  {
552  errno = EINVAL;
553  return -1;
554  }
555 
556  if (*pathname == '\0')
557  {
558  errno = ENOENT;
559  return -1;
560  }
561 
562 #ifdef __MINGW32__
563  // Windows gets off easy. No symlinks there.
564  return open(pathname, flags, create_perms);
565 #elif defined(__ANDROID__)
566  // if effective user is not root then don't try to open
567  // all paths from '/' up, might not have permissions.
568  uid_t p_euid = geteuid();
569  if (p_euid != 0)
570  {
571  return open(pathname, flags, create_perms);
572  }
573 #else // !__MINGW32__ and !__ANDROID__
574  const size_t path_bufsize = strlen(pathname) + 1;
575  char path[path_bufsize];
576  const size_t res_len = StringCopy(pathname, path, path_bufsize);
577  UNUSED(res_len);
578  assert(res_len == strlen(pathname));
579  int currentfd;
580  const char *first_dir;
581  bool trunc = false;
582  const int orig_flags = flags;
583  char *next_component = path;
584  bool p_uid;
585 
586  if (*next_component == '/')
587  {
588  first_dir = "/";
589  // Eliminate double slashes.
590  while (*(++next_component) == '/') { /*noop*/ }
591  if (!*next_component)
592  {
593  next_component = NULL;
594  }
595  }
596  else
597  {
598  first_dir = ".";
599  }
600  currentfd = openat(AT_FDCWD, first_dir, O_RDONLY);
601  if (currentfd < 0)
602  {
603  return -1;
604  }
605 
606  // current process user id
607  p_uid = geteuid();
608 
609  size_t final_size = (size_t) -1;
610  while (next_component)
611  {
612  char *component = next_component;
613  next_component = strchr(component + 1, '/');
614  // Used to restore the slashes in the final path component.
615  char *restore_slash = NULL;
616  if (next_component)
617  {
618  restore_slash = next_component;
619  *next_component = '\0';
620  // Eliminate double slashes.
621  while (*(++next_component) == '/') { /*noop*/ }
622  if (!*next_component)
623  {
624  next_component = NULL;
625  }
626  else
627  {
628  restore_slash = NULL;
629  }
630  }
631 
632  // In cases of a race condition when creating a file, our attempt to open it may fail
633  // (see O_EXCL and O_CREAT flags below). However, this can happen even under normal
634  // circumstances, if we are unlucky; it does not mean that someone is up to something bad.
635  // So retry it a few times before giving up.
636  int attempts = 3;
637  trunc = false;
638  while (true)
639  {
640 
641  if (( (orig_flags & O_RDWR) || (orig_flags & O_WRONLY))
642  && (orig_flags & O_TRUNC))
643  {
644  trunc = true;
645  /* We need to check after we have opened the file whether we
646  * opened the right one. But if we truncate it, the damage is
647  * already done, we have destroyed the contents, and that file
648  * might have been a symlink to /etc/shadow! So save that flag
649  * and apply the truncation afterwards instead. */
650  flags &= ~~O_TRUNC;
651  }
652 
653  if (restore_slash)
654  {
655  *restore_slash = '\0';
656  }
657 
658  struct stat stat_before, stat_after;
659  int stat_before_result = fstatat(currentfd, component, &stat_before, AT_SYMLINK_NOFOLLOW);
660  if (stat_before_result < 0
661  && (errno != ENOENT
662  || next_component // Meaning "not a leaf".
663  || !(flags & O_CREAT)))
664  {
665  close(currentfd);
666  return -1;
667  }
668 
669  /*
670  * This testing entry point is about the following real-world
671  * scenario: There can be an attacker that at this point
672  * overwrites the existing file or writes a file, invalidating
673  * basically the previous fstatat().
674  *
675  * - We make sure that can't happen if the file did not exist, by
676  * creating with O_EXCL.
677  * - We make sure that can't happen if the file existed, by
678  * comparing with fstat() result after the open().
679  *
680  */
682 
683  if (!next_component) /* last component */
684  {
685  if (stat_before_result < 0)
686  {
687  assert(flags & O_CREAT);
688 
689  // Doesn't exist. Make sure *we* create it.
690  flags |= O_EXCL;
691 
692  /* No need to ftruncate() the file at the end. */
693  trunc = false;
694  }
695  else
696  {
697  if ((flags & O_CREAT) && (flags & O_EXCL))
698  {
699  close(currentfd);
700  errno = EEXIST;
701  return -1;
702  }
703 
704  // Already exists. Make sure we *don't* create it.
705  flags &= ~~O_CREAT;
706  }
707  if (restore_slash)
708  {
709  *restore_slash = '/';
710  }
711  int filefd = openat(currentfd, component, flags, create_perms);
712  if (filefd < 0)
713  {
714  if ((stat_before_result < 0 && !(orig_flags & O_EXCL) && errno == EEXIST) ||
715  (stat_before_result >= 0 && (orig_flags & O_CREAT) && errno == ENOENT))
716  {
717  if (--attempts >= 0)
718  {
719  // Might be our fault. Try again.
720  flags = orig_flags;
721  continue;
722  }
723  else
724  {
725  // Too many attempts. Give up.
726  // Most likely a link that is in the way of file creation, but can also
727  // be a file that is constantly created and deleted (race condition).
728  // It is not possible to separate between the two, so return EACCES to
729  // signal that we denied access.
730  errno = EACCES;
731  }
732  }
733  close(currentfd);
734  return -1;
735  }
736  close(currentfd);
737  currentfd = filefd;
738  }
739  else
740  {
741  int new_currentfd = openat(currentfd, component, O_RDONLY);
742  close(currentfd);
743  if (new_currentfd < 0)
744  {
745  return -1;
746  }
747  currentfd = new_currentfd;
748  }
749 
750  /* If file did exist, we fstat() again and compare with previous. */
751 
752  if (stat_before_result == 0)
753  {
754  if (fstat(currentfd, &stat_after) < 0)
755  {
756  close(currentfd);
757  return -1;
758  }
759  // Some attacks may use symlinks to get higher privileges
760  // The safe cases are:
761  // * symlinks owned by root
762  // * symlinks owned by the user running the process
763  // * symlinks that have the same owner and group as the destination
764  if (stat_before.st_uid != 0 &&
765  stat_before.st_uid != p_uid &&
766  (stat_before.st_uid != stat_after.st_uid || stat_before.st_gid != stat_after.st_gid))
767  {
768  close(currentfd);
769  Log(LOG_LEVEL_ERR, "Cannot follow symlink '%s'; it is not "
770  "owned by root or the user running this process, and "
771  "the target owner and/or group differs from that of "
772  "the symlink itself.", pathname);
773  // Return ENOLINK to signal that the link cannot be followed
774  // ('Link has been severed').
775  errno = ENOLINK;
776  return -1;
777  }
778 
779  final_size = (size_t) stat_after.st_size;
780  }
781 
782  // If we got here, we've been successful, so don't try again.
783  break;
784  }
785  }
786 
787  /* Truncate if O_CREAT and the file preexisted. */
788  if (trunc)
789  {
790  /* Do not truncate if the size is already zero, some
791  * filesystems don't support ftruncate() with offset>=size. */
792  assert(final_size != (size_t) -1);
793 
794  if (final_size != 0)
795  {
796  int tr_ret = ftruncate(currentfd, 0);
797  if (tr_ret < 0)
798  {
800  "safe_open: unexpected failure (ftruncate: %s)",
801  GetErrorStr());
802  close(currentfd);
803  return -1;
804  }
805  }
806  }
807 
808  return currentfd;
809 #endif // !__MINGW32__
810 }
811 
812 FILE *safe_fopen(const char *const path, const char *const mode)
813 {
814  return safe_fopen_create_perms(path, mode, CF_PERMS_DEFAULT);
815 }
816 
817 /**
818  * Opens a file safely. It will follow symlinks, but only if the symlink is trusted,
819  * that is, if the owner of the symlink and the owner of the target are the same,
820  * or if the owner of the symlink is either root or the user running the current process.
821  * All components are checked, even symlinks encountered in earlier parts of the
822  * path name.
823  *
824  * It should always be used when opening a directory that is not guaranteed to be
825  * owned by root.
826  *
827  * @param pathname The path to open.
828  * @param flags Same mode as for system fopen().
829  * @param create_perms Permissions for file, only relevant on file creation.
830  * @return Same errors as fopen().
831  */
833  const char *const path, const char *const mode, const mode_t create_perms)
834 {
835  if (!path || !mode)
836  {
837  errno = EINVAL;
838  return NULL;
839  }
840 
841  int flags = 0;
842  for (int c = 0; mode[c]; c++)
843  {
844  switch (mode[c])
845  {
846  case 'r':
847  flags |= O_RDONLY;
848  break;
849  case 'w':
850  flags |= O_WRONLY | O_TRUNC | O_CREAT;
851  break;
852  case 'a':
853  flags |= O_WRONLY | O_CREAT;
854  break;
855  case '+':
856  flags &= ~(O_RDONLY | O_WRONLY);
857  flags |= O_RDWR;
858  break;
859  case 'b':
860  flags |= O_BINARY;
861  break;
862  case 't':
863  flags |= O_TEXT;
864  break;
865  case 'x':
866  flags |= O_EXCL;
867  break;
868  default:
869  ProgrammingError("Invalid flag for fopen: %s", mode);
870  return NULL;
871  }
872  }
873 
874  int fd = safe_open_create_perms(path, flags, create_perms);
875  if (fd < 0)
876  {
877  return NULL;
878  }
879  FILE *ret = fdopen(fd, mode);
880  if (!ret)
881  {
882  close(fd);
883  return NULL;
884  }
885 
886  if (mode[0] == 'a')
887  {
888  if (fseek(ret, 0, SEEK_END) < 0)
889  {
890  fclose(ret);
891  return NULL;
892  }
893  }
894 
895  return ret;
896 }
897 
898 /**
899  * Use this instead of chdir(). It changes into the directory safely, using safe_open().
900  * @param path Path to change into.
901  * @return Same return values as chdir().
902  */
903 int safe_chdir(const char *path)
904 {
905 #ifdef __MINGW32__
906  return chdir(path);
907 #else // !__MINGW32__
908  int fd = safe_open(path, O_RDONLY);
909  if (fd < 0)
910  {
911  return -1;
912  }
913  if (fchdir(fd) < 0)
914  {
915  close(fd);
916  return -1;
917  }
918  close(fd);
919  return 0;
920 #endif // !__MINGW32__
921 }
922 
923 #ifndef __MINGW32__
924 
925 /**
926  * Opens the true parent dir of the file in the path given. The notable
927  * difference from doing it the naive way (open(dirname(path))) is that it
928  * can follow the symlinks of the path, ending up in the true parent dir of the
929  * path. It follows the same safe mechanisms as `safe_open()` to do so. If
930  * AT_SYMLINK_NOFOLLOW is given, it is equivalent to doing it the naive way (but
931  * still following "safe" semantics).
932  * @param path Path to open parent directory of.
933  * @param flags Flags to use for fchownat.
934  * @param link_user If we have traversed a link already, which user was it.
935  * @param link_group If we have traversed a link already, which group was it.
936  * @param traversed_link Whether we have traversed a link. If this is false the
937  * two previus arguments are ignored. This is used enforce
938  * the correct UID/GID combination when following links.
939  * Initially this is false, but will be set to true in
940  * sub invocations if we follow a link.
941  * @param loop_countdown Protection against infinite loop following.
942  * @return File descriptor pointing to the parent directory of path, or -1 on
943  * error.
944  */
945 static int safe_open_true_parent_dir(const char *path,
946  int flags,
947  uid_t link_user,
948  gid_t link_group,
949  bool traversed_link,
950  int loop_countdown)
951 {
952  int dirfd = -1;
953  int ret = -1;
954 
955  char *parent_dir_alloc = xstrdup(path);
956  char *leaf_alloc = xstrdup(path);
957  char *parent_dir = dirname(parent_dir_alloc);
958  char *leaf = basename(leaf_alloc);
959  struct stat statbuf;
960  uid_t p_uid = geteuid();
961 
962  if ((dirfd = safe_open(parent_dir, O_RDONLY)) == -1)
963  {
964  goto cleanup;
965  }
966 
967  if ((ret = fstatat(dirfd, leaf, &statbuf, AT_SYMLINK_NOFOLLOW)) == -1)
968  {
969  goto cleanup;
970  }
971 
972  // Some attacks may use symlinks to get higher privileges
973  // The safe cases are:
974  // * symlinks owned by root
975  // * symlinks owned by the user running the process
976  // * symlinks that have the same owner and group as the destination
977  if (traversed_link &&
978  link_user != 0 &&
979  link_user != p_uid &&
980  (link_user != statbuf.st_uid || link_group != statbuf.st_gid))
981  {
982  errno = ENOLINK;
983  ret = -1;
984  goto cleanup;
985  }
986 
987  if (S_ISLNK(statbuf.st_mode) && !(flags & AT_SYMLINK_NOFOLLOW))
988  {
989  if (--loop_countdown <= 0)
990  {
991  ret = -1;
992  errno = ELOOP;
993  goto cleanup;
994  }
995 
996  // Add one byte for '\0', and one byte to make sure size doesn't change
997  // in between calls.
998  char *link = xmalloc(statbuf.st_size + 2);
999  ret = readlinkat(dirfd, leaf, link, statbuf.st_size + 1);
1000  if (ret < 0 || ret > statbuf.st_size)
1001  {
1002  // Link either disappeared or was changed under our feet. Be safe
1003  // and bail out.
1004  free(link);
1005  errno = ENOLINK;
1006  ret = -1;
1007  goto cleanup;
1008  }
1009  link[ret] = '\0';
1010 
1011  char *resolved_link;
1012  if (link[0] == FILE_SEPARATOR)
1013  {
1014  // Takes ownership of link's memory, so no free().
1015  resolved_link = link;
1016  }
1017  else
1018  {
1019  xasprintf(&resolved_link, "%s%c%s", parent_dir,
1020  FILE_SEPARATOR, link);
1021  free(link);
1022  }
1023 
1024  ret = safe_open_true_parent_dir(resolved_link, flags, statbuf.st_uid,
1025  statbuf.st_gid, true, loop_countdown);
1026 
1027  free(resolved_link);
1028  goto cleanup;
1029  }
1030 
1031  // We now know it either isn't a link, or we don't want to follow it if it
1032  // is. Return the parent dir.
1033  ret = dirfd;
1034  dirfd = -1;
1035 
1036 cleanup:
1037  free(parent_dir_alloc);
1038  free(leaf_alloc);
1039 
1040  if (dirfd != -1)
1041  {
1042  close(dirfd);
1043  }
1044 
1045  return ret;
1046 }
1047 
1048 /**
1049  * Implementation of safe_chown.
1050  * @param path Path to chown.
1051  * @param owner Owner to set on path.
1052  * @param group Group to set on path.
1053  * @param flags Flags to use for fchownat.
1054  * @param link_user If we have traversed a link already, which user was it.
1055  * @param link_group If we have traversed a link already, which group was it.
1056  * @param traversed_link Whether we have traversed a link. If this is false the
1057  * two previus arguments are ignored. This is used enforce
1058  * the correct UID/GID combination when following links.
1059  * Initially this is false, but will be set to true in
1060  * sub invocations if we follow a link.
1061  * @param loop_countdown Protection against infinite loop following.
1062  */
1063 int safe_chown_impl(const char *path, uid_t owner, gid_t group, int flags)
1064 {
1065  int dirfd = safe_open_true_parent_dir(path, flags, 0, 0, false, SYMLINK_MAX_DEPTH);
1066  if (dirfd < 0)
1067  {
1068  return -1;
1069  }
1070 
1071  char *leaf_alloc = xstrdup(path);
1072  char *leaf = basename(leaf_alloc);
1073 
1074  // We now know it either isn't a link, or we don't want to follow it if it
1075  // is. In either case make sure we don't try to follow it.
1076  flags |= AT_SYMLINK_NOFOLLOW;
1077 
1078  int ret = fchownat(dirfd, leaf, owner, group, flags);
1079  free(leaf_alloc);
1080  close(dirfd);
1081  return ret;
1082 }
1083 
1084 #endif // !__MINGW32__
1085 
1086 /**
1087  * Use this instead of chown(). It changes file owner safely, using safe_open().
1088  * @param path Path to operate on.
1089  * @param owner Owner.
1090  * @param group Group.
1091  * @return Same return values as chown().
1092  */
1093 int safe_chown(const char *path, uid_t owner, gid_t group)
1094 {
1095 #ifdef __MINGW32__
1096  return chown(path, owner, group);
1097 #else // !__MINGW32__
1098  return safe_chown_impl(path, owner, group, 0);
1099 #endif // !__MINGW32__
1100 }
1101 
1102 /**
1103  * Use this instead of lchown(). It changes file owner safely, using safe_open().
1104  * @param path Path to operate on.
1105  * @param owner Owner.
1106  * @param group Group.
1107  * @return Same return values as lchown().
1108  */
1109 #ifndef __MINGW32__
1110 int safe_lchown(const char *path, uid_t owner, gid_t group)
1111 {
1112  return safe_chown_impl(path, owner, group, AT_SYMLINK_NOFOLLOW);
1113 }
1114 #endif // !__MINGW32__
1115 
1116 /**
1117  * Use this instead of chmod(). It changes file permissions safely, using safe_open().
1118  * @param path Path to operate on.
1119  * @param mode Permissions.
1120  * @return Same return values as chmod().
1121  */
1122 int safe_chmod(const char *path, mode_t mode)
1123 {
1124 #ifdef __MINGW32__
1125  return chmod(path, mode);
1126 #else // !__MINGW32__
1127  int dirfd = -1;
1128  int ret = -1;
1129 
1130  char *leaf_alloc = xstrdup(path);
1131  char *leaf = basename(leaf_alloc);
1132  struct stat statbuf;
1133  uid_t olduid = 0;
1134 
1135  if ((dirfd = safe_open_true_parent_dir(path, 0, 0, 0, false, SYMLINK_MAX_DEPTH)) == -1)
1136  {
1137  goto cleanup;
1138  }
1139 
1140  if ((ret = fstatat(dirfd, leaf, &statbuf, AT_SYMLINK_NOFOLLOW)) == -1)
1141  {
1142  goto cleanup;
1143  }
1144 
1145  if (S_ISFIFO(statbuf.st_mode) || S_ISSOCK(statbuf.st_mode))
1146  {
1147  /* For FIFOs/sockets we cannot resort to the method of opening the file
1148  first, since it might block. But we also cannot use chmod directly,
1149  because the file may be switched with a symlink to a sensitive file
1150  under our feet, and there is no way to avoid following it. So
1151  instead, switch effective UID to the owner of the FIFO, and then use
1152  chmod.
1153  */
1154 
1155  /* save old euid */
1156  olduid = geteuid();
1157 
1158  if ((ret = seteuid(statbuf.st_uid)) == -1)
1159  {
1160  goto cleanup;
1161  }
1162 
1163  ret = fchmodat(dirfd, leaf, mode, 0);
1164 
1165  // Make sure EUID is set back before we check error condition, so that we
1166  // never return with lowered privileges.
1167  if (seteuid(olduid) == -1)
1168  {
1169  ProgrammingError("safe_chmod: Could not set EUID back. Should never happen.");
1170  }
1171 
1172  goto cleanup;
1173  }
1174 
1175  int file_fd = safe_open(path, 0);
1176  if (file_fd < 0)
1177  {
1178  ret = -1;
1179  goto cleanup;
1180  }
1181 
1182  ret = fchmod(file_fd, mode);
1183  close(file_fd);
1184 
1185 cleanup:
1186  free(leaf_alloc);
1187 
1188  if (dirfd != -1)
1189  {
1190  close(dirfd);
1191  }
1192 
1193  return ret;
1194 #endif // !__MINGW32__
1195 }
1196 
1197 /**
1198  * Use this instead of creat(). It creates a file safely, using safe_open().
1199  * @param path Path to operate on.
1200  * @param mode Permissions.
1201  * @return Same return values as creat().
1202  */
1203 int safe_creat(const char *pathname, mode_t mode)
1204 {
1205  return safe_open_create_perms(pathname,
1206  O_CREAT | O_WRONLY | O_TRUNC,
1207  mode);
1208 }
1209 
1210 // Windows implementation in Enterprise.
1211 #ifndef _WIN32
1212 bool SetCloseOnExec(int fd, bool enable)
1213 {
1214  int flags = fcntl(fd, F_GETFD);
1215  if (enable)
1216  {
1217  flags |= FD_CLOEXEC;
1218  }
1219  else
1220  {
1221  flags &= ~~FD_CLOEXEC;
1222  }
1223  return (fcntl(fd, F_SETFD, flags) == 0);
1224 }
1225 #endif // !_WIN32
1226 
1227 static bool DeleteDirectoryTreeInternal(const char *basepath, const char *path)
1228 {
1229  Dir *dirh = DirOpen(path);
1230  const struct dirent *dirp;
1231  bool failed = false;
1232 
1233  if (dirh == NULL)
1234  {
1235  if (errno == ENOENT)
1236  {
1237  /* Directory disappeared on its own */
1238  return true;
1239  }
1240 
1241  Log(LOG_LEVEL_INFO, "Unable to open directory '%s' during purge of directory tree '%s' (opendir: %s)",
1242  path, basepath, GetErrorStr());
1243  return false;
1244  }
1245 
1246  for (dirp = DirRead(dirh); dirp != NULL; dirp = DirRead(dirh))
1247  {
1248  if (!strcmp(dirp->d_name, ".") || !strcmp(dirp->d_name, ".."))
1249  {
1250  continue;
1251  }
1252 
1253  char subpath[PATH_MAX];
1254  snprintf(subpath, sizeof(subpath), "%s" FILE_SEPARATOR_STR "%s", path, dirp->d_name);
1255 
1256  struct stat lsb;
1257  if (lstat(subpath, &lsb) == -1)
1258  {
1259  if (errno == ENOENT)
1260  {
1261  /* File disappeared on its own */
1262  continue;
1263  }
1264 
1265  Log(LOG_LEVEL_VERBOSE, "Unable to stat file '%s' during purge of directory tree '%s' (lstat: %s)", path, basepath, GetErrorStr());
1266  failed = true;
1267  }
1268  else
1269  {
1270  if (S_ISDIR(lsb.st_mode))
1271  {
1272  if (!DeleteDirectoryTreeInternal(basepath, subpath))
1273  {
1274  failed = true;
1275  }
1276 
1277  if (rmdir(subpath) == -1)
1278  {
1279  failed = true;
1280  }
1281  }
1282  else
1283  {
1284  if (unlink(subpath) == -1)
1285  {
1286  if (errno == ENOENT)
1287  {
1288  /* File disappeared on its own */
1289  continue;
1290  }
1291 
1292  Log(LOG_LEVEL_VERBOSE, "Unable to remove file '%s' during purge of directory tree '%s'. (unlink: %s)",
1293  subpath, basepath, GetErrorStr());
1294  failed = true;
1295  }
1296  }
1297  }
1298  }
1299 
1300  DirClose(dirh);
1301  return !failed;
1302 }
1303 
1304 bool DeleteDirectoryTree(const char *path)
1305 {
1306  return DeleteDirectoryTreeInternal(path, path);
1307 }
1308 
1309 /**
1310  * @NOTE Better use FileSparseCopy() if you are copying file to file
1311  * (that one callse this function).
1312  *
1313  * @NOTE Always use FileSparseWrite() to close the file descriptor, to avoid
1314  * losing data.
1315  */
1316 bool FileSparseWrite(int fd, const void *buf, size_t count,
1317  bool *wrote_hole)
1318 {
1319  bool all_zeroes = (memcchr(buf, '\0', count) == NULL);
1320 
1321  if (all_zeroes) /* write a hole */
1322  {
1323  off_t seek_ret = lseek(fd, count, SEEK_CUR);
1324  if (seek_ret == (off_t) -1)
1325  {
1327  "Failed to write a hole in sparse file (lseek: %s)",
1328  GetErrorStr());
1329  return false;
1330  }
1331  }
1332  else /* write normally */
1333  {
1334  ssize_t w_ret = FullWrite(fd, buf, count);
1335  if (w_ret < 0)
1336  {
1338  "Failed to write to destination file (write: %s)",
1339  GetErrorStr());
1340  return false;
1341  }
1342  }
1343 
1344  *wrote_hole = all_zeroes;
1345  return true;
1346 }
1347 
1348 /**
1349  * Copy data jumping over areas filled by '\0' greater than blk_size, so
1350  * files automatically become sparse if possible.
1351  *
1352  * File descriptors should already be open, the filenames #source and
1353  * #destination are only for logging purposes.
1354  *
1355  * @NOTE Always use FileSparseClose() to close the file descriptor, to avoid
1356  * losing data.
1357  */
1358 bool FileSparseCopy(int sd, const char *src_name,
1359  int dd, const char *dst_name,
1360  size_t blk_size,
1361  size_t *total_bytes_written,
1362  bool *last_write_was_a_hole)
1363 {
1364  assert(total_bytes_written != NULL);
1365  assert(last_write_was_a_hole != NULL);
1366 
1367  const size_t buf_size = blk_size;
1368  void *buf = xmalloc(buf_size);
1369 
1370  size_t n_read_total = 0;
1371  bool retval = false;
1372 
1373  *last_write_was_a_hole = false;
1374 
1375  while (true)
1376  {
1377  ssize_t n_read = FullRead(sd, buf, buf_size);
1378  if (n_read < 0)
1379  {
1381  "Unable to read source file while copying '%s' to '%s'"
1382  " (read: %s)", src_name, dst_name, GetErrorStr());
1383  break;
1384  }
1385  else if (n_read == 0) /* EOF */
1386  {
1387  retval = true;
1388  break;
1389  }
1390 
1391  bool ret = FileSparseWrite(dd, buf, n_read,
1392  last_write_was_a_hole);
1393  if (!ret)
1394  {
1395  Log(LOG_LEVEL_ERR, "Failed to copy '%s' to '%s'",
1396  src_name, dst_name);
1397  break;
1398  }
1399 
1400  n_read_total += n_read;
1401  }
1402 
1403  free(buf);
1404  *total_bytes_written = n_read_total;
1405  return retval;
1406 }
1407 
1408 /**
1409  * Always close a written sparse file using this function, else truncation
1410  * might occur if the last part was a hole.
1411  *
1412  * If the tail of the file was a hole (and hence lseek(2)ed on destination
1413  * instead of being written), do a ftruncate(2) here to ensure the whole file
1414  * is written to the disc. But ftruncate() fails with EPERM on non-native
1415  * Linux filesystems (e.g. vfat, vboxfs) when the count is >= than the
1416  * size of the file. So we write() one byte and then ftruncate() it back.
1417  *
1418  * No need for this function to return anything, since the filedescriptor is
1419  * (attempted to) closed in either success or failure.
1420  *
1421  * TODO? instead of needing the #total_bytes_written parameter, we could
1422  * figure the offset after writing the one byte using lseek(fd,0,SEEK_CUR) and
1423  * truncate -1 from that offset. It's probably not worth adding an extra
1424  * system call for simplifying code.
1425  */
1426 bool FileSparseClose(int fd, const char *filename,
1427  bool do_sync,
1428  size_t total_bytes_written,
1429  bool last_write_was_hole)
1430 {
1431  if (last_write_was_hole)
1432  {
1433  ssize_t ret1 = FullWrite(fd, "", 1);
1434  if (ret1 == -1)
1435  {
1437  "Failed to close sparse file '%s' (write: %s)",
1438  filename, GetErrorStr());
1439  close(fd);
1440  return false;
1441  }
1442 
1443  int ret2 = ftruncate(fd, total_bytes_written);
1444  if (ret2 == -1)
1445  {
1447  "Failed to close sparse file '%s' (ftruncate: %s)",
1448  filename, GetErrorStr());
1449  close(fd);
1450  return false;
1451  }
1452  }
1453 
1454  if (do_sync)
1455  {
1456  if (fsync(fd) != 0)
1457  {
1459  "Could not sync to disk file '%s' (fsync: %s)",
1460  filename, GetErrorStr());
1461  }
1462  }
1463 
1464  int ret3 = close(fd);
1465  if (ret3 == -1)
1466  {
1468  "Failed to close file '%s' (close: %s)",
1469  filename, GetErrorStr());
1470  return false;
1471  }
1472 
1473  return true;
1474 }
1475 
1476 ssize_t CfReadLine(char **buff, size_t *size, FILE *fp)
1477 {
1478  ssize_t b = getline(buff, size, fp);
1479  assert(b != 0 && "To the best of my knowledge, getline never returns zero");
1480 
1481  if (b > 0)
1482  {
1483  if ((*buff)[b - 1] == '\n')
1484  {
1485  (*buff)[b - 1] = '\0';
1486  b--;
1487  }
1488  }
1489 
1490  return b;
1491 }
1492 
1493 ssize_t CfReadLines(char **buff, size_t *size, FILE *fp, Seq *lines)
1494 {
1495  assert(size != NULL);
1496  assert(fp != NULL);
1497  assert(lines != NULL);
1498  assert((buff != NULL) || *size == 0);
1499 
1500  ssize_t appended = 0;
1501 
1502  ssize_t ret;
1503  bool free_buff = (buff == NULL);
1504  while (!feof(fp))
1505  {
1506  assert((buff != NULL) || *size == 0);
1507  ret = CfReadLine(buff, size, fp);
1508  if (ret == -1)
1509  {
1510  if (!feof(fp))
1511  {
1512  if (free_buff)
1513  {
1514  free(*buff);
1515  }
1516  return -1;
1517  }
1518  }
1519  else
1520  {
1521  SeqAppend(lines, xstrdup(*buff));
1522  appended++;
1523  }
1524  }
1525  if (free_buff)
1526  {
1527  free(*buff);
1528  }
1529 
1530  return appended;
1531 }
1532 
1533 StringSet* GlobFileList(const char *pattern)
1534 {
1535  StringSet *set = StringSetNew();
1536  glob_t globbuf;
1537  int globflags = 0; // TODO: maybe add GLOB_BRACE later
1538 
1539  const char* r_candidates[] = { "*", "*/*", "*/*/*", "*/*/*/*", "*/*/*/*/*", "*/*/*/*/*/*" };
1540  bool starstar = ( strstr(pattern, "**") != NULL );
1541  const char** candidates = starstar ? r_candidates : NULL;
1542  const int candidate_count = starstar ? 6 : 1;
1543 
1544  for (int pi = 0; pi < candidate_count; pi++)
1545  {
1546  char *expanded = starstar ?
1547  SearchAndReplace(pattern, "**", candidates[pi]) :
1548  xstrdup(pattern);
1549 
1550 #ifdef _WIN32
1551  if (strchr(expanded, '\\'))
1552  {
1553  Log(LOG_LEVEL_VERBOSE, "Found backslash escape character in glob pattern '%s'. "
1554  "Was forward slash intended?", expanded);
1555  }
1556 #endif
1557 
1558  if (glob(expanded, globflags, NULL, &globbuf) == 0)
1559  {
1560  for (int i = 0; i < globbuf.gl_pathc; i++)
1561  {
1562  StringSetAdd(set, xstrdup(globbuf.gl_pathv[i]));
1563  }
1564 
1565  globfree(&globbuf);
1566  }
1567 
1568  free(expanded);
1569  }
1570 
1571  return set;
1572 }
1573 
1574 /*******************************************************************/
1575 
1577 {
1578  const char *procdir = getenv("CFENGINE_TEST_OVERRIDE_PROCDIR");
1579  if (procdir == NULL)
1580  {
1581  procdir = "";
1582  }
1583  else
1584  {
1585  Log(LOG_LEVEL_VERBOSE, "Overriding /proc location to be %s", procdir);
1586  }
1587 
1588  return procdir;
1589 }
1590 
1591 
1592 #if !defined(__MINGW32__)
1593 
1594 static int LockFD(int fd, short int lock_type, bool wait)
1595 {
1596  struct flock lock_spec = {
1597  .l_type = lock_type,
1598  .l_whence = SEEK_SET,
1599  .l_start = 0, /* start of the region to which the lock applies */
1600  .l_len = 0 /* till EOF */
1601  };
1602 
1603  if (wait)
1604  {
1605  while (fcntl(fd, F_SETLKW, &lock_spec) == -1)
1606  {
1607  if (errno != EINTR)
1608  {
1609  Log(LOG_LEVEL_DEBUG, "Failed to acquire file lock for FD %d: %s",
1610  fd, GetErrorStr());
1611  return -1;
1612  }
1613  }
1614  return 0;
1615  }
1616  else
1617  {
1618  if (fcntl(fd, F_SETLK, &lock_spec) == -1)
1619  {
1620  Log(LOG_LEVEL_DEBUG, "Failed to acquire file lock for FD %d: %s",
1621  fd, GetErrorStr());
1622  return -1;
1623  }
1624  /* else */
1625  return 0;
1626  }
1627 }
1628 
1629 static int UnlockFD(int fd)
1630 {
1631  struct flock lock_spec = {
1632  .l_type = F_UNLCK,
1633  .l_whence = SEEK_SET,
1634  .l_start = 0, /* start of the region to which the lock applies */
1635  .l_len = 0 /* till EOF */
1636  };
1637 
1638  if (fcntl(fd, F_SETLK, &lock_spec) == -1)
1639  {
1640  Log(LOG_LEVEL_DEBUG, "Failed to release file lock for FD %d: %s",
1641  fd, GetErrorStr());
1642  return -1;
1643  }
1644  /* else */
1645  return 0;
1646 }
1647 
1648 int ExclusiveFileLock(FileLock *lock, bool wait)
1649 {
1650  assert(lock != NULL);
1651  assert(lock->fd >= 0);
1652 
1653  return LockFD(lock->fd, F_WRLCK, wait);
1654 }
1655 
1656 int SharedFileLock(FileLock *lock, bool wait)
1657 {
1658  assert(lock != NULL);
1659  assert(lock->fd >= 0);
1660 
1661  return LockFD(lock->fd, F_RDLCK, wait);
1662 }
1663 
1665 {
1666  assert(lock != NULL);
1667  assert(lock->fd >= 0);
1668 
1669  struct flock lock_spec = {
1670  .l_type = F_WRLCK,
1671  .l_whence = SEEK_SET,
1672  .l_start = 0, /* start of the region to which the lock applies */
1673  .l_len = 0 /* till EOF */
1674  };
1675  if (fcntl(lock->fd, F_GETLK, &lock_spec) == -1)
1676  {
1677  /* should never happen */
1678  Log(LOG_LEVEL_ERR, "Error when checking locks on FD %d", lock->fd);
1679  return false;
1680  }
1681  return (lock_spec.l_type == F_UNLCK);
1682 }
1683 
1684 int ExclusiveFileUnlock(FileLock *lock, bool close_fd)
1685 {
1686  assert(lock != NULL);
1687  assert(lock->fd >= 0);
1688 
1689  if (close_fd)
1690  {
1691  /* also releases the lock */
1692  int ret = close(lock->fd);
1693  if (ret != 0)
1694  {
1695  Log(LOG_LEVEL_ERR, "Failed to close lock file with FD %d: %s",
1696  lock->fd, GetErrorStr());
1697  lock->fd = -1;
1698  return -1;
1699  }
1700  /* else*/
1701  lock->fd = -1;
1702  return 0;
1703  }
1704  else
1705  {
1706  return UnlockFD(lock->fd);
1707  }
1708 }
1709 
1710 int SharedFileUnlock(FileLock *lock, bool close_fd)
1711 {
1712  assert(lock != NULL);
1713  assert(lock->fd >= 0);
1714 
1715  /* unlocking is the same for both kinds of locks */
1716  return ExclusiveFileUnlock(lock, close_fd);
1717 }
1718 
1719 #else /* __MINGW32__ */
1720 
1721 static int LockFD(int fd, DWORD flags, bool wait)
1722 {
1723  OVERLAPPED ol = { 0 };
1724  ol.Offset = INT_MAX;
1725 
1726  if (!wait)
1727  {
1728  flags |= LOCKFILE_FAIL_IMMEDIATELY;
1729  }
1730 
1731  HANDLE fh = (HANDLE)_get_osfhandle(fd);
1732 
1733  if (!LockFileEx(fh, flags, 0, 1, 0, &ol))
1734  {
1735  Log(LOG_LEVEL_DEBUG, "Failed to acquire file lock for FD %d: %s",
1736  fd, GetErrorStr());
1737  return -1;
1738  }
1739 
1740  return 0;
1741 }
1742 
1743 int ExclusiveFileLock(FileLock *lock, bool wait)
1744 {
1745  assert(lock != NULL);
1746  assert(lock->fd >= 0);
1747 
1748  return LockFD(lock->fd, LOCKFILE_EXCLUSIVE_LOCK, wait);
1749 }
1750 
1751 int SharedFileLock(FileLock *lock, bool wait)
1752 {
1753  assert(lock != NULL);
1754  assert(lock->fd >= 0);
1755 
1756  return LockFD(lock->fd, 0, wait);
1757 }
1758 
1759 static int UnlockFD(int fd)
1760 {
1761  OVERLAPPED ol = { 0 };
1762  ol.Offset = INT_MAX;
1763 
1764  HANDLE fh = (HANDLE)_get_osfhandle(fd);
1765 
1766  if (!UnlockFileEx(fh, 0, 1, 0, &ol))
1767  {
1768  Log(LOG_LEVEL_DEBUG, "Failed to release file lock for FD %d: %s",
1769  fd, GetErrorStr());
1770  return -1;
1771  }
1772 
1773  return 0;
1774 }
1775 
1776 bool ExclusiveFileLockCheck(FileLock *lock)
1777 {
1778  /* XXX: there seems to be no way to check if the current process is holding
1779  * a lock on a file */
1780  return false;
1781 }
1782 
1783 int ExclusiveFileUnlock(FileLock *lock, bool close_fd)
1784 {
1785  assert(lock != NULL);
1786  assert(lock->fd >= 0);
1787 
1788  int ret = UnlockFD(lock->fd);
1789  if (close_fd)
1790  {
1791  close(lock->fd);
1792  lock->fd = -1;
1793  }
1794  return ret;
1795 }
1796 
1797 int SharedFileUnlock(FileLock *lock, bool close_fd)
1798 {
1799  assert(lock != NULL);
1800  assert(lock->fd >= 0);
1801 
1802  /* unlocking is the same for both kinds of locks */
1803  return ExclusiveFileUnlock(lock, close_fd);
1804 }
1805 
1806 #endif /* __MINGW32__ */
1807 
1808 int ExclusiveFileLockPath(FileLock *lock, const char *fpath, bool wait)
1809 {
1810  assert(lock != NULL);
1811  assert(lock->fd < 0);
1812 
1813  int fd = safe_open(fpath, O_CREAT|O_RDWR);
1814  if (fd < 0)
1815  {
1816  Log(LOG_LEVEL_ERR, "Failed to open '%s' for locking", fpath);
1817  return -2;
1818  }
1819 
1820  lock->fd = fd;
1821  int ret = ExclusiveFileLock(lock, wait);
1822  if (ret != 0)
1823  {
1824  lock->fd = -1;
1825  }
1826  return ret;
1827 }
1828 
1829 int SharedFileLockPath(FileLock *lock, const char *fpath, bool wait)
1830 {
1831  assert(lock != NULL);
1832  assert(lock->fd < 0);
1833 
1834  int fd = safe_open(fpath, O_CREAT|O_RDONLY);
1835  if (fd < 0)
1836  {
1837  Log(LOG_LEVEL_ERR, "Failed to open '%s' for locking", fpath);
1838  return -2;
1839  }
1840 
1841  lock->fd = fd;
1842  int ret = SharedFileLock(lock, wait);
1843  if (ret != 0)
1844  {
1845  lock->fd = -1;
1846  }
1847  return ret;
1848 }
void * xmalloc(size_t size)
Definition: alloc-mini.c:46
char * xstrdup(const char *str)
Definition: alloc-mini.c:56
int xasprintf(char **strp, const char *fmt,...)
Definition: alloc.c:71
void FatalError(const EvalContext *ctx, char *s,...)
Definition: audit.c:94
#define ARG_UNUSED
Definition: cf-net.c:47
void free(void *)
#define UNUSED(x)
Definition: compiler.h:69
#define TO_STRING(x)
Definition: compiler.h:79
#define CF_PERMS_DEFAULT
Definition: definitions.h:58
const struct dirent * DirRead(Dir *dir)
Definition: unix_dir.c:92
void DirClose(Dir *dir)
Definition: unix_dir.c:118
Dir * DirOpen(const char *dirname)
Definition: unix_dir.c:41
int dirfd(DIR *dirp)
static void cleanup(void *generic_data)
Definition: fchmodat.c:56
int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags)
Definition: fchmodat.c:60
int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group, int flags)
Definition: fchownat.c:61
bool FileSparseClose(int fd, const char *filename, bool do_sync, size_t total_bytes_written, bool last_write_was_hole)
Definition: file_lib.c:1426
#define TEST_SYMLINK_SWITCH_POINT
Definition: file_lib.c:468
bool DeleteDirectoryTree(const char *path)
Deletes directory path recursively. Symlinks are not followed. Note that this function only deletes t...
Definition: file_lib.c:1304
int safe_chmod(const char *path, mode_t mode)
Definition: file_lib.c:1122
int safe_chdir(const char *path)
Definition: file_lib.c:903
int ExclusiveFileLockPath(FileLock *lock, const char *fpath, bool wait)
Definition: file_lib.c:1808
FILE * safe_fopen_create_perms(const char *const path, const char *const mode, const mode_t create_perms)
Definition: file_lib.c:832
bool FileCanOpen(const char *path, const char *modes)
Definition: file_lib.c:46
mode_t SetUmask(mode_t new_mask)
Definition: file_lib.c:496
static bool DeleteDirectoryTreeInternal(const char *basepath, const char *path)
Definition: file_lib.c:1227
ssize_t ReadFileStreamToBuffer(FILE *file, size_t max_bytes, char *buf)
Definition: file_lib.c:76
ssize_t CfReadLines(char **buff, size_t *size, FILE *fp, Seq *lines)
Read lines from a file and return them as a sequence.
Definition: file_lib.c:1493
ssize_t FullWrite(int desc, const char *ptr, size_t len)
Definition: file_lib.c:253
bool FileSparseCopy(int sd, const char *src_name, int dd, const char *dst_name, size_t blk_size, size_t *total_bytes_written, bool *last_write_was_a_hole)
Definition: file_lib.c:1358
bool File_CopyToDir(const char *src, const char *dst_dir)
Definition: file_lib.c:177
static int LockFD(int fd, short int lock_type, bool wait)
Definition: file_lib.c:1594
char * MapNameForward(char *s)
Definition: file_lib.c:453
int ExclusiveFileLock(FileLock *lock, bool wait)
Definition: file_lib.c:1648
int safe_lchown(const char *path, uid_t owner, gid_t group)
Definition: file_lib.c:1110
#define READ_BUFSIZE
Definition: file_lib.c:61
Seq * ListDir(const char *dir, const char *extension)
Definition: file_lib.c:471
const char * GetRelocatedProcdirRoot()
For testing things against /proc, uses env var CFENGINE_TEST_OVERRIDE_PROCDIR.
Definition: file_lib.c:1576
int ExclusiveFileUnlock(FileLock *lock, bool close_fd)
Definition: file_lib.c:1684
int safe_chown_impl(const char *path, uid_t owner, gid_t group, int flags)
Definition: file_lib.c:1063
int SharedFileLock(FileLock *lock, bool wait)
Definition: file_lib.c:1656
ssize_t CfReadLine(char **buff, size_t *size, FILE *fp)
Works exactly like posix 'getline', EXCEPT it does not include carriage return at the end.
Definition: file_lib.c:1476
Writer * FileRead(const char *filename, size_t max_size, bool *truncated)
Definition: file_lib.c:63
bool IsDirReal(const char *path)
Definition: file_lib.c:314
bool SetCloseOnExec(int fd, bool enable)
Sets whether a file descriptor should be closed on exec()/CreateProcess().
Definition: file_lib.c:1212
ssize_t FullRead(int fd, char *ptr, size_t len)
Definition: file_lib.c:279
#define SYMLINK_MAX_DEPTH
Definition: file_lib.c:44
char * MapNameCopy(const char *s)
Definition: file_lib.c:446
NewLineMode FileNewLineMode(const char *file)
Definition: file_lib.c:327
Writer * FileReadFromFd(int fd, size_t max_size, bool *truncated)
Definition: file_lib.c:207
bool File_Copy(const char *src, const char *dst)
Definition: file_lib.c:100
void RestoreUmask(mode_t old_mask)
Definition: file_lib.c:502
bool IsAbsoluteFileName(const char *f)
Definition: file_lib.c:333
bool ExclusiveFileLockCheck(FileLock *lock)
Definition: file_lib.c:1664
bool FileSparseWrite(int fd, const void *buf, size_t count, bool *wrote_hole)
Definition: file_lib.c:1316
int SharedFileLockPath(FileLock *lock, const char *fpath, bool wait)
Definition: file_lib.c:1829
int SharedFileUnlock(FileLock *lock, bool close_fd)
Definition: file_lib.c:1710
FILE * safe_fopen(const char *const path, const char *const mode)
Definition: file_lib.c:812
static int safe_open_true_parent_dir(const char *path, int flags, uid_t link_user, gid_t link_group, bool traversed_link, int loop_countdown)
Definition: file_lib.c:945
static int UnlockFD(int fd)
Definition: file_lib.c:1629
StringSet * GlobFileList(const char *pattern)
Definition: file_lib.c:1533
int safe_open(const char *pathname, int flags)
Definition: file_lib.c:516
int safe_chown(const char *path, uid_t owner, gid_t group)
Definition: file_lib.c:1093
int safe_open_create_perms(const char *const pathname, int flags, const mode_t create_perms)
Definition: file_lib.c:541
int safe_creat(const char *pathname, mode_t mode)
Definition: file_lib.c:1203
#define BUFSIZE
char * MapName(char *s)
Definition: file_lib.c:441
#define IsFileSep(c)
Definition: file_lib.h:101
#define FILE_SEPARATOR_STR
Definition: file_lib.h:103
#define FILE_SEPARATOR
Definition: file_lib.h:102
#define FILE_ERROR_READ
Definition: file_lib.h:40
NewLineMode
Definition: file_lib.h:35
@ NewLineMode_Unix
Definition: file_lib.h:36
int fstatat(int dirfd, const char *pathname, struct stat *buf, int flags)
Definition: fstatat.c:60
ssize_t getline(char **lineptr, size_t *n, FILE *stream)
int errno
#define NULL
Definition: getopt1.c:56
char * getenv(char *name)
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
#define ProgrammingError(...)
Definition: misc_lib.h:33
int openat(int dirfd, const char *pathname, int flags,...)
Definition: openat.c:60
const char * Path_Basename(const char *path)
Returns the filename part of a string/path, similar to basename.
Definition: path.c:5
char * Path_JoinAlloc(const char *dir, const char *leaf)
Definition: path.c:28
int chown(const char *path, uid_t owner, gid_t group)
#define AT_FDCWD
Definition: platform.h:742
#define O_BINARY
Definition: platform.h:1001
int fchmod(int fd, mode_t mode)
#define SEEK_CUR
Definition: platform.h:880
int lstat(const char *file_name, struct stat *buf)
#define S_ISDIR(m)
Definition: platform.h:916
#define S_ISSOCK(m)
Definition: platform.h:931
#define S_ISFIFO(m)
Definition: platform.h:922
#define S_ISLNK(m)
Definition: platform.h:919
#define dirent
Definition: platform.h:160
#define O_TEXT
Definition: platform.h:1005
int fsync(int fd)
void globfree(glob_t *pglob)
int glob(const char *pattern, int flags, int(*errfunc)(const char *epath, int eerrno), glob_t *pglob)
int chmod(const char *path, mode_t mode)
#define MAX_FILENAME
Definition: platform.h:51
#define AT_SYMLINK_NOFOLLOW
Definition: platform.h:739
#define ENOLINK
Definition: platform.h:808
#define PATH_MAX
Definition: platform.h:176
int readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsize)
Definition: readlinkat.c:53
Seq * SeqNew(size_t initialCapacity, void(ItemDestroy)(void *item))
Definition: sequence.c:31
void SeqAppend(Seq *seq, void *item)
Append a new item to the Sequence.
Definition: sequence.c:104
StringSet * StringSetNew(void)
Definition: set.c:34
void StringSetAdd(const StringSet *set, char *element)
Definition: set.c:34
int seteuid(uid_t uid)
Definition: seteuid.c:28
char * strerror(int err)
Definition: strerror.c:35
bool StringEndsWith(const char *str, const char *suffix)
Check if a string ends with the given suffix.
Definition: string_lib.c:1330
void * memcchr(const void *buf, int c, size_t buf_size)
Definition: string_lib.c:1364
size_t StringCopy(const char *const from, char *const to, const size_t buf_size)
Copy a string from from to to (a buffer of at least buf_size)
Definition: string_lib.c:60
bool StringEndsWithCase(const char *str, const char *suffix, const bool case_fold)
Check if a string ends with the given suffix.
Definition: string_lib.c:1301
char * SearchAndReplace(const char *source, const char *search, const char *replace)
Definition: string_lib.c:313
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:34
char * strstr(const char *haystack, const char *needle)
Definition: strstr.c:35
Definition: unix_dir.c:33
Sequence data-structure.
Definition: sequence.h:50
Definition: set.h:138
Definition: writer.c:45
int fd
Definition: file_lib.h:201
size_t gl_pathc
Definition: platform.h:281
char ** gl_pathv
Definition: platform.h:282
size_t StringWriterLength(const Writer *writer)
Definition: writer.c:216
char * StringWriterClose(Writer *writer)
Definition: writer.c:262
size_t WriterWriteChar(Writer *writer, char c)
Definition: writer.c:200
size_t WriterWriteLen(Writer *writer, const char *str, size_t len)
Definition: writer.c:178
void WriterClose(Writer *writer)
Definition: writer.c:242
size_t WriterWriteF(Writer *writer, const char *fmt,...)
Definition: writer.c:144
Writer * StringWriter(void)
Definition: writer.c:67