popen.c
上传用户:zibowangxu
上传日期:2007-01-04
资源大小:331k
文件大小:7k
源码类别:

Ftp客户端

开发平台:

Unix_Linux

  1. /****************************************************************************    
  2.   Copyright (c) 1999 WU-FTPD Development Group.  
  3.   All rights reserved.
  4.    
  5.   Portions Copyright (c) 1980, 1985, 1988, 1989, 1990, 1991, 1993, 1994  
  6.     The Regents of the University of California. 
  7.   Portions Copyright (c) 1993, 1994 Washington University in Saint Louis.  
  8.   Portions Copyright (c) 1996, 1998 Berkeley Software Design, Inc.  
  9.   Portions Copyright (c) 1989 Massachusetts Institute of Technology.  
  10.   Portions Copyright (c) 1998 Sendmail, Inc.  
  11.   Portions Copyright (c) 1983, 1995, 1996, 1997 Eric P.  Allman.  
  12.   Portions Copyright (c) 1997 by Stan Barber.  
  13.   Portions Copyright (c) 1997 by Kent Landfield.  
  14.   Portions Copyright (c) 1991, 1992, 1993, 1994, 1995, 1996, 1997  
  15.     Free Software Foundation, Inc.    
  16.    
  17.   Use and distribution of this software and its source code are governed   
  18.   by the terms and conditions of the WU-FTPD Software License ("LICENSE").  
  19.    
  20.   If you did not receive a copy of the license, it may be obtained online  
  21.   at http://www.wu-ftpd.org/license.html.  
  22.    
  23.   $Id: popen.c,v 1.15 1999/10/03 13:13:09 wuftpd Exp $  
  24.    
  25. ****************************************************************************/
  26. #include "config.h"
  27. #include <sys/types.h>
  28. #include <sys/wait.h>
  29. #include <signal.h>
  30. #include <stdio.h>
  31. #include <string.h>
  32. #if defined(HAVE_FCNTL_H)
  33. #include <fcntl.h>
  34. #endif
  35. #ifdef HAVE_GETRLIMIT
  36. #ifdef TIME_WITH_SYS_TIME
  37. #include <time.h>
  38. #include <sys/time.h>
  39. #else
  40. #ifdef HAVE_SYS_TIME_H
  41. #include <sys/time.h>
  42. #else
  43. #include <time.h>
  44. #endif
  45. #endif
  46. #include <sys/resource.h>
  47. #endif
  48. #include "pathnames.h"
  49. #include "proto.h"
  50. /* 
  51.  * Special version of popen which avoids call to shell.  This insures noone
  52.  * may create a pipe to a hidden program as a side effect of a list or dir
  53.  * command. 
  54.  */
  55. static int *pids;
  56. static int fds;
  57. #define MAX_ARGV 100
  58. #define MAX_GARGV 1000
  59. FILE *ftpd_popen(char *program, char *type, int closestderr)
  60. {
  61.     register char *cp;
  62.     FILE *iop;
  63.     int argc, gargc, pdes[2], pid, i, devnullfd;
  64.     char **pop, *argv[MAX_ARGV], *gargv[MAX_GARGV], *vv[2];
  65.     extern char **ftpglob(register char *v);
  66.     extern char **copyblk(register char **v);
  67.     extern char *strspl(register char *cp, register char *dp);
  68.     extern char *globerr;
  69. #ifdef HAVE_GETRLIMIT
  70.     struct rlimit rlp;
  71.     rlp.rlim_cur = rlp.rlim_max = RLIM_INFINITY;
  72.     if (getrlimit(RLIMIT_NOFILE, &rlp))
  73. return (NULL);
  74.     fds = rlp.rlim_cur;
  75. #else
  76. #ifdef HAVE_GETDTABLESIZE
  77.     if ((fds = getdtablesize()) <= 0)
  78. return (NULL);
  79. #else
  80. #ifdef HAVE_SYSCONF
  81.     fds = sysconf(_SC_OPEN_MAX);
  82. #else
  83. #ifdef OPEN_MAX
  84.     fds = OPEN_MAX; /* need to include limits.h somehow */
  85. #else
  86.     fds = 31; /* XXX -- magic cookie */
  87. #endif
  88. #endif
  89. #endif
  90. #endif
  91.     if ((*type != 'r' && *type != 'w') || type[1])
  92. return (NULL);
  93.     if (!pids) {
  94. pids = (int *) calloc(fds, sizeof(int));
  95. if (pids == NULL)
  96.     return (NULL);
  97.     }
  98.     if (pipe(pdes) < 0)
  99. return (NULL);
  100.     (void) memset((void *) argv, 0, sizeof(argv));
  101.     /* empty the array */
  102.     memset((char *) argv, '', sizeof(argv));
  103.     /* break up string into pieces */
  104.     for (argc = 0, cp = program; argc < MAX_ARGV - 1; cp = NULL)
  105. if (!(argv[argc++] = strtok(cp, " tn")))
  106.     break;
  107.     /* glob each piece */
  108.     gargv[0] = argv[0];
  109.     for (gargc = argc = 1; argc < MAX_ARGV && argv[argc]; argc++) {
  110. if (!(pop = ftpglob(argv[argc])) || globerr != NULL) { /* globbing failed */
  111.     vv[0] = strspl(argv[argc], "");
  112.     vv[1] = NULL;
  113.     pop = copyblk(vv);
  114. }
  115. argv[argc] = (char *) pop; /* save to free later */
  116. while (*pop && gargc < (MAX_GARGV - 1))
  117.     gargv[gargc++] = *pop++;
  118.     }
  119.     gargv[gargc] = NULL;
  120. #ifdef SIGCHLD
  121.     (void) signal(SIGCHLD, SIG_DFL);
  122. #endif
  123.     iop = NULL;
  124.     switch (pid = vfork()) {
  125.     case -1: /* error */
  126. (void) close(pdes[0]);
  127. (void) close(pdes[1]);
  128. goto pfree;
  129. /* NOTREACHED */
  130.     case 0: /* child */
  131. if (*type == 'r') {
  132.     if (pdes[1] != 1) {
  133. dup2(pdes[1], 1);
  134. if (closestderr) {
  135.     (void) close(2);
  136.     /* stderr output is written to fd 2, so make sure it isn't
  137.      * available to be assigned to another file */
  138.     if ((devnullfd = open(_PATH_DEVNULL, O_RDWR)) != -1) {
  139. if (devnullfd != 2) {
  140.     dup2(devnullfd, 2);
  141.     (void) close(devnullfd);
  142. }
  143.     }
  144. }
  145. else
  146.     dup2(pdes[1], 2); /* stderr, too! */
  147. (void) close(pdes[1]);
  148.     }
  149.     (void) close(pdes[0]);
  150. }
  151. else {
  152.     if (pdes[0] != 0) {
  153. dup2(pdes[0], 0);
  154. (void) close(pdes[0]);
  155.     }
  156.     (void) close(pdes[1]);
  157. }
  158. for (i = 3; i < fds; i++)
  159.     close(i);
  160. /* begin CERT suggested fixes */
  161. close(0);
  162. i = geteuid();
  163. delay_signaling(); /* we can't allow any signals while euid==0: kinch */
  164. seteuid(0);
  165. setgid(getegid());
  166. setuid(i);
  167. enable_signaling(); /* we can allow signals once again: kinch */
  168. /* end CERT suggested fixes */
  169. execv(gargv[0], gargv);
  170. _exit(1);
  171.     }
  172.     /* parent; assume fdopen can't fail...  */
  173.     if (*type == 'r') {
  174. iop = fdopen(pdes[0], type);
  175. (void) close(pdes[1]);
  176.     }
  177.     else {
  178. iop = fdopen(pdes[1], type);
  179. (void) close(pdes[0]);
  180.     }
  181.     pids[fileno(iop)] = pid;
  182.   pfree:for (argc = 1; argc < MAX_ARGV && argv[argc]; argc++) {
  183. blkfree((char **) argv[argc]);
  184. free((char *) argv[argc]);
  185.     }
  186.     return (iop);
  187. }
  188. int ftpd_pclose(FILE *iop)
  189. {
  190.     register int fdes;
  191.     int pid;
  192. #if defined(HAVE_SIGPROCMASK) || (defined(SVR4) && !defined(AUTOCONF))
  193.     sigset_t sig, omask;
  194.     int stat_loc;
  195.     sigemptyset(&sig);
  196.     sigaddset(&sig, SIGINT);
  197.     sigaddset(&sig, SIGQUIT);
  198.     sigaddset(&sig, SIGHUP);
  199. #elif defined (_OSF_SOURCE)
  200.     int omask;
  201.     int status;
  202. #else
  203.     int omask;
  204.     union wait stat_loc;
  205. #endif
  206.     /* pclose returns -1 if stream is not associated with a `popened'
  207.      * command, or, if already `pclosed'. */
  208.     if (pids == 0 || pids[fdes = fileno(iop)] == 0)
  209. return (-1);
  210.     (void) fclose(iop);
  211. #if defined(HAVE_SIGPROCMASK) || (!defined(AUTOCONF) && defined(SVR4))
  212.     sigprocmask(SIG_BLOCK, &sig, &omask);
  213. #else
  214.     omask = sigblock(sigmask(SIGINT) | sigmask(SIGQUIT) | sigmask(SIGHUP));
  215. #endif
  216. #if (!defined(HAVE_SIGPROCMASK) || (!defined(SVR4) && !defined(AUTOCONF))) && defined (_OSF_SOURCE)
  217.     while ((pid = wait(&status)) != pids[fdes] && pid != -1);
  218. #elif ! defined(NeXT)
  219.     while ((pid = wait((int *) &stat_loc)) != pids[fdes] && pid != -1);
  220. #else
  221.     while ((pid = wait(&stat_loc)) != pids[fdes] && pid != -1);
  222. #endif
  223.     pids[fdes] = 0;
  224. #ifdef SIGCHLD
  225.     (void) signal(SIGCHLD, SIG_IGN);
  226. #endif
  227. #if defined(HAVE_SIGPROCMASK) || (defined(SVR4) && !defined(AUTOCONF))
  228.     sigprocmask(SIG_SETMASK, &omask, (sigset_t *) NULL);
  229.     return (pid == -1 ? -1 : WEXITSTATUS(stat_loc));
  230. #else
  231.     (void) sigsetmask(omask);
  232. #ifdef _OSF_SOURCE
  233.     return (pid == -1 ? -1 : status);
  234. #elif defined(LINUX)
  235.     return (pid == -1 ? -1 : WEXITSTATUS(stat_loc));
  236. #else
  237.     return (pid == -1 ? -1 : stat_loc.w_status);
  238. #endif
  239. #endif
  240. }