xref: /freebsd/usr.sbin/cron/cron/popen.c (revision 8a7b6120)
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