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)  

pipes_unix.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 
25 #include <pipes.h>
26 
27 #include <mutex.h>
28 #include <global_mutex.h>
29 #include <exec_tools.h>
30 #include <rlist.h>
31 #include <policy.h>
32 #include <eval_context.h>
33 #include <file_lib.h>
34 #include <signals.h>
35 #include <string_lib.h>
36 
37 static bool CfSetuid(uid_t uid, gid_t gid);
38 
39 static int cf_pwait(pid_t pid);
40 
41 static pid_t *CHILDREN = NULL; /* GLOBAL_X */
42 static int MAX_FD = 2048; /* GLOBAL_X */ /* Max number of simultaneous pipes */
43 
44 
45 static void ChildrenFDInit()
46 {
48  if (CHILDREN == NULL) /* first time */
49  {
50  CHILDREN = xcalloc(MAX_FD, sizeof(pid_t));
51  }
52 
54 }
55 
56 /*****************************************************************************/
57 
58 /* This leaks memory and is not thread-safe! To be used only when you are
59  * about to exec() or _exit(), and only async-signal-safe code is allowed. */
60 static void ChildrenFDUnsafeClose()
61 {
62  /* GenericCreatePipeAndFork() must have been called to init this. */
63  assert(CHILDREN != NULL);
64 
65  for (int i = 0; i < MAX_FD; i++)
66  {
67  if (CHILDREN[i] > 0)
68  {
69  close(i);
70  }
71  }
72  CHILDREN = NULL; /* leaks on purpose */
73 }
74 
75 /* This is the original safe version, but not signal-handler-safe.
76  It's currently unused. */
77 #if 0
78 static void ChildrenFDClose()
79 {
81  int i;
82  for (i = 0; i < MAX_FD; i++)
83  {
84  if (CHILDREN[i] > 0)
85  {
86  close(i);
87  }
88  }
89  free(CHILDREN);
90  CHILDREN = NULL;
92 }
93 #endif
94 
95 /*****************************************************************************/
96 
97 static void ChildrenFDSet(int fd, pid_t pid)
98 {
99  int new_max = 0;
100 
101  if (fd >= MAX_FD)
102  {
104  "File descriptor %d of child %jd higher than MAX_FD, check for defunct children",
105  fd, (intmax_t) pid);
106  new_max = fd + 32;
107  }
108 
110 
111  if (new_max)
112  {
113  CHILDREN = xrealloc(CHILDREN, new_max * sizeof(pid_t));
114  MAX_FD = new_max;
115  }
116 
117  CHILDREN[fd] = pid;
119 }
120 
121 /*****************************************************************************/
122 
123 typedef struct
124 {
125  const char *type;
126  int pipe_desc[2];
127 } IOPipe;
128 
129 static pid_t GenericCreatePipeAndFork(IOPipe *pipes)
130 {
131  for (int i = 0; i < 2; i++)
132  {
133  if (pipes[i].type && !PipeTypeIsOk(pipes[i].type))
134  {
135  errno = EINVAL;
136  return -1;
137  }
138  }
139 
140  ChildrenFDInit();
141 
142  /* Create pair of descriptors to this process. */
143  if (pipes[0].type && pipe(pipes[0].pipe_desc) < 0)
144  {
145  return -1;
146  }
147 
148  /* Create second pair of descriptors (if exists) to this process.
149  * This will allow full I/O operations. */
150  if (pipes[1].type && pipe(pipes[1].pipe_desc) < 0)
151  {
152  close(pipes[0].pipe_desc[0]);
153  close(pipes[0].pipe_desc[1]);
154  return -1;
155  }
156 
157  pid_t pid = -1;
158 
159  if ((pid = fork()) == (pid_t) -1)
160  {
161  /* One pipe will be always here. */
162  close(pipes[0].pipe_desc[0]);
163  close(pipes[0].pipe_desc[1]);
164 
165  /* Second pipe is optional so we have to check existence. */
166  if (pipes[1].type)
167  {
168  close(pipes[1].pipe_desc[0]);
169  close(pipes[1].pipe_desc[1]);
170  }
171  return -1;
172  }
173 
174  /* Ignore SIGCHLD, by setting the handler to SIG_DFL. NOTE: this is
175  * different than setting to SIG_IGN. In the latter case no zombies are
176  * generated ever and you can't wait() for the child to finish. */
177  struct sigaction sa = {
178  .sa_handler = SIG_DFL,
179  };
180  sigemptyset(&sa.sa_mask);
181  sigaction(SIGCHLD, &sa, NULL);
182 
183  if (pid == 0) /* child */
184  {
185  /* WARNING only call async-signal-safe functions in child. */
186 
187  /* The fork()ed child is always single-threaded, but we are only
188  * allowed to call async-signal-safe functions (man 3p fork). */
189 
190  // Redmine #2971: reset SIGPIPE signal handler in the child to have a
191  // sane behavior of piped commands within child
192  signal(SIGPIPE, SIG_DFL);
193 
194  /* The child should always accept all signals after it has exec'd,
195  * else the child might be unkillable! (happened in ENT-3147). */
196  sigset_t sigmask;
197  sigemptyset(&sigmask);
198  sigprocmask(SIG_SETMASK, &sigmask, NULL);
199  }
200 
201  ALARM_PID = (pid != 0 ? pid : -1);
202 
203  return pid;
204 }
205 
206 /*****************************************************************************/
207 
208 static pid_t CreatePipeAndFork(const char *type, int *pd)
209 {
210  IOPipe pipes[2];
211  pipes[0].type = type;
212  pipes[1].type = NULL; /* We don't want to create this one. */
213 
214  pid_t pid = GenericCreatePipeAndFork(pipes);
215 
216  pd[0] = pipes[0].pipe_desc[0];
217  pd[1] = pipes[0].pipe_desc[1];
218 
219  return pid;
220 }
221 
222 /*****************************************************************************/
223 
224 static pid_t CreatePipesAndFork(const char *type, int *pd, int *pdb)
225 {
226  IOPipe pipes[2];
227  /* Both pipes MUST have the same type. */
228  pipes[0].type = type;
229  pipes[1].type = type;
230 
231  pid_t pid = GenericCreatePipeAndFork(pipes);
232 
233  pd[0] = pipes[0].pipe_desc[0];
234  pd[1] = pipes[0].pipe_desc[1];
235  pdb[0] = pipes[1].pipe_desc[0];
236  pdb[1] = pipes[1].pipe_desc[1];
237  return pid;
238 }
239 
240 /*****************************************************************************/
241 
242 IOData cf_popen_full_duplex(const char *command, bool capture_stderr, bool require_full_path)
243 {
244  /* For simplifying reading and writing directions */
245  const int READ=0, WRITE=1;
246  int child_pipe[2]; /* From child to parent */
247  int parent_pipe[2]; /* From parent to child */
248  pid_t pid;
249 
250  char **argv = ArgSplitCommand(command);
251 
252  fflush(NULL); /* Empty file buffers */
253  pid = CreatePipesAndFork("r+t", child_pipe, parent_pipe);
254 
255  if (pid == (pid_t) -1)
256  {
257  Log(LOG_LEVEL_ERR, "Couldn't fork child process: %s", GetErrorStr());
258  ArgFree(argv);
259  return (IOData) {-1, -1};
260  }
261 
262  else if (pid > 0) // parent
263  {
264  close(child_pipe[WRITE]);
265  close(parent_pipe[READ]);
266 
267  IOData io_desc;
268  io_desc.write_fd = parent_pipe[WRITE];
269  io_desc.read_fd = child_pipe[READ];
270 
271  ChildrenFDSet(parent_pipe[WRITE], pid);
272  ChildrenFDSet(child_pipe[READ], pid);
273  ArgFree(argv);
274  return io_desc;
275  }
276  else // child
277  {
278  close(child_pipe[READ]);
279  close(parent_pipe[WRITE]);
280 
281  /* Open stdin from parant process and stdout from child */
282  if (dup2(parent_pipe[READ], 0) == -1 || dup2(child_pipe[WRITE],1) == -1)
283  {
284  Log(LOG_LEVEL_ERR, "Can not execute dup2: %s", GetErrorStr());
285  _exit(EXIT_FAILURE);
286  }
287 
288  if (capture_stderr)
289  {
290  /* Merge stdout/stderr */
291  if(dup2(child_pipe[WRITE], 2) == -1)
292  {
293  Log(LOG_LEVEL_ERR, "Can not execute dup2 for merging stderr: %s",
294  GetErrorStr());
295  _exit(EXIT_FAILURE);
296  }
297  }
298  else
299  {
300  /* leave stderr open */
301  }
302 
303  close(child_pipe[WRITE]);
304  close(parent_pipe[READ]);
305 
307 
308  int res;
309  if (require_full_path)
310  {
311  res = execv(argv[0], argv);
312  }
313  else
314  {
315  res = execvp(argv[0], argv);
316  }
317 
318  if (res == -1)
319  {
320  /* NOTE: exec functions return only when error have occurred. */
321  Log(LOG_LEVEL_ERR, "Couldn't run '%s'. (%s: %s)",
322  argv[0],
323  require_full_path ? "execv" : "execvp",
324  GetErrorStr());
325  }
326 
327  /* We shouldn't reach this point */
328  _exit(EXIT_FAILURE);
329  }
330 }
331 
332 FILE *cf_popen(const char *command, const char *type, bool capture_stderr)
333 {
334  int pd[2];
335  pid_t pid;
336  FILE *pp = NULL;
337 
338  char **argv = ArgSplitCommand(command);
339 
340  pid = CreatePipeAndFork(type, pd);
341  if (pid == (pid_t) -1)
342  {
343  ArgFree(argv);
344  return NULL;
345  }
346 
347  if (pid == 0) /* child */
348  {
349  /* WARNING only call async-signal-safe functions in child. */
350 
351  switch (*type)
352  {
353  case 'r':
354 
355  close(pd[0]); /* Don't need output from parent */
356 
357  if (pd[1] != 1)
358  {
359  dup2(pd[1], 1); /* Attach pp=pd[1] to our stdout */
360 
361  if (capture_stderr)
362  {
363  dup2(pd[1], 2); /* Merge stdout/stderr */
364  }
365  else
366  {
367  int nullfd = open(NULLFILE, O_WRONLY);
368  dup2(nullfd, 2);
369  close(nullfd);
370  }
371 
372  close(pd[1]);
373  }
374 
375  break;
376 
377  case 'w':
378 
379  close(pd[1]);
380 
381  if (pd[0] != 0)
382  {
383  dup2(pd[0], 0);
384  close(pd[0]);
385  }
386  }
387 
389 
390  if (execv(argv[0], argv) == -1)
391  {
392  Log(LOG_LEVEL_ERR, "Couldn't run '%s'. (execv: %s)", argv[0], GetErrorStr());
393  }
394 
395  _exit(EXIT_FAILURE);
396  }
397  else /* parent */
398  {
399  switch (*type)
400  {
401  case 'r':
402 
403  close(pd[1]);
404 
405  if ((pp = fdopen(pd[0], type)) == NULL)
406  {
407  cf_pwait(pid);
408  ArgFree(argv);
409  return NULL;
410  }
411  break;
412 
413  case 'w':
414 
415  close(pd[0]);
416 
417  if ((pp = fdopen(pd[1], type)) == NULL)
418  {
419  cf_pwait(pid);
420  ArgFree(argv);
421  return NULL;
422  }
423  }
424 
425  ChildrenFDSet(fileno(pp), pid);
426  ArgFree(argv);
427  return pp;
428  }
429 
430  ProgrammingError("Unreachable code");
431  return NULL;
432 }
433 
434 /*****************************************************************************/
435 
436 /*
437  * WARNING: this is only allowed to be called from single-threaded code,
438  * because of the safe_chdir() call in the forked child.
439  */
440 FILE *cf_popensetuid(const char *command, const char *type,
441  uid_t uid, gid_t gid, char *chdirv, char *chrootv,
442  ARG_UNUSED int background)
443 {
444  int pd[2];
445  pid_t pid;
446  FILE *pp = NULL;
447 
448  char **argv = ArgSplitCommand(command);
449 
450  pid = CreatePipeAndFork(type, pd);
451  if (pid == (pid_t) -1)
452  {
453  ArgFree(argv);
454  return NULL;
455  }
456 
457  if (pid == 0) /* child */
458  {
459  /* WARNING only call async-signal-safe functions in child. */
460 
461  switch (*type)
462  {
463  case 'r':
464 
465  close(pd[0]); /* Don't need output from parent */
466 
467  if (pd[1] != 1)
468  {
469  dup2(pd[1], 1); /* Attach pp=pd[1] to our stdout */
470  dup2(pd[1], 2); /* Merge stdout/stderr */
471  close(pd[1]);
472  }
473 
474  break;
475 
476  case 'w':
477 
478  close(pd[1]);
479 
480  if (pd[0] != 0)
481  {
482  dup2(pd[0], 0);
483  close(pd[0]);
484  }
485  }
486 
488 
489  if (chrootv && (strlen(chrootv) != 0))
490  {
491  if (chroot(chrootv) == -1)
492  {
493  Log(LOG_LEVEL_ERR, "Couldn't chroot to '%s'. (chroot: %s)", chrootv, GetErrorStr());
494  _exit(EXIT_FAILURE);
495  }
496  }
497 
498  if (chdirv && (strlen(chdirv) != 0))
499  {
500  if (safe_chdir(chdirv) == -1)
501  {
502  Log(LOG_LEVEL_ERR, "Couldn't chdir to '%s'. (chdir: %s)", chdirv, GetErrorStr());
503  _exit(EXIT_FAILURE);
504  }
505  }
506 
507  if (!CfSetuid(uid, gid))
508  {
509  _exit(EXIT_FAILURE);
510  }
511 
512  if (execv(argv[0], argv) == -1)
513  {
514  Log(LOG_LEVEL_ERR, "Couldn't run '%s'. (execv: %s)", argv[0], GetErrorStr());
515  }
516 
517  _exit(EXIT_FAILURE);
518  }
519  else /* parent */
520  {
521  switch (*type)
522  {
523  case 'r':
524 
525  close(pd[1]);
526 
527  if ((pp = fdopen(pd[0], type)) == NULL)
528  {
529  cf_pwait(pid);
530  ArgFree(argv);
531  return NULL;
532  }
533  break;
534 
535  case 'w':
536 
537  close(pd[0]);
538 
539  if ((pp = fdopen(pd[1], type)) == NULL)
540  {
541  cf_pwait(pid);
542  ArgFree(argv);
543  return NULL;
544  }
545  }
546 
547  ChildrenFDSet(fileno(pp), pid);
548  ArgFree(argv);
549  return pp;
550  }
551 
552  ProgrammingError("Unreachable code");
553  return NULL;
554 }
555 
556 /*****************************************************************************/
557 /* Shell versions of commands - not recommended for security reasons */
558 /*****************************************************************************/
559 
560 FILE *cf_popen_sh(const char *command, const char *type)
561 {
562  int pd[2];
563  pid_t pid;
564  FILE *pp = NULL;
565 
566  pid = CreatePipeAndFork(type, pd);
567  if (pid == (pid_t) -1)
568  {
569  return NULL;
570  }
571 
572  if (pid == 0) /* child */
573  {
574  /* WARNING only call async-signal-safe functions in child. */
575 
576  switch (*type)
577  {
578  case 'r':
579 
580  close(pd[0]); /* Don't need output from parent */
581 
582  if (pd[1] != 1)
583  {
584  dup2(pd[1], 1); /* Attach pp=pd[1] to our stdout */
585  dup2(pd[1], 2); /* Merge stdout/stderr */
586  close(pd[1]);
587  }
588 
589  break;
590 
591  case 'w':
592 
593  close(pd[1]);
594 
595  if (pd[0] != 0)
596  {
597  dup2(pd[0], 0);
598  close(pd[0]);
599  }
600  }
601 
603 
604  execl(SHELL_PATH, "sh", "-c", command, NULL);
605 
606  Log(LOG_LEVEL_ERR, "Couldn't run: '%s' (execl: %s)", command, GetErrorStr());
607  _exit(EXIT_FAILURE);
608  }
609  else /* parent */
610  {
611  switch (*type)
612  {
613  case 'r':
614 
615  close(pd[1]);
616 
617  if ((pp = fdopen(pd[0], type)) == NULL)
618  {
619  cf_pwait(pid);
620  return NULL;
621  }
622  break;
623 
624  case 'w':
625 
626  close(pd[0]);
627 
628  if ((pp = fdopen(pd[1], type)) == NULL)
629  {
630  cf_pwait(pid);
631  return NULL;
632  }
633  }
634 
635  ChildrenFDSet(fileno(pp), pid);
636  return pp;
637  }
638 
639  ProgrammingError("Unreachable code");
640  return NULL;
641 }
642 
643 /******************************************************************************/
644 
645 /*
646  * WARNING: this is only allowed to be called from single-threaded code,
647  * because of the safe_chdir() call in the forked child.
648  */
649 FILE *cf_popen_shsetuid(const char *command, const char *type,
650  uid_t uid, gid_t gid, char *chdirv, char *chrootv,
651  ARG_UNUSED int background)
652 {
653  int pd[2];
654  pid_t pid;
655  FILE *pp = NULL;
656 
657  pid = CreatePipeAndFork(type, pd);
658  if (pid == (pid_t) -1)
659  {
660  return NULL;
661  }
662 
663  if (pid == 0) /* child */
664  {
665  /* WARNING only call async-signal-safe functions in child. */
666 
667  switch (*type)
668  {
669  case 'r':
670 
671  close(pd[0]); /* Don't need output from parent */
672 
673  if (pd[1] != 1)
674  {
675  dup2(pd[1], 1); /* Attach pp=pd[1] to our stdout */
676  dup2(pd[1], 2); /* Merge stdout/stderr */
677  close(pd[1]);
678  }
679 
680  break;
681 
682  case 'w':
683 
684  close(pd[1]);
685 
686  if (pd[0] != 0)
687  {
688  dup2(pd[0], 0);
689  close(pd[0]);
690  }
691  }
692 
694 
695  if (chrootv && (strlen(chrootv) != 0))
696  {
697  if (chroot(chrootv) == -1)
698  {
699  Log(LOG_LEVEL_ERR, "Couldn't chroot to '%s'. (chroot: %s)", chrootv, GetErrorStr());
700  _exit(EXIT_FAILURE);
701  }
702  }
703 
704  if (chdirv && (strlen(chdirv) != 0))
705  {
706  if (safe_chdir(chdirv) == -1)
707  {
708  Log(LOG_LEVEL_ERR, "Couldn't chdir to '%s'. (chdir: %s)", chdirv, GetErrorStr());
709  _exit(EXIT_FAILURE);
710  }
711  }
712 
713  if (!CfSetuid(uid, gid))
714  {
715  _exit(EXIT_FAILURE);
716  }
717 
718  execl(SHELL_PATH, "sh", "-c", command, NULL);
719 
720  Log(LOG_LEVEL_ERR, "Couldn't run: '%s' (execl: %s)", command, GetErrorStr());
721  _exit(EXIT_FAILURE);
722  }
723  else /* parent */
724  {
725  switch (*type)
726  {
727  case 'r':
728 
729  close(pd[1]);
730 
731  if ((pp = fdopen(pd[0], type)) == NULL)
732  {
733  cf_pwait(pid);
734  return NULL;
735  }
736  break;
737 
738  case 'w':
739 
740  close(pd[0]);
741 
742  if ((pp = fdopen(pd[1], type)) == NULL)
743  {
744  cf_pwait(pid);
745  return NULL;
746  }
747  }
748 
749  ChildrenFDSet(fileno(pp), pid);
750  return pp;
751  }
752 
753  ProgrammingError("Unreachable code");
754  return NULL;
755 }
756 
757 static int cf_pwait(pid_t pid)
758 {
760  "cf_pwait - waiting for process %jd", (intmax_t) pid);
761 
762  int status;
763  while (waitpid(pid, &status, 0) < 0)
764  {
765  if (errno != EINTR)
766  {
768  "Waiting for child PID %jd failed (waitpid: %s)",
769  (intmax_t) pid, GetErrorStr());
770  return -1;
771  }
772  }
773 
774  if (!WIFEXITED(status))
775  {
777  "Child PID %jd exited abnormally (%s)", (intmax_t) pid,
778  WIFSIGNALED(status) ? "signalled" : (
779  WIFSTOPPED(status) ? "stopped" : (
780  WIFCONTINUED(status) ? "continued" : "unknown" )));
781  return -1;
782  }
783 
784  int retcode = WEXITSTATUS(status);
785 
786  Log(LOG_LEVEL_DEBUG, "cf_pwait - process %jd exited with code: %d",
787  (intmax_t) pid, retcode);
788  return retcode;
789 }
790 
791 /*******************************************************************/
792 
793 /**
794  * Closes the pipe without waiting the child.
795  *
796  * @param pp pipe to the child process
797  */
798 void cf_pclose_nowait(FILE *pp)
799 {
800  if (fclose(pp) == EOF)
801  {
803  "Could not close the pipe to the executed subcommand (fclose: %s)",
804  GetErrorStr());
805  }
806 }
807 
808 /**
809  * Closes the pipe and wait()s for PID of the child,
810  * in order to reap the zombies.
811  */
812 int cf_pclose(FILE *pp)
813 {
814  int fd = fileno(pp);
815  pid_t pid;
816 
818 
819  if (CHILDREN == NULL) /* popen hasn't been called */
820  {
822  fclose(pp);
823  return -1;
824  }
825 
826  ALARM_PID = -1;
827 
828  if (fd >= MAX_FD)
829  {
832  "File descriptor %d of child higher than MAX_FD in cf_pclose!",
833  fd);
834  fclose(pp);
835  return -1;
836  }
837 
838  pid = CHILDREN[fd];
839  CHILDREN[fd] = 0;
841 
842  if (fclose(pp) == EOF)
843  {
845  "Could not close the pipe to the executed subcommand (fclose: %s)",
846  GetErrorStr());
847  }
848 
849  return cf_pwait(pid);
850 }
851 
853 {
855 
856  if (CHILDREN == NULL) /* popen hasn't been called */
857  {
859  close(fd);
860  return -1;
861  }
862 
863  if (fd >= MAX_FD)
864  {
867  "File descriptor %d of child higher than MAX_FD in cf_pclose_full_duplex_side!",
868  fd);
869  }
870  else
871  {
872  CHILDREN[fd] = 0;
874  }
875  return close(fd);
876 }
877 
878 
879 /* We are assuming that read_fd part will be always open at this point. */
881 {
883 
884  if (CHILDREN == NULL)
885  {
887  if (data->read_fd >= 0)
888  {
889  close(data->read_fd);
890  }
891 
892  if (data->write_fd >= 0)
893  {
894  close(data->write_fd);
895  }
896  return -1;
897  }
898 
899  ALARM_PID = -1;
900  pid_t pid = 0;
901 
902  /* Safe as pipes[1] is -1 if not initialized */
903  if (data->read_fd >= MAX_FD || data->write_fd >= MAX_FD)
904  {
907  "File descriptor %d of child higher than MAX_FD in cf_pclose!",
908  data->read_fd > data->write_fd ? data->read_fd : data->write_fd);
909  }
910  else
911  {
912  pid = CHILDREN[data->read_fd];
913  if (data->write_fd >= 0)
914  {
915  assert(pid == CHILDREN[data->write_fd]);
916  CHILDREN[data->write_fd] = 0;
917  }
918  CHILDREN[data->read_fd] = 0;
920  }
921 
922  if (close(data->read_fd) != 0 || (data->write_fd >= 0 && close(data->write_fd) != 0) || pid == 0)
923  {
924  return -1;
925  }
926 
927  return cf_pwait(pid);
928 }
929 
930 bool PipeToPid(pid_t *pid, FILE *pp)
931 {
932  int fd = fileno(pp);
934 
935  if (CHILDREN == NULL) /* popen hasn't been called */
936  {
938  return false;
939  }
940 
941  *pid = CHILDREN[fd];
943 
944  return true;
945 }
946 
947 /*******************************************************************/
948 
949 static bool CfSetuid(uid_t uid, gid_t gid)
950 {
951  struct passwd *pw;
952 
953  if (gid != (gid_t) - 1)
954  {
955  Log(LOG_LEVEL_VERBOSE, "Changing gid to %ju", (uintmax_t)gid);
956 
957  if (setgid(gid) == -1)
958  {
959  Log(LOG_LEVEL_ERR, "Couldn't set gid to '%ju'. (setgid: %s)", (uintmax_t)gid, GetErrorStr());
960  return false;
961  }
962 
963  /* Now eliminate any residual privileged groups */
964 
965  if ((pw = getpwuid(uid)) == NULL)
966  {
967  Log(LOG_LEVEL_ERR, "Unable to get login groups when dropping privilege to '%ju'. (getpwuid: %s)", (uintmax_t)uid, GetErrorStr());
968  return false;
969  }
970 
971  if (initgroups(pw->pw_name, pw->pw_gid) == -1)
972  {
973  Log(LOG_LEVEL_ERR, "Unable to set login groups when dropping privilege to '%s=%ju'. (initgroups: %s)", pw->pw_name,
974  (uintmax_t)uid, GetErrorStr());
975  return false;
976  }
977  }
978 
979  if (uid != (uid_t) - 1)
980  {
981  Log(LOG_LEVEL_VERBOSE, "Changing uid to '%ju'", (uintmax_t)uid);
982 
983  if (setuid(uid) == -1)
984  {
985  Log(LOG_LEVEL_ERR, "Couldn't set uid to '%ju'. (setuid: %s)", (uintmax_t)uid, GetErrorStr());
986  return false;
987  }
988  }
989 
990  return true;
991 }
992 
993 /* For Windows we need a different method because select() does not */
994 /* work with non-socket file descriptors. */
995 int PipeIsReadWriteReady(const IOData *io, int timeout_sec)
996 {
997  fd_set rset;
998  FD_ZERO(&rset);
999  FD_SET(io->read_fd, &rset);
1000 
1001  struct timeval tv = {
1002  .tv_sec = timeout_sec,
1003  .tv_usec = 0,
1004  };
1005 
1007  "PipeIsReadWriteReady: wait max %ds for data on fd %d",
1008  timeout_sec, io->read_fd);
1009 
1010  int ret = select(io->read_fd + 1, &rset, NULL, NULL, &tv);
1011 
1012  if (ret < 0)
1013  {
1014  Log(LOG_LEVEL_VERBOSE, "Failed checking for data (select: %s)",
1015  GetErrorStr());
1016  return -1;
1017  }
1018  else if (FD_ISSET(io->read_fd, &rset))
1019  {
1020  return io->read_fd;
1021  }
1022  else if (ret == 0)
1023  {
1024  /* timeout_sec has elapsed but no data was available. */
1025  return 0;
1026  }
1027  else
1028  {
1029  UnexpectedError("select() returned > 0 but our only fd is not set!");
1030  return -1;
1031  }
1032 }
void * xcalloc(size_t nmemb, size_t size)
Definition: alloc-mini.c:51
void * xrealloc(void *ptr, size_t size)
Definition: alloc.c:51
#define ARG_UNUSED
Definition: cf-net.c:47
#define NULLFILE
Definition: cf3.defs.h:281
pid_t ALARM_PID
Definition: cf3globals.c:112
void free(void *)
char ** ArgSplitCommand(const char *comm)
Definition: exec_tools.c:256
void ArgFree(char **args)
Definition: exec_tools.c:329
int safe_chdir(const char *path)
Definition: file_lib.c:903
int errno
#define NULL
Definition: getopt1.c:56
pthread_mutex_t * cft_count
Definition: global_mutex.c:38
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
#define ProgrammingError(...)
Definition: misc_lib.h:33
#define UnexpectedError(...)
Definition: misc_lib.h:38
#define ThreadUnlock(m)
Definition: mutex.h:33
#define ThreadLock(m)
Definition: mutex.h:32
bool PipeTypeIsOk(const char *type)
Definition: pipes.c:31
FILE * cf_popensetuid(const char *command, const char *type, uid_t uid, gid_t gid, char *chdirv, char *chrootv, int background)
Definition: pipes_unix.c:440
static pid_t CreatePipeAndFork(const char *type, int *pd)
Definition: pipes_unix.c:208
static int MAX_FD
Definition: pipes_unix.c:42
int cf_pclose(FILE *pp)
Definition: pipes_unix.c:812
static void ChildrenFDSet(int fd, pid_t pid)
Definition: pipes_unix.c:97
static void ChildrenFDUnsafeClose()
Definition: pipes_unix.c:60
static bool CfSetuid(uid_t uid, gid_t gid)
Definition: pipes_unix.c:949
static pid_t * CHILDREN
Definition: pipes_unix.c:41
static pid_t CreatePipesAndFork(const char *type, int *pd, int *pdb)
Definition: pipes_unix.c:224
FILE * cf_popen_shsetuid(const char *command, const char *type, uid_t uid, gid_t gid, char *chdirv, char *chrootv, int background)
Definition: pipes_unix.c:649
int cf_pclose_full_duplex_side(int fd)
Definition: pipes_unix.c:852
IOData cf_popen_full_duplex(const char *command, bool capture_stderr, bool require_full_path)
Definition: pipes_unix.c:242
static pid_t GenericCreatePipeAndFork(IOPipe *pipes)
Definition: pipes_unix.c:129
void cf_pclose_nowait(FILE *pp)
Definition: pipes_unix.c:798
int PipeIsReadWriteReady(const IOData *io, int timeout_sec)
Definition: pipes_unix.c:995
int cf_pclose_full_duplex(IOData *data)
Definition: pipes_unix.c:880
static int cf_pwait(pid_t pid)
Definition: pipes_unix.c:757
FILE * cf_popen(const char *command, const char *type, bool capture_stderr)
Definition: pipes_unix.c:332
FILE * cf_popen_sh(const char *command, const char *type)
Definition: pipes_unix.c:560
static void ChildrenFDInit()
Definition: pipes_unix.c:45
bool PipeToPid(pid_t *pid, FILE *pp)
Definition: pipes_unix.c:930
#define WEXITSTATUS(s)
Definition: platform.h:141
#define WIFSIGNALED(s)
Definition: platform.h:147
#define WIFEXITED(s)
Definition: platform.h:144
Definition: pipes.h:31
int read_fd
Definition: pipes.h:33
int write_fd
Definition: pipes.h:32
const char * type
Definition: pipes_unix.c:125
int pipe_desc[2]
Definition: pipes_unix.c:126