1 /* $OpenBSD: popen.c,v 1.19 2003/06/02 04:39:45 millert Exp $ */
2
3 /*
4 * Copyright (c) 1988, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software written by Ken Arnold and
8 * published in UNIX Review, Vol. 6, No. 8.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 */
35
36 /* this came out of the ftpd sources; it's been modified to avoid the
37 * globbing stuff since we don't need it. also execvp instead of execv.
38 */
39
40 #ifndef lint
41 #if 0
42 static const sccsid[] = "@(#)popen.c 8.3 (Berkeley) 4/6/94";
43 #else
44 static const char rcsid[] = "$OpenBSD: popen.c,v 1.19 2003/06/02 04:39:45 millert Exp $";
45 #endif
46 #endif /* not lint */
47
48 #include "cron.h"
49
50 #define MAX_ARGV 100
51 #define MAX_GARGV 1000
52
53 /*
54 * Special version of popen which avoids call to shell. This ensures noone
55 * may create a pipe to a hidden program as a side effect of a list or dir
56 * command.
57 */
58 static PID_T *pids;
59 static int fds;
60
61 FILE *
cron_popen(char * program,char * type,struct passwd * pw)62 cron_popen(char *program, char *type, struct passwd *pw) {
63 char *cp;
64 FILE *iop;
65 int argc, pdes[2];
66 PID_T pid;
67 char *argv[MAX_ARGV];
68
69 if ((*type != 'r' && *type != 'w') || type[1] != '\0')
70 return (NULL);
71
72 if (!pids) {
73 if ((fds = sysconf(_SC_OPEN_MAX)) <= 0)
74 return (NULL);
75 if (!(pids = (PID_T *)malloc((size_t)(fds * sizeof(PID_T)))))
76 return (NULL);
77 bzero(pids, fds * sizeof(PID_T));
78 }
79 if (pipe(pdes) < 0)
80 return (NULL);
81
82 /* break up string into pieces */
83 for (argc = 0, cp = program; argc < MAX_ARGV - 1; cp = NULL)
84 if (!(argv[argc++] = strtok(cp, " \t\n")))
85 break;
86 argv[MAX_ARGV-1] = NULL;
87
88 switch (pid = fork()) {
89 case -1: /* error */
90 (void)close(pdes[0]);
91 (void)close(pdes[1]);
92 return (NULL);
93 /* NOTREACHED */
94 case 0: /* child */
95 if (pw) {
96 #ifdef LOGIN_CAP
97 if (setusercontext(0, pw, pw->pw_uid, LOGIN_SETALL) < 0) {
98 fprintf(stderr,
99 "setusercontext failed for %s\n",
100 pw->pw_name);
101 _exit(ERROR_EXIT);
102 }
103 #else
104 if (setgid(pw->pw_gid) < 0 ||
105 initgroups(pw->pw_name, pw->pw_gid) < 0) {
106 fprintf(stderr,
107 "unable to set groups for %s\n",
108 pw->pw_name);
109 _exit(1);
110 }
111 #if (defined(BSD)) && (BSD >= 199103)
112 setlogin(pw->pw_name);
113 #endif /* BSD */
114 if (setuid(pw->pw_uid)) {
115 fprintf(stderr,
116 "unable to set uid for %s\n",
117 pw->pw_name);
118 _exit(1);
119 }
120 #endif /* LOGIN_CAP */
121 }
122 if (*type == 'r') {
123 if (pdes[1] != STDOUT) {
124 dup2(pdes[1], STDOUT);
125 (void)close(pdes[1]);
126 }
127 dup2(STDOUT, STDERR); /* stderr too! */
128 (void)close(pdes[0]);
129 } else {
130 if (pdes[0] != STDIN) {
131 dup2(pdes[0], STDIN);
132 (void)close(pdes[0]);
133 }
134 (void)close(pdes[1]);
135 }
136 execvp(argv[0], argv);
137 _exit(1);
138 }
139
140 /* parent; assume fdopen can't fail... */
141 if (*type == 'r') {
142 iop = fdopen(pdes[0], type);
143 (void)close(pdes[1]);
144 } else {
145 iop = fdopen(pdes[1], type);
146 (void)close(pdes[0]);
147 }
148 pids[fileno(iop)] = pid;
149
150 return (iop);
151 }
152
153 int
cron_pclose(FILE * iop)154 cron_pclose(FILE *iop) {
155 int fdes;
156 PID_T pid;
157 WAIT_T status;
158 sigset_t sigset, osigset;
159
160 /*
161 * pclose returns -1 if stream is not associated with a
162 * `popened' command, or, if already `pclosed'.
163 */
164 if (pids == 0 || pids[fdes = fileno(iop)] == 0)
165 return (-1);
166 (void)fclose(iop);
167 sigemptyset(&sigset);
168 sigaddset(&sigset, SIGINT);
169 sigaddset(&sigset, SIGQUIT);
170 sigaddset(&sigset, SIGHUP);
171 sigprocmask(SIG_BLOCK, &sigset, &osigset);
172 while ((pid = waitpid(pids[fdes], &status, 0)) < 0 && errno == EINTR)
173 continue;
174 sigprocmask(SIG_SETMASK, &osigset, NULL);
175 pids[fdes] = 0;
176 if (pid < 0)
177 return (pid);
178 if (WIFEXITED(status))
179 return (WEXITSTATUS(status));
180 return (1);
181 }
182