LCOV - code coverage report
Current view: top level - g10 - exec.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 226 0.0 %
Date: 2016-11-29 15:00:56 Functions: 0 6 0.0 %

          Line data    Source code
       1             : /* exec.c - generic call-a-program code
       2             :  * Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
       3             :  *
       4             :  * This file is part of GnuPG.
       5             :  *
       6             :  * GnuPG is free software; you can redistribute it and/or modify
       7             :  * it under the terms of the GNU General Public License as published by
       8             :  * the Free Software Foundation; either version 3 of the License, or
       9             :  * (at your option) any later version.
      10             :  *
      11             :  * GnuPG is distributed in the hope that it will be useful,
      12             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :  * GNU General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License
      17             :  * along with this program; if not, see <https://www.gnu.org/licenses/>.
      18             :  */
      19             : 
      20             : /*
      21             :    FIXME: We should replace most code in this module by our
      22             :    spawn implementation from common/exechelp.c.
      23             :  */
      24             : 
      25             : 
      26             : #include <config.h>
      27             : #include <stdlib.h>
      28             : #include <stdarg.h>
      29             : #include <stdio.h>
      30             : #include <sys/stat.h>
      31             : #include <sys/types.h>
      32             : #ifndef EXEC_TEMPFILE_ONLY
      33             : #include <sys/wait.h>
      34             : #endif
      35             : #ifdef HAVE_DOSISH_SYSTEM
      36             : # ifdef HAVE_WINSOCK2_H
      37             : #  include <winsock2.h>
      38             : # endif
      39             : # include <windows.h>
      40             : #endif
      41             : #include <fcntl.h>
      42             : #include <unistd.h>
      43             : #include <string.h>
      44             : #include <errno.h>
      45             : 
      46             : #include "gpg.h"
      47             : #include "options.h"
      48             : #include "i18n.h"
      49             : #include "iobuf.h"
      50             : #include "util.h"
      51             : #include "membuf.h"
      52             : #include "sysutils.h"
      53             : #include "exec.h"
      54             : 
      55             : #ifdef NO_EXEC
      56             : int
      57             : exec_write(struct exec_info **info,const char *program,
      58             :                const char *args_in,const char *name,int writeonly,int binary)
      59             : {
      60             :   log_error(_("no remote program execution supported\n"));
      61             :   return GPG_ERR_GENERAL;
      62             : }
      63             : 
      64             : int
      65             : exec_read(struct exec_info *info) { return GPG_ERR_GENERAL; }
      66             : int
      67             : exec_finish(struct exec_info *info) { return GPG_ERR_GENERAL; }
      68             : int
      69             : set_exec_path(const char *path) { return GPG_ERR_GENERAL; }
      70             : 
      71             : #else /* ! NO_EXEC */
      72             : 
      73             : #if defined (_WIN32)
      74             : /* This is a nicer system() for windows that waits for programs to
      75             :    return before returning control to the caller.  I hate helpful
      76             :    computers. */
      77             : static int
      78             : w32_system(const char *command)
      79             : {
      80             : #ifdef HAVE_W32CE_SYSTEM
      81             : #warning Change this code to use common/exechelp.c
      82             : #else
      83             :   PROCESS_INFORMATION pi;
      84             :   STARTUPINFO si;
      85             :   char *string;
      86             : 
      87             :   /* We must use a copy of the command as CreateProcess modifies this
      88             :      argument. */
      89             :   string=xstrdup(command);
      90             : 
      91             :   memset(&pi,0,sizeof(pi));
      92             :   memset(&si,0,sizeof(si));
      93             :   si.cb=sizeof(si);
      94             : 
      95             :   if(!CreateProcess(NULL,string,NULL,NULL,FALSE,
      96             :                     DETACHED_PROCESS,
      97             :                     NULL,NULL,&si,&pi))
      98             :     return -1;
      99             : 
     100             :   /* Wait for the child to exit */
     101             :   WaitForSingleObject(pi.hProcess,INFINITE);
     102             : 
     103             :   CloseHandle(pi.hProcess);
     104             :   CloseHandle(pi.hThread);
     105             :   xfree(string);
     106             : 
     107             :   return 0;
     108             : #endif
     109             : }
     110             : #endif
     111             : 
     112             : /* Replaces current $PATH */
     113             : int
     114           0 : set_exec_path(const char *path)
     115             : {
     116             : #ifdef HAVE_W32CE_SYSTEM
     117             : #warning Change this code to use common/exechelp.c
     118             : #else
     119             :   char *p;
     120             : 
     121           0 :   p=xmalloc(5+strlen(path)+1);
     122           0 :   strcpy(p,"PATH=");
     123           0 :   strcat(p,path);
     124             : 
     125           0 :   if(DBG_EXTPROG)
     126           0 :     log_debug("set_exec_path: %s\n",p);
     127             : 
     128             :   /* Notice that path is never freed.  That is intentional due to the
     129             :      way putenv() works.  This leaks a few bytes if we call
     130             :      set_exec_path multiple times. */
     131             : 
     132           0 :   if(putenv(p)!=0)
     133           0 :     return GPG_ERR_GENERAL;
     134             :   else
     135           0 :     return 0;
     136             : #endif
     137             : }
     138             : 
     139             : /* Makes a temp directory and filenames */
     140             : static int
     141           0 : make_tempdir(struct exec_info *info)
     142             : {
     143           0 :   char *tmp=opt.temp_dir,*namein=info->name,*nameout;
     144             : 
     145           0 :   if(!namein)
     146           0 :     namein=info->flags.binary?"tempin" EXTSEP_S "bin":"tempin" EXTSEP_S "txt";
     147             : 
     148           0 :   nameout=info->flags.binary?"tempout" EXTSEP_S "bin":"tempout" EXTSEP_S "txt";
     149             : 
     150             :   /* Make up the temp dir and files in case we need them */
     151             : 
     152           0 :   if(tmp==NULL)
     153             :     {
     154             : #if defined (_WIN32)
     155             :       int err;
     156             : 
     157             :       tmp=xmalloc(MAX_PATH+2);
     158             :       err=GetTempPath(MAX_PATH+1,tmp);
     159             :       if(err==0 || err>MAX_PATH+1)
     160             :         strcpy(tmp,"c:\\windows\\temp");
     161             :       else
     162             :         {
     163             :           int len=strlen(tmp);
     164             : 
     165             :           /* GetTempPath may return with \ on the end */
     166             :           while(len>0 && tmp[len-1]=='\\')
     167             :             {
     168             :               tmp[len-1]='\0';
     169             :               len--;
     170             :             }
     171             :         }
     172             : #else /* More unixish systems */
     173           0 :       tmp=getenv("TMPDIR");
     174           0 :       if(tmp==NULL)
     175             :         {
     176           0 :           tmp=getenv("TMP");
     177           0 :           if(tmp==NULL)
     178             :             {
     179             : #ifdef __riscos__
     180             :               tmp="<Wimp$ScrapDir>.GnuPG";
     181             :               mkdir(tmp,0700); /* Error checks occur later on */
     182             : #else
     183           0 :               tmp="/tmp";
     184             : #endif
     185             :             }
     186             :         }
     187             : #endif
     188             :     }
     189             : 
     190           0 :   info->tempdir=xmalloc(strlen(tmp)+strlen(DIRSEP_S)+10+1);
     191             : 
     192           0 :   sprintf(info->tempdir,"%s" DIRSEP_S "gpg-XXXXXX",tmp);
     193             : 
     194             : #if defined (_WIN32)
     195             :   xfree(tmp);
     196             : #endif
     197             : 
     198           0 :   if (!gnupg_mkdtemp(info->tempdir))
     199           0 :     log_error(_("can't create directory '%s': %s\n"),
     200           0 :               info->tempdir,strerror(errno));
     201             :   else
     202             :     {
     203           0 :       info->flags.madedir=1;
     204             : 
     205           0 :       info->tempfile_in=xmalloc(strlen(info->tempdir)+
     206             :                                 strlen(DIRSEP_S)+strlen(namein)+1);
     207           0 :       sprintf(info->tempfile_in,"%s" DIRSEP_S "%s",info->tempdir,namein);
     208             : 
     209           0 :       if(!info->flags.writeonly)
     210             :         {
     211           0 :           info->tempfile_out=xmalloc(strlen(info->tempdir)+
     212             :                                      strlen(DIRSEP_S)+strlen(nameout)+1);
     213           0 :           sprintf(info->tempfile_out,"%s" DIRSEP_S "%s",info->tempdir,nameout);
     214             :         }
     215             :     }
     216             : 
     217           0 :   return info->flags.madedir? 0 : GPG_ERR_GENERAL;
     218             : }
     219             : 
     220             : /* Expands %i and %o in the args to the full temp files within the
     221             :    temp directory. */
     222             : static int
     223           0 : expand_args(struct exec_info *info,const char *args_in)
     224             : {
     225           0 :   const char *ch = args_in;
     226             :   membuf_t command;
     227             : 
     228           0 :   info->flags.use_temp_files=0;
     229           0 :   info->flags.keep_temp_files=0;
     230             : 
     231           0 :   if(DBG_EXTPROG)
     232           0 :     log_debug("expanding string \"%s\"\n",args_in);
     233             : 
     234           0 :   init_membuf (&command, 100);
     235             : 
     236           0 :   while(*ch!='\0')
     237             :     {
     238           0 :       if(*ch=='%')
     239             :         {
     240           0 :           char *append=NULL;
     241             : 
     242           0 :           ch++;
     243             : 
     244           0 :           switch(*ch)
     245             :             {
     246             :             case 'O':
     247           0 :               info->flags.keep_temp_files=1;
     248             :               /* fall through */
     249             : 
     250             :             case 'o': /* out */
     251           0 :               if(!info->flags.madedir)
     252             :                 {
     253           0 :                   if(make_tempdir(info))
     254           0 :                     goto fail;
     255             :                 }
     256           0 :               append=info->tempfile_out;
     257           0 :               info->flags.use_temp_files=1;
     258           0 :               break;
     259             : 
     260             :             case 'I':
     261           0 :               info->flags.keep_temp_files=1;
     262             :               /* fall through */
     263             : 
     264             :             case 'i': /* in */
     265           0 :               if(!info->flags.madedir)
     266             :                 {
     267           0 :                   if(make_tempdir(info))
     268           0 :                     goto fail;
     269             :                 }
     270           0 :               append=info->tempfile_in;
     271           0 :               info->flags.use_temp_files=1;
     272           0 :               break;
     273             : 
     274             :             case '%':
     275           0 :               append="%";
     276           0 :               break;
     277             :             }
     278             : 
     279           0 :           if(append)
     280           0 :             put_membuf_str (&command, append);
     281             :         }
     282             :       else
     283           0 :         put_membuf (&command, ch, 1);
     284             : 
     285           0 :       ch++;
     286             :     }
     287             : 
     288           0 :   put_membuf (&command, "", 1);  /* Terminate string.  */
     289             : 
     290           0 :   info->command = get_membuf (&command, NULL);
     291           0 :   if (!info->command)
     292           0 :     return gpg_error_from_syserror ();
     293             : 
     294           0 :   if(DBG_EXTPROG)
     295           0 :     log_debug("args expanded to \"%s\", use %u, keep %u\n",info->command,
     296           0 :               info->flags.use_temp_files,info->flags.keep_temp_files);
     297             : 
     298           0 :   return 0;
     299             : 
     300             :  fail:
     301           0 :   xfree (get_membuf (&command, NULL));
     302           0 :   return GPG_ERR_GENERAL;
     303             : }
     304             : 
     305             : /* Either handles the tempfile creation, or the fork/exec.  If it
     306             :    returns ok, then info->tochild is a FILE * that can be written to.
     307             :    The rules are: if there are no args, then it's a fork/exec/pipe.
     308             :    If there are args, but no tempfiles, then it's a fork/exec/pipe via
     309             :    shell -c.  If there are tempfiles, then it's a system. */
     310             : 
     311             : int
     312           0 : exec_write(struct exec_info **info,const char *program,
     313             :            const char *args_in,const char *name,int writeonly,int binary)
     314             : {
     315           0 :   int ret = GPG_ERR_GENERAL;
     316             : 
     317           0 :   if(opt.exec_disable && !opt.no_perm_warn)
     318             :     {
     319           0 :       log_info(_("external program calls are disabled due to unsafe "
     320             :                  "options file permissions\n"));
     321             : 
     322           0 :       return ret;
     323             :     }
     324             : 
     325             : #if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
     326             :   /* There should be no way to get to this spot while still carrying
     327             :      setuid privs.  Just in case, bomb out if we are. */
     328             :   if ( getuid () != geteuid ())
     329             :     BUG ();
     330             : #endif
     331             : 
     332           0 :   if(program==NULL && args_in==NULL)
     333           0 :     BUG();
     334             : 
     335           0 :   *info=xmalloc_clear(sizeof(struct exec_info));
     336             : 
     337           0 :   if(name)
     338           0 :     (*info)->name=xstrdup(name);
     339           0 :   (*info)->flags.binary=binary;
     340           0 :   (*info)->flags.writeonly=writeonly;
     341             : 
     342             :   /* Expand the args, if any */
     343           0 :   if(args_in && expand_args(*info,args_in))
     344           0 :     goto fail;
     345             : 
     346             : #ifdef EXEC_TEMPFILE_ONLY
     347             :   if(!(*info)->flags.use_temp_files)
     348             :     {
     349             :       log_error(_("this platform requires temporary files when calling"
     350             :                   " external programs\n"));
     351             :       goto fail;
     352             :     }
     353             : 
     354             : #else /* !EXEC_TEMPFILE_ONLY */
     355             : 
     356             :   /* If there are no args, or there are args, but no temp files, we
     357             :      can use fork/exec/pipe */
     358           0 :   if(args_in==NULL || (*info)->flags.use_temp_files==0)
     359             :     {
     360             :       int to[2],from[2];
     361             : 
     362           0 :       if(pipe(to)==-1)
     363           0 :         goto fail;
     364             : 
     365           0 :       if(pipe(from)==-1)
     366             :         {
     367           0 :           close(to[0]);
     368           0 :           close(to[1]);
     369           0 :           goto fail;
     370             :         }
     371             : 
     372           0 :       if(((*info)->child=fork())==-1)
     373             :         {
     374           0 :           close(to[0]);
     375           0 :           close(to[1]);
     376           0 :           close(from[0]);
     377           0 :           close(from[1]);
     378           0 :           goto fail;
     379             :         }
     380             : 
     381           0 :       if((*info)->child==0)
     382             :         {
     383           0 :           char *shell=getenv("SHELL");
     384             : 
     385           0 :           if(shell==NULL)
     386           0 :             shell="/bin/sh";
     387             : 
     388             :           /* I'm the child */
     389             : 
     390             :           /* If the program isn't going to respond back, they get to
     391             :              keep their stdout/stderr */
     392           0 :           if(!(*info)->flags.writeonly)
     393             :             {
     394             :               /* implied close of STDERR */
     395           0 :               if(dup2(STDOUT_FILENO,STDERR_FILENO)==-1)
     396           0 :                 _exit(1);
     397             : 
     398             :               /* implied close of STDOUT */
     399           0 :               close(from[0]);
     400           0 :               if(dup2(from[1],STDOUT_FILENO)==-1)
     401           0 :                 _exit(1);
     402             :             }
     403             : 
     404             :           /* implied close of STDIN */
     405           0 :           close(to[1]);
     406           0 :           if(dup2(to[0],STDIN_FILENO)==-1)
     407           0 :             _exit(1);
     408             : 
     409           0 :           if(args_in==NULL)
     410             :             {
     411           0 :               if(DBG_EXTPROG)
     412           0 :                 log_debug("execlp: %s\n",program);
     413             : 
     414           0 :               execlp(program,program,(void *)NULL);
     415             :             }
     416             :           else
     417             :             {
     418           0 :               if(DBG_EXTPROG)
     419           0 :                 log_debug("execlp: %s -c %s\n",shell,(*info)->command);
     420             : 
     421           0 :               execlp(shell,shell,"-c",(*info)->command,(void *)NULL);
     422             :             }
     423             : 
     424             :           /* If we get this far the exec failed.  Clean up and return. */
     425             : 
     426           0 :           if(args_in==NULL)
     427           0 :             log_error(_("unable to execute program '%s': %s\n"),
     428           0 :                       program,strerror(errno));
     429             :           else
     430           0 :             log_error(_("unable to execute shell '%s': %s\n"),
     431           0 :                       shell,strerror(errno));
     432             : 
     433             :           /* This mimics the POSIX sh behavior - 127 means "not found"
     434             :              from the shell. */
     435           0 :           if(errno==ENOENT)
     436           0 :             _exit(127);
     437             : 
     438           0 :           _exit(1);
     439             :         }
     440             : 
     441             :       /* I'm the parent */
     442             : 
     443           0 :       close(to[0]);
     444             : 
     445           0 :       (*info)->tochild=fdopen(to[1],binary?"wb":"w");
     446           0 :       if((*info)->tochild==NULL)
     447             :         {
     448           0 :           ret = gpg_error_from_syserror ();
     449           0 :           close(to[1]);
     450           0 :           goto fail;
     451             :         }
     452             : 
     453           0 :       close(from[1]);
     454             : 
     455           0 :       (*info)->fromchild=iobuf_fdopen(from[0],"r");
     456           0 :       if((*info)->fromchild==NULL)
     457             :         {
     458           0 :           ret = gpg_error_from_syserror ();
     459           0 :           close(from[0]);
     460           0 :           goto fail;
     461             :         }
     462             : 
     463             :       /* fd iobufs are cached! */
     464           0 :       iobuf_ioctl((*info)->fromchild, IOBUF_IOCTL_NO_CACHE, 1, NULL);
     465             : 
     466           0 :       return 0;
     467             :     }
     468             : #endif /* !EXEC_TEMPFILE_ONLY */
     469             : 
     470           0 :   if(DBG_EXTPROG)
     471           0 :     log_debug("using temp file '%s'\n",(*info)->tempfile_in);
     472             : 
     473             :   /* It's not fork/exec/pipe, so create a temp file */
     474           0 :   if( is_secured_filename ((*info)->tempfile_in) )
     475             :     {
     476           0 :       (*info)->tochild = NULL;
     477           0 :       gpg_err_set_errno (EPERM);
     478             :     }
     479             :   else
     480           0 :     (*info)->tochild=fopen((*info)->tempfile_in,binary?"wb":"w");
     481           0 :   if((*info)->tochild==NULL)
     482             :     {
     483           0 :       ret = gpg_error_from_syserror ();
     484           0 :       log_error(_("can't create '%s': %s\n"),
     485           0 :                 (*info)->tempfile_in,strerror(errno));
     486           0 :       goto fail;
     487             :     }
     488             : 
     489           0 :   ret=0;
     490             : 
     491             :  fail:
     492           0 :   if (ret)
     493             :     {
     494           0 :       xfree (*info);
     495           0 :       *info = NULL;
     496             :     }
     497           0 :   return ret;
     498             : }
     499             : 
     500             : int
     501           0 : exec_read(struct exec_info *info)
     502             : {
     503           0 :   int ret = GPG_ERR_GENERAL;
     504             : 
     505           0 :   fclose(info->tochild);
     506           0 :   info->tochild=NULL;
     507             : 
     508           0 :   if(info->flags.use_temp_files)
     509             :     {
     510           0 :       if(DBG_EXTPROG)
     511           0 :         log_debug("system() command is %s\n",info->command);
     512             : 
     513             : #if defined (_WIN32)
     514             :       info->progreturn=w32_system(info->command);
     515             : #else
     516           0 :       info->progreturn=system(info->command);
     517             : #endif
     518             : 
     519           0 :       if(info->progreturn==-1)
     520             :         {
     521           0 :           log_error(_("system error while calling external program: %s\n"),
     522           0 :                     strerror(errno));
     523           0 :           info->progreturn=127;
     524           0 :           goto fail;
     525             :         }
     526             : 
     527             : #if defined(WIFEXITED) && defined(WEXITSTATUS)
     528           0 :       if(WIFEXITED(info->progreturn))
     529           0 :         info->progreturn=WEXITSTATUS(info->progreturn);
     530             :       else
     531             :         {
     532           0 :           log_error(_("unnatural exit of external program\n"));
     533           0 :           info->progreturn=127;
     534           0 :           goto fail;
     535             :         }
     536             : #else
     537             :       /* If we don't have the macros, do the best we can. */
     538             :       info->progreturn = (info->progreturn & 0xff00) >> 8;
     539             : #endif
     540             : 
     541             :       /* 127 is the magic value returned from system() to indicate
     542             :          that the shell could not be executed, or from /bin/sh to
     543             :          indicate that the program could not be executed. */
     544             : 
     545           0 :       if(info->progreturn==127)
     546             :         {
     547           0 :           log_error(_("unable to execute external program\n"));
     548           0 :           goto fail;
     549             :         }
     550             : 
     551           0 :       if(!info->flags.writeonly)
     552             :         {
     553           0 :           info->fromchild=iobuf_open(info->tempfile_out);
     554           0 :           if (info->fromchild
     555           0 :               && is_secured_file (iobuf_get_fd (info->fromchild)))
     556             :             {
     557           0 :               iobuf_close (info->fromchild);
     558           0 :               info->fromchild = NULL;
     559           0 :               gpg_err_set_errno (EPERM);
     560             :             }
     561           0 :           if(info->fromchild==NULL)
     562             :             {
     563           0 :               ret = gpg_error_from_syserror ();
     564           0 :               log_error(_("unable to read external program response: %s\n"),
     565           0 :                         strerror(errno));
     566           0 :               goto fail;
     567             :             }
     568             : 
     569             :           /* Do not cache this iobuf on close */
     570           0 :           iobuf_ioctl(info->fromchild, IOBUF_IOCTL_NO_CACHE, 1, NULL);
     571             :         }
     572             :     }
     573             : 
     574           0 :   ret=0;
     575             : 
     576             :  fail:
     577           0 :   return ret;
     578             : }
     579             : 
     580             : int
     581           0 : exec_finish(struct exec_info *info)
     582             : {
     583           0 :   int ret=info->progreturn;
     584             : 
     585           0 :   if(info->fromchild)
     586           0 :     iobuf_close(info->fromchild);
     587             : 
     588           0 :   if(info->tochild)
     589           0 :     fclose(info->tochild);
     590             : 
     591             : #ifndef EXEC_TEMPFILE_ONLY
     592           0 :   if(info->child>0)
     593             :     {
     594           0 :       if(waitpid(info->child,&info->progreturn,0)!=0 &&
     595           0 :          WIFEXITED(info->progreturn))
     596           0 :         ret=WEXITSTATUS(info->progreturn);
     597             :       else
     598             :         {
     599           0 :           log_error(_("unnatural exit of external program\n"));
     600           0 :           ret=127;
     601             :         }
     602             :     }
     603             : #endif
     604             : 
     605           0 :   if(info->flags.madedir && !info->flags.keep_temp_files)
     606             :     {
     607           0 :       if(info->tempfile_in)
     608             :         {
     609           0 :           if(unlink(info->tempfile_in)==-1)
     610           0 :             log_info(_("WARNING: unable to remove tempfile (%s) '%s': %s\n"),
     611           0 :                      "in",info->tempfile_in,strerror(errno));
     612             :         }
     613             : 
     614           0 :       if(info->tempfile_out)
     615             :         {
     616           0 :           if(unlink(info->tempfile_out)==-1)
     617           0 :             log_info(_("WARNING: unable to remove tempfile (%s) '%s': %s\n"),
     618           0 :                      "out",info->tempfile_out,strerror(errno));
     619             :         }
     620             : 
     621           0 :       if(rmdir(info->tempdir)==-1)
     622           0 :         log_info(_("WARNING: unable to remove temp directory '%s': %s\n"),
     623           0 :                  info->tempdir,strerror(errno));
     624             :     }
     625             : 
     626           0 :   xfree(info->command);
     627           0 :   xfree(info->name);
     628           0 :   xfree(info->tempdir);
     629           0 :   xfree(info->tempfile_in);
     630           0 :   xfree(info->tempfile_out);
     631           0 :   xfree(info);
     632             : 
     633           0 :   return ret;
     634             : }
     635             : #endif /* ! NO_EXEC */

Generated by: LCOV version 1.11