12311Sjkh/* 22311Sjkh * Copyright (c) 1988 The Regents of the University of California. 32311Sjkh * All rights reserved. 42311Sjkh * 52311Sjkh * This code is derived from software written by Ken Arnold and 62311Sjkh * published in UNIX Review, Vol. 6, No. 8. 72311Sjkh * 82311Sjkh * Redistribution and use in source and binary forms are permitted 92311Sjkh * provided that the above copyright notice and this paragraph are 102311Sjkh * duplicated in all such forms and that any documentation, 112311Sjkh * advertising materials, and other materials related to such 122311Sjkh * distribution and use acknowledge that the software was developed 132311Sjkh * by the University of California, Berkeley. The name of the 142311Sjkh * University may not be used to endorse or promote products derived 152311Sjkh * from this software without specific prior written permission. 162311Sjkh * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 172311Sjkh * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 182311Sjkh * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 192311Sjkh * 202311Sjkh */ 212311Sjkh 222311Sjkh/* this came out of the ftpd sources; it's been modified to avoid the 232311Sjkh * globbing stuff since we don't need it. also execvp instead of execv. 242311Sjkh */ 252311Sjkh 262311Sjkh#ifndef lint 2729452Scharnier#if 0 282311Sjkhstatic char sccsid[] = "@(#)popen.c 5.7 (Berkeley) 2/14/89"; 2929452Scharnier#endif 3029452Scharnierstatic const char rcsid[] = 3150479Speter "$FreeBSD$"; 322311Sjkh#endif /* not lint */ 332311Sjkh 342311Sjkh#include "cron.h" 352311Sjkh#include <sys/signal.h> 3645369Speter#include <fcntl.h> 3769793Sobrien#include <paths.h> 3862367Sache#if defined(SYSLOG) 3962367Sache# include <syslog.h> 4062367Sache#endif 4162367Sache#if defined(LOGIN_CAP) 4262367Sache# include <login_cap.h> 4362367Sache#endif 442311Sjkh 452311Sjkh 4620573Spst#define MAX_ARGS 100 472311Sjkh#define WANT_GLOBBING 0 482311Sjkh 492311Sjkh/* 502311Sjkh * Special version of popen which avoids call to shell. This insures noone 512311Sjkh * may create a pipe to a hidden program as a side effect of a list or dir 522311Sjkh * command. 532311Sjkh */ 542311Sjkhstatic PID_T *pids; 552311Sjkhstatic int fds; 562311Sjkh 572311SjkhFILE * 5862367Sachecron_popen(program, type, e) 592311Sjkh char *program, *type; 6062367Sache entry *e; 612311Sjkh{ 622311Sjkh register char *cp; 632311Sjkh FILE *iop; 642311Sjkh int argc, pdes[2]; 652311Sjkh PID_T pid; 6662367Sache char *usernm; 6720573Spst char *argv[MAX_ARGS + 1]; 6862367Sache# if defined(LOGIN_CAP) 6962367Sache struct passwd *pwd; 7062367Sache login_cap_t *lc; 7162367Sache# endif 722311Sjkh#if WANT_GLOBBING 732311Sjkh char **pop, *vv[2]; 742311Sjkh int gargc; 752311Sjkh char *gargv[1000]; 762311Sjkh extern char **glob(), **copyblk(); 772311Sjkh#endif 782311Sjkh 7929452Scharnier if ((*type != 'r' && *type != 'w') || type[1]) 802311Sjkh return(NULL); 812311Sjkh 822311Sjkh if (!pids) { 832311Sjkh if ((fds = getdtablesize()) <= 0) 842311Sjkh return(NULL); 852311Sjkh if (!(pids = (PID_T *)malloc((u_int)(fds * sizeof(PID_T))))) 862311Sjkh return(NULL); 872311Sjkh bzero((char *)pids, fds * sizeof(PID_T)); 882311Sjkh } 892311Sjkh if (pipe(pdes) < 0) 902311Sjkh return(NULL); 912311Sjkh 922311Sjkh /* break up string into pieces */ 9320573Spst for (argc = 0, cp = program; argc < MAX_ARGS; cp = NULL) 942311Sjkh if (!(argv[argc++] = strtok(cp, " \t\n"))) 952311Sjkh break; 9662365Sache argv[MAX_ARGS] = NULL; 972311Sjkh 982311Sjkh#if WANT_GLOBBING 992311Sjkh /* glob each piece */ 1002311Sjkh gargv[0] = argv[0]; 1012311Sjkh for (gargc = argc = 1; argv[argc]; argc++) { 1022311Sjkh if (!(pop = glob(argv[argc]))) { /* globbing failed */ 1032311Sjkh vv[0] = argv[argc]; 1042311Sjkh vv[1] = NULL; 1052311Sjkh pop = copyblk(vv); 1062311Sjkh } 1072311Sjkh argv[argc] = (char *)pop; /* save to free later */ 1082311Sjkh while (*pop && gargc < 1000) 1092311Sjkh gargv[gargc++] = *pop++; 1102311Sjkh } 1112311Sjkh gargv[gargc] = NULL; 1122311Sjkh#endif 1132311Sjkh 1142311Sjkh iop = NULL; 1152311Sjkh switch(pid = vfork()) { 1162311Sjkh case -1: /* error */ 1172311Sjkh (void)close(pdes[0]); 1182311Sjkh (void)close(pdes[1]); 1192311Sjkh goto pfree; 1202311Sjkh /* NOTREACHED */ 1212311Sjkh case 0: /* child */ 12262367Sache if (e != NULL) { 12362367Sache#ifdef SYSLOG 12462367Sache closelog(); 12562367Sache#endif 12662367Sache 12762367Sache /* get new pgrp, void tty, etc. 12862367Sache */ 12962367Sache (void) setsid(); 13062367Sache } 1312311Sjkh if (*type == 'r') { 13245369Speter /* Do not share our parent's stdin */ 13345369Speter (void)close(0); 13469793Sobrien (void)open(_PATH_DEVNULL, O_RDWR); 1352311Sjkh if (pdes[1] != 1) { 1362311Sjkh dup2(pdes[1], 1); 1372311Sjkh dup2(pdes[1], 2); /* stderr, too! */ 1382311Sjkh (void)close(pdes[1]); 1392311Sjkh } 1402311Sjkh (void)close(pdes[0]); 1412311Sjkh } else { 1422311Sjkh if (pdes[0] != 0) { 1432311Sjkh dup2(pdes[0], 0); 1442311Sjkh (void)close(pdes[0]); 1452311Sjkh } 14645369Speter /* Hack: stdout gets revoked */ 14745369Speter (void)close(1); 14869793Sobrien (void)open(_PATH_DEVNULL, O_RDWR); 14945369Speter (void)close(2); 15069793Sobrien (void)open(_PATH_DEVNULL, O_RDWR); 1512311Sjkh (void)close(pdes[1]); 1522311Sjkh } 15362367Sache if (e != NULL) { 15462367Sache /* Set user's entire context, but skip the environment 15562367Sache * as cron provides a separate interface for this 15662367Sache */ 15762367Sache usernm = env_get("LOGNAME", e->envp); 15890276Sbbraun# if defined(LOGIN_CAP) 15962367Sache if ((pwd = getpwnam(usernm)) == NULL) 16062367Sache pwd = getpwuid(e->uid); 16162367Sache lc = NULL; 16262367Sache if (pwd != NULL) { 16362367Sache pwd->pw_gid = e->gid; 16462367Sache if (e->class != NULL) 16562367Sache lc = login_getclass(e->class); 16662367Sache } 16762367Sache if (pwd && 16862367Sache setusercontext(lc, pwd, e->uid, 16962367Sache LOGIN_SETALL & ~(LOGIN_SETPATH|LOGIN_SETENV)) == 0) 17062367Sache (void) endpwent(); 17162367Sache else { 17262367Sache /* fall back to the old method */ 17362367Sache (void) endpwent(); 17462367Sache# endif 175159523Smaxim /* 176159523Smaxim * Set our directory, uid and gid. Set gid 177159523Smaxim * first since once we set uid, we've lost 178159527Smaxim * root privileges. 17962367Sache */ 180159142Smaxim if (setgid(e->gid) != 0) 181159142Smaxim _exit(ERROR_EXIT); 18262367Sache# if defined(BSD) 183159142Smaxim if (initgroups(usernm, e->gid) != 0) 184159142Smaxim _exit(ERROR_EXIT); 18562367Sache# endif 186159142Smaxim if (setlogin(usernm) != 0) 187159142Smaxim _exit(ERROR_EXIT); 188159142Smaxim if (setuid(e->uid) != 0) 189159142Smaxim _exit(ERROR_EXIT); 190159142Smaxim /* we aren't root after this..*/ 19162367Sache#if defined(LOGIN_CAP) 19262367Sache } 19362376Sache if (lc != NULL) 19462376Sache login_close(lc); 19562367Sache#endif 19662367Sache chdir(env_get("HOME", e->envp)); 19762367Sache } 1982311Sjkh#if WANT_GLOBBING 1992311Sjkh execvp(gargv[0], gargv); 2002311Sjkh#else 2012311Sjkh execvp(argv[0], argv); 2022311Sjkh#endif 2032311Sjkh _exit(1); 2042311Sjkh } 2052311Sjkh /* parent; assume fdopen can't fail... */ 2062311Sjkh if (*type == 'r') { 2072311Sjkh iop = fdopen(pdes[0], type); 2082311Sjkh (void)close(pdes[1]); 2092311Sjkh } else { 2102311Sjkh iop = fdopen(pdes[1], type); 2112311Sjkh (void)close(pdes[0]); 2122311Sjkh } 2132311Sjkh pids[fileno(iop)] = pid; 2142311Sjkh 2152311Sjkhpfree: 2162311Sjkh#if WANT_GLOBBING 2172311Sjkh for (argc = 1; argv[argc] != NULL; argc++) { 2182311Sjkh/* blkfree((char **)argv[argc]); */ 2192311Sjkh free((char *)argv[argc]); 2202311Sjkh } 2212311Sjkh#endif 2222311Sjkh return(iop); 2232311Sjkh} 2242311Sjkh 2252311Sjkhint 2262311Sjkhcron_pclose(iop) 2272311Sjkh FILE *iop; 2282311Sjkh{ 2292311Sjkh register int fdes; 2302311Sjkh int omask; 2312311Sjkh WAIT_T stat_loc; 2322311Sjkh PID_T pid; 2332311Sjkh 2342311Sjkh /* 2352311Sjkh * pclose returns -1 if stream is not associated with a 2362311Sjkh * `popened' command, or, if already `pclosed'. 2372311Sjkh */ 2382311Sjkh if (pids == 0 || pids[fdes = fileno(iop)] == 0) 2392311Sjkh return(-1); 2402311Sjkh (void)fclose(iop); 2412311Sjkh omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); 2422311Sjkh while ((pid = wait(&stat_loc)) != pids[fdes] && pid != -1) 2432311Sjkh ; 2442311Sjkh (void)sigsetmask(omask); 2452311Sjkh pids[fdes] = 0; 2462311Sjkh return (pid == -1 ? -1 : WEXITSTATUS(stat_loc)); 2472311Sjkh} 248