1 /*
2 Copyright 2021 Northern.tech AS
3
4 This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; version 3.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18
19 To the extent this program is licensed as part of the Enterprise
20 versions of CFEngine, the applicable Commercial Open Source License
21 (COSL) may apply to this file if you as a licensee so wish it. See
22 included file COSL.txt.
23 */
24
25 #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
ChildrenFDInit()45 static void ChildrenFDInit()
46 {
47 ThreadLock(cft_count);
48 if (CHILDREN == NULL) /* first time */
49 {
50 CHILDREN = xcalloc(MAX_FD, sizeof(pid_t));
51 }
52
53 ThreadUnlock(cft_count);
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. */
ChildrenFDUnsafeClose()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 {
80 ThreadLock(cft_count);
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;
91 ThreadUnlock(cft_count);
92 }
93 #endif
94
ChildOutputSelectDupClose(int pd[2],OutputSelect output_select)95 static void ChildOutputSelectDupClose(int pd[2], OutputSelect output_select)
96 {
97 close(pd[0]); // Don't need output from parent
98
99 if (pd[1] != 1) // TODO: When is pd[1] == 1 ???
100 {
101 if ((output_select == OUTPUT_SELECT_BOTH)
102 || (output_select == OUTPUT_SELECT_STDOUT))
103 {
104 // close our(child) stdout(1) and open (pd[1]) as stdout
105 dup2(pd[1], 1);
106 // Subsequent stdout output will go to parent (pd[1])
107 }
108 else
109 {
110 // Close / discard stdout
111 int nullfd = open(NULLFILE, O_WRONLY);
112 dup2(nullfd, 1);
113 close(nullfd);
114 }
115
116 if ((output_select == OUTPUT_SELECT_BOTH)
117 || (output_select == OUTPUT_SELECT_STDERR))
118 {
119 // close our(child) stderr(2) and open (pd[1]) as stderr
120 dup2(pd[1], 2);
121 // Subsequent stderr output will go to parent (pd[1])
122 }
123 else
124 {
125 // Close / discard stderr
126 int nullfd = open(NULLFILE, O_WRONLY);
127 dup2(nullfd, 2);
128 close(nullfd);
129 }
130
131 close(pd[1]);
132 }
133 }
134
135 /*****************************************************************************/
136
ChildrenFDSet(int fd,pid_t pid)137 static void ChildrenFDSet(int fd, pid_t pid)
138 {
139 int new_max = 0;
140
141 if (fd >= MAX_FD)
142 {
143 Log(LOG_LEVEL_WARNING,
144 "File descriptor %d of child %jd higher than MAX_FD, check for defunct children",
145 fd, (intmax_t) pid);
146 new_max = fd + 32;
147 }
148
149 ThreadLock(cft_count);
150
151 if (new_max)
152 {
153 CHILDREN = xrealloc(CHILDREN, new_max * sizeof(pid_t));
154 MAX_FD = new_max;
155 }
156
157 CHILDREN[fd] = pid;
158 ThreadUnlock(cft_count);
159 }
160
161 /*****************************************************************************/
162
163 typedef struct
164 {
165 const char *type;
166 int pipe_desc[2];
167 } IOPipe;
168
GenericCreatePipeAndFork(IOPipe * pipes)169 static pid_t GenericCreatePipeAndFork(IOPipe *pipes)
170 {
171 for (int i = 0; i < 2; i++)
172 {
173 if (pipes[i].type && !PipeTypeIsOk(pipes[i].type))
174 {
175 errno = EINVAL;
176 return -1;
177 }
178 }
179
180 ChildrenFDInit();
181
182 /* Create pair of descriptors to this process. */
183 if (pipes[0].type && pipe(pipes[0].pipe_desc) < 0)
184 {
185 return -1;
186 }
187
188 /* Create second pair of descriptors (if exists) to this process.
189 * This will allow full I/O operations. */
190 if (pipes[1].type && pipe(pipes[1].pipe_desc) < 0)
191 {
192 close(pipes[0].pipe_desc[0]);
193 close(pipes[0].pipe_desc[1]);
194 return -1;
195 }
196
197 pid_t pid = -1;
198
199 if ((pid = fork()) == (pid_t) -1)
200 {
201 /* One pipe will be always here. */
202 close(pipes[0].pipe_desc[0]);
203 close(pipes[0].pipe_desc[1]);
204
205 /* Second pipe is optional so we have to check existence. */
206 if (pipes[1].type)
207 {
208 close(pipes[1].pipe_desc[0]);
209 close(pipes[1].pipe_desc[1]);
210 }
211 return -1;
212 }
213
214 /* Ignore SIGCHLD, by setting the handler to SIG_DFL. NOTE: this is
215 * different than setting to SIG_IGN. In the latter case no zombies are
216 * generated ever and you can't wait() for the child to finish. */
217 struct sigaction sa = {
218 .sa_handler = SIG_DFL,
219 };
220 sigemptyset(&sa.sa_mask);
221 sigaction(SIGCHLD, &sa, NULL);
222
223 if (pid == 0) /* child */
224 {
225 /* WARNING only call async-signal-safe functions in child. */
226
227 /* The fork()ed child is always single-threaded, but we are only
228 * allowed to call async-signal-safe functions (man 3p fork). */
229
230 // Redmine #2971: reset SIGPIPE signal handler in the child to have a
231 // sane behavior of piped commands within child
232 signal(SIGPIPE, SIG_DFL);
233
234 /* The child should always accept all signals after it has exec'd,
235 * else the child might be unkillable! (happened in ENT-3147). */
236 sigset_t sigmask;
237 sigemptyset(&sigmask);
238 sigprocmask(SIG_SETMASK, &sigmask, NULL);
239 }
240
241 ALARM_PID = (pid != 0 ? pid : -1);
242
243 return pid;
244 }
245
246 /*****************************************************************************/
247
CreatePipeAndFork(const char * type,int * pd)248 static pid_t CreatePipeAndFork(const char *type, int *pd)
249 {
250 IOPipe pipes[2];
251 pipes[0].type = type;
252 pipes[1].type = NULL; /* We don't want to create this one. */
253
254 pid_t pid = GenericCreatePipeAndFork(pipes);
255
256 pd[0] = pipes[0].pipe_desc[0];
257 pd[1] = pipes[0].pipe_desc[1];
258
259 return pid;
260 }
261
262 /*****************************************************************************/
263
CreatePipesAndFork(const char * type,int * pd,int * pdb)264 static pid_t CreatePipesAndFork(const char *type, int *pd, int *pdb)
265 {
266 IOPipe pipes[2];
267 /* Both pipes MUST have the same type. */
268 pipes[0].type = type;
269 pipes[1].type = type;
270
271 pid_t pid = GenericCreatePipeAndFork(pipes);
272
273 pd[0] = pipes[0].pipe_desc[0];
274 pd[1] = pipes[0].pipe_desc[1];
275 pdb[0] = pipes[1].pipe_desc[0];
276 pdb[1] = pipes[1].pipe_desc[1];
277 return pid;
278 }
279
280 /*****************************************************************************/
281
cf_popen_full_duplex(const char * command,bool capture_stderr,bool require_full_path)282 IOData cf_popen_full_duplex(const char *command, bool capture_stderr, bool require_full_path)
283 {
284 /* For simplifying reading and writing directions */
285 const int READ=0, WRITE=1;
286 int child_pipe[2]; /* From child to parent */
287 int parent_pipe[2]; /* From parent to child */
288 pid_t pid;
289
290 char **argv = ArgSplitCommand(command);
291
292 fflush(NULL); /* Empty file buffers */
293 pid = CreatePipesAndFork("r+t", child_pipe, parent_pipe);
294
295 if (pid == (pid_t) -1)
296 {
297 Log(LOG_LEVEL_ERR, "Couldn't fork child process: %s", GetErrorStr());
298 ArgFree(argv);
299 return (IOData) {-1, -1, NULL, NULL};
300 }
301
302 else if (pid > 0) // parent
303 {
304 close(child_pipe[WRITE]);
305 close(parent_pipe[READ]);
306
307 IOData io_desc;
308 io_desc.write_fd = parent_pipe[WRITE];
309 io_desc.read_fd = child_pipe[READ];
310 io_desc.read_stream = NULL;
311 io_desc.write_stream = NULL;
312
313 ChildrenFDSet(parent_pipe[WRITE], pid);
314 ChildrenFDSet(child_pipe[READ], pid);
315 ArgFree(argv);
316 return io_desc;
317 }
318 else // child
319 {
320 close(child_pipe[READ]);
321 close(parent_pipe[WRITE]);
322
323 /* Open stdin from parant process and stdout from child */
324 if (dup2(parent_pipe[READ], 0) == -1 || dup2(child_pipe[WRITE],1) == -1)
325 {
326 Log(LOG_LEVEL_ERR, "Can not execute dup2: %s", GetErrorStr());
327 _exit(EXIT_FAILURE);
328 }
329
330 if (capture_stderr)
331 {
332 /* Merge stdout/stderr */
333 if(dup2(child_pipe[WRITE], 2) == -1)
334 {
335 Log(LOG_LEVEL_ERR, "Can not execute dup2 for merging stderr: %s",
336 GetErrorStr());
337 _exit(EXIT_FAILURE);
338 }
339 }
340 else
341 {
342 /* leave stderr open */
343 }
344
345 close(child_pipe[WRITE]);
346 close(parent_pipe[READ]);
347
348 ChildrenFDUnsafeClose();
349
350 int res;
351 if (require_full_path)
352 {
353 res = execv(argv[0], argv);
354 }
355 else
356 {
357 res = execvp(argv[0], argv);
358 }
359
360 if (res == -1)
361 {
362 /* NOTE: exec functions return only when error have occurred. */
363 Log(LOG_LEVEL_ERR, "Couldn't run '%s'. (%s: %s)",
364 argv[0],
365 require_full_path ? "execv" : "execvp",
366 GetErrorStr());
367 }
368
369 /* We shouldn't reach this point */
370 _exit(EXIT_FAILURE);
371 }
372 }
373
cf_popen_select(const char * command,const char * type,OutputSelect output_select)374 FILE *cf_popen_select(const char *command, const char *type, OutputSelect output_select)
375 {
376 int pd[2];
377 pid_t pid;
378 FILE *pp = NULL;
379
380 char **argv = ArgSplitCommand(command);
381
382 pid = CreatePipeAndFork(type, pd);
383 if (pid == (pid_t) -1)
384 {
385 ArgFree(argv);
386 return NULL;
387 }
388
389 if (pid == 0) /* child */
390 {
391 /* WARNING only call async-signal-safe functions in child. */
392
393 switch (*type)
394 {
395 case 'r':
396 ChildOutputSelectDupClose(pd, output_select);
397 break;
398
399 case 'w':
400
401 close(pd[1]);
402
403 if (pd[0] != 0)
404 {
405 dup2(pd[0], 0);
406 close(pd[0]);
407 }
408 }
409
410 ChildrenFDUnsafeClose();
411
412 if (execv(argv[0], argv) == -1)
413 {
414 Log(LOG_LEVEL_ERR, "Couldn't run '%s'. (execv: %s)", argv[0], GetErrorStr());
415 }
416
417 _exit(EXIT_FAILURE);
418 }
419 else /* parent */
420 {
421 switch (*type)
422 {
423 case 'r':
424
425 close(pd[1]);
426
427 if ((pp = fdopen(pd[0], type)) == NULL)
428 {
429 cf_pwait(pid);
430 ArgFree(argv);
431 return NULL;
432 }
433 break;
434
435 case 'w':
436
437 close(pd[0]);
438
439 if ((pp = fdopen(pd[1], type)) == NULL)
440 {
441 cf_pwait(pid);
442 ArgFree(argv);
443 return NULL;
444 }
445 }
446
447 ChildrenFDSet(fileno(pp), pid);
448 ArgFree(argv);
449 return pp;
450 }
451
452 ProgrammingError("Unreachable code");
453 return NULL;
454 }
455
cf_popen(const char * command,const char * type,bool capture_stderr)456 FILE *cf_popen(const char *command, const char *type, bool capture_stderr)
457 {
458 return cf_popen_select(
459 command,
460 type,
461 capture_stderr ? OUTPUT_SELECT_BOTH : OUTPUT_SELECT_STDOUT);
462 }
463
464 /*****************************************************************************/
465
466 /*
467 * WARNING: this is only allowed to be called from single-threaded code,
468 * because of the safe_chdir() call in the forked child.
469 */
cf_popensetuid(const char * command,const char * type,uid_t uid,gid_t gid,char * chdirv,char * chrootv,ARG_UNUSED int background)470 FILE *cf_popensetuid(const char *command, const char *type,
471 uid_t uid, gid_t gid, char *chdirv, char *chrootv,
472 ARG_UNUSED int background)
473 {
474 int pd[2];
475 pid_t pid;
476 FILE *pp = NULL;
477
478 char **argv = ArgSplitCommand(command);
479
480 pid = CreatePipeAndFork(type, pd);
481 if (pid == (pid_t) -1)
482 {
483 ArgFree(argv);
484 return NULL;
485 }
486
487 if (pid == 0) /* child */
488 {
489 /* WARNING only call async-signal-safe functions in child. */
490
491 switch (*type)
492 {
493 case 'r':
494
495 close(pd[0]); /* Don't need output from parent */
496
497 if (pd[1] != 1)
498 {
499 dup2(pd[1], 1); /* Attach pp=pd[1] to our stdout */
500 dup2(pd[1], 2); /* Merge stdout/stderr */
501 close(pd[1]);
502 }
503
504 break;
505
506 case 'w':
507
508 close(pd[1]);
509
510 if (pd[0] != 0)
511 {
512 dup2(pd[0], 0);
513 close(pd[0]);
514 }
515 }
516
517 ChildrenFDUnsafeClose();
518
519 if (chrootv && (strlen(chrootv) != 0))
520 {
521 if (chroot(chrootv) == -1)
522 {
523 Log(LOG_LEVEL_ERR, "Couldn't chroot to '%s'. (chroot: %s)", chrootv, GetErrorStr());
524 _exit(EXIT_FAILURE);
525 }
526 }
527
528 if (chdirv && (strlen(chdirv) != 0))
529 {
530 if (safe_chdir(chdirv) == -1)
531 {
532 Log(LOG_LEVEL_ERR, "Couldn't chdir to '%s'. (chdir: %s)", chdirv, GetErrorStr());
533 _exit(EXIT_FAILURE);
534 }
535 }
536
537 if (!CfSetuid(uid, gid))
538 {
539 _exit(EXIT_FAILURE);
540 }
541
542 if (execv(argv[0], argv) == -1)
543 {
544 Log(LOG_LEVEL_ERR, "Couldn't run '%s'. (execv: %s)", argv[0], GetErrorStr());
545 }
546
547 _exit(EXIT_FAILURE);
548 }
549 else /* parent */
550 {
551 switch (*type)
552 {
553 case 'r':
554
555 close(pd[1]);
556
557 if ((pp = fdopen(pd[0], type)) == NULL)
558 {
559 cf_pwait(pid);
560 ArgFree(argv);
561 return NULL;
562 }
563 break;
564
565 case 'w':
566
567 close(pd[0]);
568
569 if ((pp = fdopen(pd[1], type)) == NULL)
570 {
571 cf_pwait(pid);
572 ArgFree(argv);
573 return NULL;
574 }
575 }
576
577 ChildrenFDSet(fileno(pp), pid);
578 ArgFree(argv);
579 return pp;
580 }
581
582 ProgrammingError("Unreachable code");
583 return NULL;
584 }
585
586 /*****************************************************************************/
587 /* Shell versions of commands - not recommended for security reasons */
588 /*****************************************************************************/
589
cf_popen_sh_select(const char * command,const char * type,OutputSelect output_select)590 FILE *cf_popen_sh_select(const char *command, const char *type, OutputSelect output_select)
591 {
592 int pd[2];
593 pid_t pid;
594 FILE *pp = NULL;
595
596 pid = CreatePipeAndFork(type, pd);
597 if (pid == (pid_t) -1)
598 {
599 return NULL;
600 }
601
602 if (pid == 0) /* child */
603 {
604 /* WARNING only call async-signal-safe functions in child. */
605
606 switch (*type)
607 {
608 case 'r':
609 ChildOutputSelectDupClose(pd, output_select);
610
611 break;
612
613 case 'w':
614
615 close(pd[1]);
616
617 if (pd[0] != 0)
618 {
619 dup2(pd[0], 0);
620 close(pd[0]);
621 }
622 }
623
624 ChildrenFDUnsafeClose();
625
626 execl(SHELL_PATH, "sh", "-c", command, NULL);
627
628 Log(LOG_LEVEL_ERR, "Couldn't run: '%s' (execl: %s)", command, GetErrorStr());
629 _exit(EXIT_FAILURE);
630 }
631 else /* parent */
632 {
633 switch (*type)
634 {
635 case 'r':
636
637 close(pd[1]);
638
639 if ((pp = fdopen(pd[0], type)) == NULL)
640 {
641 cf_pwait(pid);
642 return NULL;
643 }
644 break;
645
646 case 'w':
647
648 close(pd[0]);
649
650 if ((pp = fdopen(pd[1], type)) == NULL)
651 {
652 cf_pwait(pid);
653 return NULL;
654 }
655 }
656
657 ChildrenFDSet(fileno(pp), pid);
658 return pp;
659 }
660
661 ProgrammingError("Unreachable code");
662 return NULL;
663 }
664
cf_popen_sh(const char * command,const char * type)665 FILE *cf_popen_sh(const char *command, const char *type)
666 {
667 return cf_popen_sh_select(command, type, OUTPUT_SELECT_BOTH);
668 }
669
670 /******************************************************************************/
671
672 /*
673 * WARNING: this is only allowed to be called from single-threaded code,
674 * because of the safe_chdir() call in the forked child.
675 */
cf_popen_shsetuid(const char * command,const char * type,uid_t uid,gid_t gid,char * chdirv,char * chrootv,ARG_UNUSED int background)676 FILE *cf_popen_shsetuid(const char *command, const char *type,
677 uid_t uid, gid_t gid, char *chdirv, char *chrootv,
678 ARG_UNUSED int background)
679 {
680 int pd[2];
681 pid_t pid;
682 FILE *pp = NULL;
683
684 pid = CreatePipeAndFork(type, pd);
685 if (pid == (pid_t) -1)
686 {
687 return NULL;
688 }
689
690 if (pid == 0) /* child */
691 {
692 /* WARNING only call async-signal-safe functions in child. */
693
694 switch (*type)
695 {
696 case 'r':
697
698 close(pd[0]); /* Don't need output from parent */
699
700 if (pd[1] != 1)
701 {
702 dup2(pd[1], 1); /* Attach pp=pd[1] to our stdout */
703 dup2(pd[1], 2); /* Merge stdout/stderr */
704 close(pd[1]);
705 }
706
707 break;
708
709 case 'w':
710
711 close(pd[1]);
712
713 if (pd[0] != 0)
714 {
715 dup2(pd[0], 0);
716 close(pd[0]);
717 }
718 }
719
720 ChildrenFDUnsafeClose();
721
722 if (chrootv && (strlen(chrootv) != 0))
723 {
724 if (chroot(chrootv) == -1)
725 {
726 Log(LOG_LEVEL_ERR, "Couldn't chroot to '%s'. (chroot: %s)", chrootv, GetErrorStr());
727 _exit(EXIT_FAILURE);
728 }
729 }
730
731 if (chdirv && (strlen(chdirv) != 0))
732 {
733 if (safe_chdir(chdirv) == -1)
734 {
735 Log(LOG_LEVEL_ERR, "Couldn't chdir to '%s'. (chdir: %s)", chdirv, GetErrorStr());
736 _exit(EXIT_FAILURE);
737 }
738 }
739
740 if (!CfSetuid(uid, gid))
741 {
742 _exit(EXIT_FAILURE);
743 }
744
745 execl(SHELL_PATH, "sh", "-c", command, NULL);
746
747 Log(LOG_LEVEL_ERR, "Couldn't run: '%s' (execl: %s)", command, GetErrorStr());
748 _exit(EXIT_FAILURE);
749 }
750 else /* parent */
751 {
752 switch (*type)
753 {
754 case 'r':
755
756 close(pd[1]);
757
758 if ((pp = fdopen(pd[0], type)) == NULL)
759 {
760 cf_pwait(pid);
761 return NULL;
762 }
763 break;
764
765 case 'w':
766
767 close(pd[0]);
768
769 if ((pp = fdopen(pd[1], type)) == NULL)
770 {
771 cf_pwait(pid);
772 return NULL;
773 }
774 }
775
776 ChildrenFDSet(fileno(pp), pid);
777 return pp;
778 }
779
780 ProgrammingError("Unreachable code");
781 return NULL;
782 }
783
cf_pwait(pid_t pid)784 static int cf_pwait(pid_t pid)
785 {
786 Log(LOG_LEVEL_DEBUG,
787 "cf_pwait - waiting for process %jd", (intmax_t) pid);
788
789 int status;
790 while (waitpid(pid, &status, 0) < 0)
791 {
792 if (errno != EINTR)
793 {
794 Log(LOG_LEVEL_ERR,
795 "Waiting for child PID %jd failed (waitpid: %s)",
796 (intmax_t) pid, GetErrorStr());
797 return -1;
798 }
799 }
800
801 if (!WIFEXITED(status))
802 {
803 Log(LOG_LEVEL_VERBOSE,
804 "Child PID %jd exited abnormally (%s)", (intmax_t) pid,
805 WIFSIGNALED(status) ? "signalled" : (
806 WIFSTOPPED(status) ? "stopped" : (
807 WIFCONTINUED(status) ? "continued" : "unknown" )));
808 return -1;
809 }
810
811 int retcode = WEXITSTATUS(status);
812
813 Log(LOG_LEVEL_DEBUG, "cf_pwait - process %jd exited with code: %d",
814 (intmax_t) pid, retcode);
815 return retcode;
816 }
817
818 /*******************************************************************/
819
820 /**
821 * Closes the pipe without waiting the child.
822 *
823 * @param pp pipe to the child process
824 */
cf_pclose_nowait(FILE * pp)825 void cf_pclose_nowait(FILE *pp)
826 {
827 if (fclose(pp) == EOF)
828 {
829 Log(LOG_LEVEL_ERR,
830 "Could not close the pipe to the executed subcommand (fclose: %s)",
831 GetErrorStr());
832 }
833 }
834
835 /**
836 * Closes the pipe and wait()s for PID of the child,
837 * in order to reap the zombies.
838 */
cf_pclose(FILE * pp)839 int cf_pclose(FILE *pp)
840 {
841 int fd = fileno(pp);
842 pid_t pid;
843
844 ThreadLock(cft_count);
845
846 if (CHILDREN == NULL) /* popen hasn't been called */
847 {
848 ThreadUnlock(cft_count);
849 fclose(pp);
850 return -1;
851 }
852
853 ALARM_PID = -1;
854
855 if (fd >= MAX_FD)
856 {
857 ThreadUnlock(cft_count);
858 Log(LOG_LEVEL_ERR,
859 "File descriptor %d of child higher than MAX_FD in cf_pclose!",
860 fd);
861 fclose(pp);
862 return -1;
863 }
864
865 pid = CHILDREN[fd];
866 CHILDREN[fd] = 0;
867 ThreadUnlock(cft_count);
868
869 if (fclose(pp) == EOF)
870 {
871 Log(LOG_LEVEL_ERR,
872 "Could not close the pipe to the executed subcommand (fclose: %s)",
873 GetErrorStr());
874 }
875
876 return cf_pwait(pid);
877 }
878
cf_pclose_full_duplex_side(int fd)879 int cf_pclose_full_duplex_side(int fd)
880 {
881 ThreadLock(cft_count);
882
883 if (CHILDREN == NULL) /* popen hasn't been called */
884 {
885 ThreadUnlock(cft_count);
886 close(fd);
887 return -1;
888 }
889
890 if (fd >= MAX_FD)
891 {
892 ThreadUnlock(cft_count);
893 Log(LOG_LEVEL_ERR,
894 "File descriptor %d of child higher than MAX_FD in cf_pclose_full_duplex_side!",
895 fd);
896 }
897 else
898 {
899 CHILDREN[fd] = 0;
900 ThreadUnlock(cft_count);
901 }
902 return close(fd);
903 }
904
905
906 /* We are assuming that read_fd part will be always open at this point. */
cf_pclose_full_duplex(IOData * data)907 int cf_pclose_full_duplex(IOData *data)
908 {
909 assert(data != NULL);
910 ThreadLock(cft_count);
911
912 if (CHILDREN == NULL)
913 {
914 ThreadUnlock(cft_count);
915 if (data->read_stream != NULL)
916 {
917 // fclose closes the underlying fd / socket,
918 // but we need the fd for handling of processes below.
919 assert(data->read_fd >= 0);
920 fclose(data->read_stream);
921 }
922 else if (data->read_fd >= 0)
923 {
924 close(data->read_fd);
925 }
926
927 if (data->write_stream != NULL)
928 {
929 // fclose closes the underlying fd / socket,
930 // but we need the fd for handling of processes below.
931 assert(data->write_fd >= 0);
932 fclose(data->write_stream);
933 }
934 else if (data->write_fd >= 0)
935 {
936 close(data->write_fd);
937 }
938 return -1;
939 }
940
941 ALARM_PID = -1;
942 pid_t pid = 0;
943
944 /* Safe as pipes[1] is -1 if not initialized */
945 if (data->read_fd >= MAX_FD || data->write_fd >= MAX_FD)
946 {
947 ThreadUnlock(cft_count);
948 Log(LOG_LEVEL_ERR,
949 "File descriptor %d of child higher than MAX_FD in cf_pclose!",
950 data->read_fd > data->write_fd ? data->read_fd : data->write_fd);
951 }
952 else
953 {
954 pid = CHILDREN[data->read_fd];
955 if (data->write_fd >= 0)
956 {
957 assert(pid == CHILDREN[data->write_fd]);
958 CHILDREN[data->write_fd] = 0;
959 }
960 CHILDREN[data->read_fd] = 0;
961 ThreadUnlock(cft_count);
962 }
963
964 if (data->read_stream != NULL)
965 {
966 // Stream is open, fclose it
967 if (fclose(data->read_stream) != 0)
968 {
969 return -1;
970 }
971 }
972 else
973 {
974 // No stream, just close fd
975 if (close(data->read_fd) != 0)
976 {
977 return -1;
978 }
979 }
980
981 if (data->write_fd >= 0)
982 {
983 // write fd needs to be closed
984 if (data->write_stream != NULL)
985 {
986 // Stream is open, fclose it
987 if (fclose(data->write_stream) != 0)
988 {
989 return -1;
990 }
991 }
992 else
993 {
994 // No stream, close fd directly
995 if (close(data->write_fd) != 0)
996 {
997 return -1;
998 }
999 }
1000 }
1001
1002 if (pid == 0)
1003 {
1004 return -1;
1005 }
1006
1007 return cf_pwait(pid);
1008 }
1009
PipeToPid(pid_t * pid,FILE * pp)1010 bool PipeToPid(pid_t *pid, FILE *pp)
1011 {
1012 int fd = fileno(pp);
1013 ThreadLock(cft_count);
1014
1015 if (CHILDREN == NULL) /* popen hasn't been called */
1016 {
1017 ThreadUnlock(cft_count);
1018 return false;
1019 }
1020
1021 *pid = CHILDREN[fd];
1022 ThreadUnlock(cft_count);
1023
1024 return true;
1025 }
1026
1027 /*******************************************************************/
1028
CfSetuid(uid_t uid,gid_t gid)1029 static bool CfSetuid(uid_t uid, gid_t gid)
1030 {
1031 struct passwd *pw;
1032
1033 if (gid != (gid_t) - 1)
1034 {
1035 Log(LOG_LEVEL_VERBOSE, "Changing gid to %ju", (uintmax_t)gid);
1036
1037 if (setgid(gid) == -1)
1038 {
1039 Log(LOG_LEVEL_ERR, "Couldn't set gid to '%ju'. (setgid: %s)", (uintmax_t)gid, GetErrorStr());
1040 return false;
1041 }
1042
1043 /* Now eliminate any residual privileged groups */
1044
1045 if ((pw = getpwuid(uid)) == NULL)
1046 {
1047 Log(LOG_LEVEL_ERR, "Unable to get login groups when dropping privilege to '%ju'. (getpwuid: %s)", (uintmax_t)uid, GetErrorStr());
1048 return false;
1049 }
1050
1051 if (initgroups(pw->pw_name, pw->pw_gid) == -1)
1052 {
1053 Log(LOG_LEVEL_ERR, "Unable to set login groups when dropping privilege to '%s=%ju'. (initgroups: %s)", pw->pw_name,
1054 (uintmax_t)uid, GetErrorStr());
1055 return false;
1056 }
1057 }
1058
1059 if (uid != (uid_t) - 1)
1060 {
1061 Log(LOG_LEVEL_VERBOSE, "Changing uid to '%ju'", (uintmax_t)uid);
1062
1063 if (setuid(uid) == -1)
1064 {
1065 Log(LOG_LEVEL_ERR, "Couldn't set uid to '%ju'. (setuid: %s)", (uintmax_t)uid, GetErrorStr());
1066 return false;
1067 }
1068 }
1069
1070 return true;
1071 }
1072
1073 /* For Windows we need a different method because select() does not */
1074 /* work with non-socket file descriptors. */
PipeIsReadWriteReady(const IOData * io,int timeout_sec)1075 int PipeIsReadWriteReady(const IOData *io, int timeout_sec)
1076 {
1077 fd_set rset;
1078 FD_ZERO(&rset);
1079 FD_SET(io->read_fd, &rset);
1080
1081 struct timeval tv = {
1082 .tv_sec = timeout_sec,
1083 .tv_usec = 0,
1084 };
1085
1086 Log(LOG_LEVEL_DEBUG,
1087 "PipeIsReadWriteReady: wait max %ds for data on fd %d",
1088 timeout_sec, io->read_fd);
1089
1090 int ret = select(io->read_fd + 1, &rset, NULL, NULL, &tv);
1091
1092 if (ret < 0)
1093 {
1094 Log(LOG_LEVEL_VERBOSE, "Failed checking for data (select: %s)",
1095 GetErrorStr());
1096 return -1;
1097 }
1098 else if (FD_ISSET(io->read_fd, &rset))
1099 {
1100 return io->read_fd;
1101 }
1102 else if (ret == 0)
1103 {
1104 /* timeout_sec has elapsed but no data was available. */
1105 return 0;
1106 }
1107 else
1108 {
1109 UnexpectedError("select() returned > 0 but our only fd is not set!");
1110 return -1;
1111 }
1112 }
1113