184f33deaSJordan K. Hubbard /*
284f33deaSJordan K. Hubbard * Copyright (c) 1988 The Regents of the University of California.
384f33deaSJordan K. Hubbard * All rights reserved.
484f33deaSJordan K. Hubbard *
584f33deaSJordan K. Hubbard * This code is derived from software written by Ken Arnold and
684f33deaSJordan K. Hubbard * published in UNIX Review, Vol. 6, No. 8.
784f33deaSJordan K. Hubbard *
884f33deaSJordan K. Hubbard * Redistribution and use in source and binary forms are permitted
984f33deaSJordan K. Hubbard * provided that the above copyright notice and this paragraph are
1084f33deaSJordan K. Hubbard * duplicated in all such forms and that any documentation,
1184f33deaSJordan K. Hubbard * advertising materials, and other materials related to such
1284f33deaSJordan K. Hubbard * distribution and use acknowledge that the software was developed
1384f33deaSJordan K. Hubbard * by the University of California, Berkeley. The name of the
1484f33deaSJordan K. Hubbard * University may not be used to endorse or promote products derived
1584f33deaSJordan K. Hubbard * from this software without specific prior written permission.
1684f33deaSJordan K. Hubbard * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1784f33deaSJordan K. Hubbard * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1884f33deaSJordan K. Hubbard * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1984f33deaSJordan K. Hubbard *
2084f33deaSJordan K. Hubbard */
2184f33deaSJordan K. Hubbard
2284f33deaSJordan K. Hubbard /* this came out of the ftpd sources; it's been modified to avoid the
2384f33deaSJordan K. Hubbard * globbing stuff since we don't need it. also execvp instead of execv.
2484f33deaSJordan K. Hubbard */
2584f33deaSJordan K. Hubbard
2684f33deaSJordan K. Hubbard #ifndef lint
27401e6468SPhilippe Charnier static const char rcsid[] =
28fe590ffeSEric van Gyzen "$Id: popen.c,v 1.3 1998/08/14 00:32:41 vixie Exp $";
2984f33deaSJordan K. Hubbard #endif /* not lint */
3084f33deaSJordan K. Hubbard
3184f33deaSJordan K. Hubbard #include "cron.h"
32fe46d6a8SAndrey A. Chernov #if defined(LOGIN_CAP)
33fe46d6a8SAndrey A. Chernov # include <login_cap.h>
34fe46d6a8SAndrey A. Chernov #endif
3584f33deaSJordan K. Hubbard
36bdddbd2fSPaul Traina #define MAX_ARGS 100
3784f33deaSJordan K. Hubbard #define WANT_GLOBBING 0
3884f33deaSJordan K. Hubbard
3984f33deaSJordan K. Hubbard /*
4084f33deaSJordan K. Hubbard * Special version of popen which avoids call to shell. This insures no one
4184f33deaSJordan K. Hubbard * may create a pipe to a hidden program as a side effect of a list or dir
4284f33deaSJordan K. Hubbard * command.
4384f33deaSJordan K. Hubbard */
4484f33deaSJordan K. Hubbard static PID_T *pids;
4584f33deaSJordan K. Hubbard static int fds;
4684f33deaSJordan K. Hubbard
4784f33deaSJordan K. Hubbard FILE *
cron_popen(char * program,char * type,entry * e,PID_T * pidptr)48e93f27e3SJohn Baldwin cron_popen(char *program, char *type, entry *e, PID_T *pidptr)
4984f33deaSJordan K. Hubbard {
50fe590ffeSEric van Gyzen char *cp;
5184f33deaSJordan K. Hubbard FILE *iop;
5284f33deaSJordan K. Hubbard int argc, pdes[2];
5384f33deaSJordan K. Hubbard PID_T pid;
54fe46d6a8SAndrey A. Chernov char *usernm;
55bdddbd2fSPaul Traina char *argv[MAX_ARGS + 1];
56fe46d6a8SAndrey A. Chernov # if defined(LOGIN_CAP)
57fe46d6a8SAndrey A. Chernov struct passwd *pwd;
58fe46d6a8SAndrey A. Chernov login_cap_t *lc;
59fe46d6a8SAndrey A. Chernov # endif
6084f33deaSJordan K. Hubbard #if WANT_GLOBBING
6184f33deaSJordan K. Hubbard char **pop, *vv[2];
6284f33deaSJordan K. Hubbard int gargc;
6384f33deaSJordan K. Hubbard char *gargv[1000];
6484f33deaSJordan K. Hubbard extern char **glob(), **copyblk();
6584f33deaSJordan K. Hubbard #endif
6684f33deaSJordan K. Hubbard
67fe590ffeSEric van Gyzen if ((*type != 'r' && *type != 'w') || type[1] != '\0')
6884f33deaSJordan K. Hubbard return (NULL);
6984f33deaSJordan K. Hubbard
7084f33deaSJordan K. Hubbard if (!pids) {
71fe590ffeSEric van Gyzen if ((fds = sysconf(_SC_OPEN_MAX)) <= 0)
7284f33deaSJordan K. Hubbard return (NULL);
73c28c9846SPedro F. Giffuni if (!(pids = calloc(fds, sizeof(PID_T))))
7484f33deaSJordan K. Hubbard return (NULL);
7584f33deaSJordan K. Hubbard }
7684f33deaSJordan K. Hubbard if (pipe(pdes) < 0)
7784f33deaSJordan K. Hubbard return (NULL);
7884f33deaSJordan K. Hubbard
7984f33deaSJordan K. Hubbard /* break up string into pieces */
80bdddbd2fSPaul Traina for (argc = 0, cp = program; argc < MAX_ARGS; cp = NULL)
8184f33deaSJordan K. Hubbard if (!(argv[argc++] = strtok(cp, " \t\n")))
8284f33deaSJordan K. Hubbard break;
83c38d808dSAndrey A. Chernov argv[MAX_ARGS] = NULL;
8484f33deaSJordan K. Hubbard
8584f33deaSJordan K. Hubbard #if WANT_GLOBBING
8684f33deaSJordan K. Hubbard /* glob each piece */
8784f33deaSJordan K. Hubbard gargv[0] = argv[0];
8884f33deaSJordan K. Hubbard for (gargc = argc = 1; argv[argc]; argc++) {
8984f33deaSJordan K. Hubbard if (!(pop = glob(argv[argc]))) { /* globbing failed */
9084f33deaSJordan K. Hubbard vv[0] = argv[argc];
9184f33deaSJordan K. Hubbard vv[1] = NULL;
9284f33deaSJordan K. Hubbard pop = copyblk(vv);
9384f33deaSJordan K. Hubbard }
9484f33deaSJordan K. Hubbard argv[argc] = (char *)pop; /* save to free later */
9584f33deaSJordan K. Hubbard while (*pop && gargc < 1000)
9684f33deaSJordan K. Hubbard gargv[gargc++] = *pop++;
9784f33deaSJordan K. Hubbard }
9884f33deaSJordan K. Hubbard gargv[gargc] = NULL;
9984f33deaSJordan K. Hubbard #endif
10084f33deaSJordan K. Hubbard
10184f33deaSJordan K. Hubbard iop = NULL;
1029b367233SKyle Evans switch(pid = fork()) {
10384f33deaSJordan K. Hubbard case -1: /* error */
10484f33deaSJordan K. Hubbard (void)close(pdes[0]);
10584f33deaSJordan K. Hubbard (void)close(pdes[1]);
10684f33deaSJordan K. Hubbard goto pfree;
10784f33deaSJordan K. Hubbard /* NOTREACHED */
10884f33deaSJordan K. Hubbard case 0: /* child */
109fe46d6a8SAndrey A. Chernov if (e != NULL) {
110fe46d6a8SAndrey A. Chernov #ifdef SYSLOG
111fe46d6a8SAndrey A. Chernov closelog();
112fe46d6a8SAndrey A. Chernov #endif
113fe46d6a8SAndrey A. Chernov
114fe46d6a8SAndrey A. Chernov /* get new pgrp, void tty, etc.
115fe46d6a8SAndrey A. Chernov */
116fe46d6a8SAndrey A. Chernov (void) setsid();
117fe46d6a8SAndrey A. Chernov }
11884f33deaSJordan K. Hubbard if (*type == 'r') {
1195ef48958SPeter Wemm /* Do not share our parent's stdin */
1205ef48958SPeter Wemm (void)close(0);
1211a37aa56SDavid E. O'Brien (void)open(_PATH_DEVNULL, O_RDWR);
12284f33deaSJordan K. Hubbard if (pdes[1] != 1) {
12384f33deaSJordan K. Hubbard dup2(pdes[1], 1);
12484f33deaSJordan K. Hubbard dup2(pdes[1], 2); /* stderr, too! */
12584f33deaSJordan K. Hubbard (void)close(pdes[1]);
12684f33deaSJordan K. Hubbard }
12784f33deaSJordan K. Hubbard (void)close(pdes[0]);
12884f33deaSJordan K. Hubbard } else {
12984f33deaSJordan K. Hubbard if (pdes[0] != 0) {
13084f33deaSJordan K. Hubbard dup2(pdes[0], 0);
13184f33deaSJordan K. Hubbard (void)close(pdes[0]);
13284f33deaSJordan K. Hubbard }
1335ef48958SPeter Wemm /* Hack: stdout gets revoked */
1345ef48958SPeter Wemm (void)close(1);
1351a37aa56SDavid E. O'Brien (void)open(_PATH_DEVNULL, O_RDWR);
1365ef48958SPeter Wemm (void)close(2);
1371a37aa56SDavid E. O'Brien (void)open(_PATH_DEVNULL, O_RDWR);
13884f33deaSJordan K. Hubbard (void)close(pdes[1]);
13984f33deaSJordan K. Hubbard }
140fe46d6a8SAndrey A. Chernov if (e != NULL) {
141fe46d6a8SAndrey A. Chernov /* Set user's entire context, but skip the environment
142fe46d6a8SAndrey A. Chernov * as cron provides a separate interface for this
143fe46d6a8SAndrey A. Chernov */
144fe46d6a8SAndrey A. Chernov usernm = env_get("LOGNAME", e->envp);
145af71ab4fSRob Braun # if defined(LOGIN_CAP)
146fe46d6a8SAndrey A. Chernov if ((pwd = getpwnam(usernm)) == NULL)
147fe46d6a8SAndrey A. Chernov pwd = getpwuid(e->uid);
148fe46d6a8SAndrey A. Chernov lc = NULL;
149fe46d6a8SAndrey A. Chernov if (pwd != NULL) {
150fe46d6a8SAndrey A. Chernov pwd->pw_gid = e->gid;
151fe46d6a8SAndrey A. Chernov if (e->class != NULL)
152fe46d6a8SAndrey A. Chernov lc = login_getclass(e->class);
153fe46d6a8SAndrey A. Chernov }
154fe46d6a8SAndrey A. Chernov if (pwd &&
155fe46d6a8SAndrey A. Chernov setusercontext(lc, pwd, e->uid,
156fe46d6a8SAndrey A. Chernov LOGIN_SETALL & ~(LOGIN_SETPATH|LOGIN_SETENV)) == 0)
157fe46d6a8SAndrey A. Chernov (void) endpwent();
158fe46d6a8SAndrey A. Chernov else {
159fe46d6a8SAndrey A. Chernov /* fall back to the old method */
160fe46d6a8SAndrey A. Chernov (void) endpwent();
161fe46d6a8SAndrey A. Chernov # endif
162b608e56dSMaxim Konovalov /*
163b608e56dSMaxim Konovalov * Set our directory, uid and gid. Set gid
164b608e56dSMaxim Konovalov * first since once we set uid, we've lost
165708f27a1SMaxim Konovalov * root privileges.
166fe46d6a8SAndrey A. Chernov */
167bb0aa1a5SMaxim Konovalov if (setgid(e->gid) != 0)
168bb0aa1a5SMaxim Konovalov _exit(ERROR_EXIT);
169fe46d6a8SAndrey A. Chernov # if defined(BSD)
170bb0aa1a5SMaxim Konovalov if (initgroups(usernm, e->gid) != 0)
171bb0aa1a5SMaxim Konovalov _exit(ERROR_EXIT);
172fe46d6a8SAndrey A. Chernov # endif
173bb0aa1a5SMaxim Konovalov if (setlogin(usernm) != 0)
174bb0aa1a5SMaxim Konovalov _exit(ERROR_EXIT);
175bb0aa1a5SMaxim Konovalov if (setuid(e->uid) != 0)
176bb0aa1a5SMaxim Konovalov _exit(ERROR_EXIT);
177bb0aa1a5SMaxim Konovalov /* we aren't root after this..*/
178fe46d6a8SAndrey A. Chernov #if defined(LOGIN_CAP)
179fe46d6a8SAndrey A. Chernov }
1803d99cebfSAndrey A. Chernov if (lc != NULL)
1813d99cebfSAndrey A. Chernov login_close(lc);
182fe46d6a8SAndrey A. Chernov #endif
183fe46d6a8SAndrey A. Chernov chdir(env_get("HOME", e->envp));
184fe46d6a8SAndrey A. Chernov }
18584f33deaSJordan K. Hubbard #if WANT_GLOBBING
18684f33deaSJordan K. Hubbard execvp(gargv[0], gargv);
18784f33deaSJordan K. Hubbard #else
18884f33deaSJordan K. Hubbard execvp(argv[0], argv);
18984f33deaSJordan K. Hubbard #endif
19084f33deaSJordan K. Hubbard _exit(1);
19184f33deaSJordan K. Hubbard }
19284f33deaSJordan K. Hubbard /* parent; assume fdopen can't fail... */
19384f33deaSJordan K. Hubbard if (*type == 'r') {
19484f33deaSJordan K. Hubbard iop = fdopen(pdes[0], type);
19584f33deaSJordan K. Hubbard (void)close(pdes[1]);
19684f33deaSJordan K. Hubbard } else {
19784f33deaSJordan K. Hubbard iop = fdopen(pdes[1], type);
19884f33deaSJordan K. Hubbard (void)close(pdes[0]);
19984f33deaSJordan K. Hubbard }
20084f33deaSJordan K. Hubbard pids[fileno(iop)] = pid;
20184f33deaSJordan K. Hubbard
20284f33deaSJordan K. Hubbard pfree:
20384f33deaSJordan K. Hubbard #if WANT_GLOBBING
20484f33deaSJordan K. Hubbard for (argc = 1; argv[argc] != NULL; argc++) {
20584f33deaSJordan K. Hubbard /* blkfree((char **)argv[argc]); */
20684f33deaSJordan K. Hubbard free((char *)argv[argc]);
20784f33deaSJordan K. Hubbard }
20884f33deaSJordan K. Hubbard #endif
2095b80de23SKyle Evans
2105b80de23SKyle Evans *pidptr = pid;
2115b80de23SKyle Evans
21284f33deaSJordan K. Hubbard return (iop);
21384f33deaSJordan K. Hubbard }
21484f33deaSJordan K. Hubbard
21584f33deaSJordan K. Hubbard int
cron_pclose(FILE * iop)216e93f27e3SJohn Baldwin cron_pclose(FILE *iop)
21784f33deaSJordan K. Hubbard {
218fe590ffeSEric van Gyzen int fdes;
21984f33deaSJordan K. Hubbard int omask;
22084f33deaSJordan K. Hubbard WAIT_T stat_loc;
22184f33deaSJordan K. Hubbard PID_T pid;
22284f33deaSJordan K. Hubbard
22384f33deaSJordan K. Hubbard /*
22484f33deaSJordan K. Hubbard * pclose returns -1 if stream is not associated with a
22584f33deaSJordan K. Hubbard * `popened' command, or, if already `pclosed'.
22684f33deaSJordan K. Hubbard */
22784f33deaSJordan K. Hubbard if (pids == 0 || pids[fdes = fileno(iop)] == 0)
22884f33deaSJordan K. Hubbard return (-1);
22984f33deaSJordan K. Hubbard (void)fclose(iop);
23084f33deaSJordan K. Hubbard omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
23184f33deaSJordan K. Hubbard while ((pid = wait(&stat_loc)) != pids[fdes] && pid != -1)
23284f33deaSJordan K. Hubbard ;
23384f33deaSJordan K. Hubbard (void)sigsetmask(omask);
23484f33deaSJordan K. Hubbard pids[fdes] = 0;
23584f33deaSJordan K. Hubbard return (pid == -1 ? -1 : WEXITSTATUS(stat_loc));
23684f33deaSJordan K. Hubbard }
237