"Fossies" - the Fresh Open Source Software Archive

Member "gnupg-2.2.17/g10/exec.c" (17 May 2019, 16110 Bytes) of package /linux/misc/gnupg-2.2.17.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "exec.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 2.2.15_vs_2.2.16.

    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 "../common/i18n.h"
   49 #include "../common/iobuf.h"
   50 #include "../common/util.h"
   51 #include "../common/membuf.h"
   52 #include "../common/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   if (!strncmp (command, "!ShellExecute ", 14))
   81     {
   82       SHELLEXECUTEINFOW see;
   83       wchar_t *wname;
   84       int waitms;
   85 
   86       command = command + 14;
   87       while (spacep (command))
   88         command++;
   89       waitms = atoi (command);
   90       if (waitms < 0)
   91         waitms = 0;
   92       else if (waitms > 60*1000)
   93         waitms = 60000;
   94       while (*command && !spacep (command))
   95         command++;
   96       while (spacep (command))
   97         command++;
   98 
   99       wname = utf8_to_wchar (command);
  100       if (!wname)
  101         return -1;
  102 
  103       memset (&see, 0, sizeof see);
  104       see.cbSize = sizeof see;
  105       see.fMask = (SEE_MASK_NOCLOSEPROCESS
  106                    | SEE_MASK_NOASYNC
  107                    | SEE_MASK_FLAG_NO_UI
  108                    | SEE_MASK_NO_CONSOLE);
  109       see.lpVerb = L"open";
  110       see.lpFile = (LPCWSTR)wname;
  111       see.nShow = SW_SHOW;
  112 
  113       if (DBG_EXTPROG)
  114         log_debug ("running ShellExecuteEx(open,'%s')\n", command);
  115       if (!ShellExecuteExW (&see))
  116         {
  117           if (DBG_EXTPROG)
  118             log_debug ("ShellExecuteEx failed: rc=%d\n", (int)GetLastError ());
  119           xfree (wname);
  120           return -1;
  121         }
  122       if (DBG_EXTPROG)
  123         log_debug ("ShellExecuteEx succeeded (hProcess=%p,hInstApp=%d)\n",
  124                    see.hProcess, (int)see.hInstApp);
  125 
  126       if (!see.hProcess)
  127         {
  128           gnupg_usleep (waitms*1000);
  129           if (DBG_EXTPROG)
  130             log_debug ("ShellExecuteEx ready (wait=%dms)\n", waitms);
  131         }
  132       else
  133         {
  134           WaitForSingleObject (see.hProcess, INFINITE);
  135           if (DBG_EXTPROG)
  136             log_debug ("ShellExecuteEx ready\n");
  137         }
  138       CloseHandle (see.hProcess);
  139 
  140       xfree (wname);
  141     }
  142   else
  143     {
  144       char *string;
  145       PROCESS_INFORMATION pi;
  146       STARTUPINFO si;
  147 
  148       /* We must use a copy of the command as CreateProcess modifies
  149        * this argument. */
  150       string = xstrdup (command);
  151 
  152       memset (&pi, 0, sizeof(pi));
  153       memset (&si, 0, sizeof(si));
  154       si.cb = sizeof (si);
  155 
  156       if (!CreateProcess (NULL, string, NULL, NULL, FALSE,
  157                           DETACHED_PROCESS,
  158                           NULL, NULL, &si, &pi))
  159         return -1;
  160 
  161       /* Wait for the child to exit */
  162       WaitForSingleObject (pi.hProcess, INFINITE);
  163 
  164       CloseHandle (pi.hProcess);
  165       CloseHandle (pi.hThread);
  166       xfree (string);
  167     }
  168 
  169   return 0;
  170 }
  171 #endif /*_W32*/
  172 
  173 
  174 /* Replaces current $PATH */
  175 int
  176 set_exec_path(const char *path)
  177 {
  178 #ifdef HAVE_W32CE_SYSTEM
  179 #warning Change this code to use common/exechelp.c
  180 #else
  181   char *p;
  182 
  183   p=xmalloc(5+strlen(path)+1);
  184   strcpy(p,"PATH=");
  185   strcat(p,path);
  186 
  187   if(DBG_EXTPROG)
  188     log_debug("set_exec_path: %s\n",p);
  189 
  190   /* Notice that path is never freed.  That is intentional due to the
  191      way putenv() works.  This leaks a few bytes if we call
  192      set_exec_path multiple times. */
  193 
  194   if(putenv(p)!=0)
  195     return GPG_ERR_GENERAL;
  196   else
  197     return 0;
  198 #endif
  199 }
  200 
  201 /* Makes a temp directory and filenames */
  202 static int
  203 make_tempdir(struct exec_info *info)
  204 {
  205   char *tmp=opt.temp_dir,*namein=info->name,*nameout;
  206 
  207   if(!namein)
  208     namein=info->flags.binary?"tempin" EXTSEP_S "bin":"tempin" EXTSEP_S "txt";
  209 
  210   nameout=info->flags.binary?"tempout" EXTSEP_S "bin":"tempout" EXTSEP_S "txt";
  211 
  212   /* Make up the temp dir and files in case we need them */
  213 
  214   if(tmp==NULL)
  215     {
  216 #if defined (_WIN32)
  217       int err;
  218 
  219       tmp=xmalloc(MAX_PATH+2);
  220       err=GetTempPath(MAX_PATH+1,tmp);
  221       if(err==0 || err>MAX_PATH+1)
  222     strcpy(tmp,"c:\\windows\\temp");
  223       else
  224     {
  225       int len=strlen(tmp);
  226 
  227       /* GetTempPath may return with \ on the end */
  228       while(len>0 && tmp[len-1]=='\\')
  229         {
  230           tmp[len-1]='\0';
  231           len--;
  232         }
  233     }
  234 #else /* More unixish systems */
  235       tmp=getenv("TMPDIR");
  236       if(tmp==NULL)
  237     {
  238       tmp=getenv("TMP");
  239       if(tmp==NULL)
  240         {
  241 #ifdef __riscos__
  242           tmp="<Wimp$ScrapDir>.GnuPG";
  243           mkdir(tmp,0700); /* Error checks occur later on */
  244 #else
  245           tmp="/tmp";
  246 #endif
  247         }
  248     }
  249 #endif
  250     }
  251 
  252   info->tempdir=xmalloc(strlen(tmp)+strlen(DIRSEP_S)+10+1);
  253 
  254   sprintf(info->tempdir,"%s" DIRSEP_S "gpg-XXXXXX",tmp);
  255 
  256 #if defined (_WIN32)
  257   xfree(tmp);
  258 #endif
  259 
  260   if (!gnupg_mkdtemp(info->tempdir))
  261     log_error(_("can't create directory '%s': %s\n"),
  262           info->tempdir,strerror(errno));
  263   else
  264     {
  265       info->flags.madedir=1;
  266 
  267       info->tempfile_in=xmalloc(strlen(info->tempdir)+
  268                 strlen(DIRSEP_S)+strlen(namein)+1);
  269       sprintf(info->tempfile_in,"%s" DIRSEP_S "%s",info->tempdir,namein);
  270 
  271       if(!info->flags.writeonly)
  272     {
  273       info->tempfile_out=xmalloc(strlen(info->tempdir)+
  274                      strlen(DIRSEP_S)+strlen(nameout)+1);
  275       sprintf(info->tempfile_out,"%s" DIRSEP_S "%s",info->tempdir,nameout);
  276     }
  277     }
  278 
  279   return info->flags.madedir? 0 : GPG_ERR_GENERAL;
  280 }
  281 
  282 /* Expands %i and %o in the args to the full temp files within the
  283    temp directory. */
  284 static int
  285 expand_args(struct exec_info *info,const char *args_in)
  286 {
  287   const char *ch = args_in;
  288   membuf_t command;
  289 
  290   info->flags.use_temp_files=0;
  291   info->flags.keep_temp_files=0;
  292 
  293   if(DBG_EXTPROG)
  294     log_debug("expanding string \"%s\"\n",args_in);
  295 
  296   init_membuf (&command, 100);
  297 
  298   while(*ch!='\0')
  299     {
  300       if(*ch=='%')
  301     {
  302       char *append=NULL;
  303 
  304       ch++;
  305 
  306       switch(*ch)
  307         {
  308         case 'O':
  309           info->flags.keep_temp_files=1;
  310           /* fall through */
  311 
  312         case 'o': /* out */
  313           if(!info->flags.madedir)
  314         {
  315           if(make_tempdir(info))
  316             goto fail;
  317         }
  318           append=info->tempfile_out;
  319           info->flags.use_temp_files=1;
  320           break;
  321 
  322         case 'I':
  323           info->flags.keep_temp_files=1;
  324           /* fall through */
  325 
  326         case 'i': /* in */
  327           if(!info->flags.madedir)
  328         {
  329           if(make_tempdir(info))
  330             goto fail;
  331         }
  332           append=info->tempfile_in;
  333           info->flags.use_temp_files=1;
  334           break;
  335 
  336         case '%':
  337           append="%";
  338           break;
  339         }
  340 
  341       if(append)
  342             put_membuf_str (&command, append);
  343     }
  344       else
  345         put_membuf (&command, ch, 1);
  346 
  347       ch++;
  348     }
  349 
  350   put_membuf (&command, "", 1);  /* Terminate string.  */
  351 
  352   info->command = get_membuf (&command, NULL);
  353   if (!info->command)
  354     return gpg_error_from_syserror ();
  355 
  356   if(DBG_EXTPROG)
  357     log_debug("args expanded to \"%s\", use %u, keep %u\n",info->command,
  358           info->flags.use_temp_files,info->flags.keep_temp_files);
  359 
  360   return 0;
  361 
  362  fail:
  363   xfree (get_membuf (&command, NULL));
  364   return GPG_ERR_GENERAL;
  365 }
  366 
  367 /* Either handles the tempfile creation, or the fork/exec.  If it
  368    returns ok, then info->tochild is a FILE * that can be written to.
  369    The rules are: if there are no args, then it's a fork/exec/pipe.
  370    If there are args, but no tempfiles, then it's a fork/exec/pipe via
  371    shell -c.  If there are tempfiles, then it's a system. */
  372 
  373 int
  374 exec_write(struct exec_info **info,const char *program,
  375            const char *args_in,const char *name,int writeonly,int binary)
  376 {
  377   int ret = GPG_ERR_GENERAL;
  378 
  379   if(opt.exec_disable && !opt.no_perm_warn)
  380     {
  381       log_info(_("external program calls are disabled due to unsafe "
  382          "options file permissions\n"));
  383 
  384       return ret;
  385     }
  386 
  387 #if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
  388   /* There should be no way to get to this spot while still carrying
  389      setuid privs.  Just in case, bomb out if we are. */
  390   if ( getuid () != geteuid ())
  391     BUG ();
  392 #endif
  393 
  394   if(program==NULL && args_in==NULL)
  395     BUG();
  396 
  397   *info=xmalloc_clear(sizeof(struct exec_info));
  398 
  399   if(name)
  400     (*info)->name=xstrdup(name);
  401   (*info)->flags.binary=binary;
  402   (*info)->flags.writeonly=writeonly;
  403 
  404   /* Expand the args, if any */
  405   if(args_in && expand_args(*info,args_in))
  406     goto fail;
  407 
  408 #ifdef EXEC_TEMPFILE_ONLY
  409   if(!(*info)->flags.use_temp_files)
  410     {
  411       log_error(_("this platform requires temporary files when calling"
  412           " external programs\n"));
  413       goto fail;
  414     }
  415 
  416 #else /* !EXEC_TEMPFILE_ONLY */
  417 
  418   /* If there are no args, or there are args, but no temp files, we
  419      can use fork/exec/pipe */
  420   if(args_in==NULL || (*info)->flags.use_temp_files==0)
  421     {
  422       int to[2],from[2];
  423 
  424       if(pipe(to)==-1)
  425     goto fail;
  426 
  427       if(pipe(from)==-1)
  428     {
  429       close(to[0]);
  430       close(to[1]);
  431       goto fail;
  432     }
  433 
  434       if(((*info)->child=fork())==-1)
  435     {
  436       close(to[0]);
  437       close(to[1]);
  438       close(from[0]);
  439       close(from[1]);
  440       goto fail;
  441     }
  442 
  443       if((*info)->child==0)
  444     {
  445       char *shell=getenv("SHELL");
  446 
  447       if(shell==NULL)
  448         shell="/bin/sh";
  449 
  450       /* I'm the child */
  451 
  452       /* If the program isn't going to respond back, they get to
  453              keep their stdout/stderr */
  454       if(!(*info)->flags.writeonly)
  455         {
  456           /* implied close of STDERR */
  457           if(dup2(STDOUT_FILENO,STDERR_FILENO)==-1)
  458         _exit(1);
  459 
  460           /* implied close of STDOUT */
  461           close(from[0]);
  462           if(dup2(from[1],STDOUT_FILENO)==-1)
  463         _exit(1);
  464         }
  465 
  466       /* implied close of STDIN */
  467       close(to[1]);
  468       if(dup2(to[0],STDIN_FILENO)==-1)
  469         _exit(1);
  470 
  471       if(args_in==NULL)
  472         {
  473           if(DBG_EXTPROG)
  474         log_debug("execlp: %s\n",program);
  475 
  476           execlp(program,program,(void *)NULL);
  477         }
  478       else
  479         {
  480           if(DBG_EXTPROG)
  481         log_debug("execlp: %s -c %s\n",shell,(*info)->command);
  482 
  483           execlp(shell,shell,"-c",(*info)->command,(void *)NULL);
  484         }
  485 
  486       /* If we get this far the exec failed.  Clean up and return. */
  487 
  488       if(args_in==NULL)
  489         log_error(_("unable to execute program '%s': %s\n"),
  490               program,strerror(errno));
  491       else
  492         log_error(_("unable to execute shell '%s': %s\n"),
  493               shell,strerror(errno));
  494 
  495       /* This mimics the POSIX sh behavior - 127 means "not found"
  496              from the shell. */
  497       if(errno==ENOENT)
  498         _exit(127);
  499 
  500       _exit(1);
  501     }
  502 
  503       /* I'm the parent */
  504 
  505       close(to[0]);
  506 
  507       (*info)->tochild=fdopen(to[1],binary?"wb":"w");
  508       if((*info)->tochild==NULL)
  509     {
  510           ret = gpg_error_from_syserror ();
  511       close(to[1]);
  512       goto fail;
  513     }
  514 
  515       close(from[1]);
  516 
  517       (*info)->fromchild=iobuf_fdopen(from[0],"r");
  518       if((*info)->fromchild==NULL)
  519     {
  520           ret = gpg_error_from_syserror ();
  521       close(from[0]);
  522       goto fail;
  523     }
  524 
  525       /* fd iobufs are cached! */
  526       iobuf_ioctl((*info)->fromchild, IOBUF_IOCTL_NO_CACHE, 1, NULL);
  527 
  528       return 0;
  529     }
  530 #endif /* !EXEC_TEMPFILE_ONLY */
  531 
  532   if(DBG_EXTPROG)
  533     log_debug("using temp file '%s'\n",(*info)->tempfile_in);
  534 
  535   /* It's not fork/exec/pipe, so create a temp file */
  536   if( is_secured_filename ((*info)->tempfile_in) )
  537     {
  538       (*info)->tochild = NULL;
  539       gpg_err_set_errno (EPERM);
  540     }
  541   else
  542     (*info)->tochild=fopen((*info)->tempfile_in,binary?"wb":"w");
  543   if((*info)->tochild==NULL)
  544     {
  545       ret = gpg_error_from_syserror ();
  546       log_error(_("can't create '%s': %s\n"),
  547         (*info)->tempfile_in,strerror(errno));
  548       goto fail;
  549     }
  550 
  551   ret=0;
  552 
  553  fail:
  554   if (ret)
  555     {
  556       xfree (*info);
  557       *info = NULL;
  558     }
  559   return ret;
  560 }
  561 
  562 int
  563 exec_read(struct exec_info *info)
  564 {
  565   int ret = GPG_ERR_GENERAL;
  566 
  567   fclose(info->tochild);
  568   info->tochild=NULL;
  569 
  570   if(info->flags.use_temp_files)
  571     {
  572       if(DBG_EXTPROG)
  573     log_debug ("running command: %s\n",info->command);
  574 
  575 #if defined (_WIN32)
  576       info->progreturn=w32_system(info->command);
  577 #else
  578       info->progreturn=system(info->command);
  579 #endif
  580 
  581       if(info->progreturn==-1)
  582     {
  583       log_error(_("system error while calling external program: %s\n"),
  584             strerror(errno));
  585       info->progreturn=127;
  586       goto fail;
  587     }
  588 
  589 #if defined(WIFEXITED) && defined(WEXITSTATUS)
  590       if(WIFEXITED(info->progreturn))
  591     info->progreturn=WEXITSTATUS(info->progreturn);
  592       else
  593     {
  594       log_error(_("unnatural exit of external program\n"));
  595       info->progreturn=127;
  596       goto fail;
  597     }
  598 #else
  599       /* If we don't have the macros, do the best we can. */
  600       info->progreturn = (info->progreturn & 0xff00) >> 8;
  601 #endif
  602 
  603       /* 127 is the magic value returned from system() to indicate
  604          that the shell could not be executed, or from /bin/sh to
  605          indicate that the program could not be executed. */
  606 
  607       if(info->progreturn==127)
  608     {
  609       log_error(_("unable to execute external program\n"));
  610       goto fail;
  611     }
  612 
  613       if(!info->flags.writeonly)
  614     {
  615       info->fromchild=iobuf_open(info->tempfile_out);
  616           if (info->fromchild
  617               && is_secured_file (iobuf_get_fd (info->fromchild)))
  618             {
  619               iobuf_close (info->fromchild);
  620               info->fromchild = NULL;
  621               gpg_err_set_errno (EPERM);
  622             }
  623       if(info->fromchild==NULL)
  624         {
  625               ret = gpg_error_from_syserror ();
  626           log_error(_("unable to read external program response: %s\n"),
  627             strerror(errno));
  628           goto fail;
  629         }
  630 
  631       /* Do not cache this iobuf on close */
  632       iobuf_ioctl(info->fromchild, IOBUF_IOCTL_NO_CACHE, 1, NULL);
  633     }
  634     }
  635 
  636   ret=0;
  637 
  638  fail:
  639   return ret;
  640 }
  641 
  642 int
  643 exec_finish(struct exec_info *info)
  644 {
  645   int ret=info->progreturn;
  646 
  647   if(info->fromchild)
  648     iobuf_close(info->fromchild);
  649 
  650   if(info->tochild)
  651     fclose(info->tochild);
  652 
  653 #ifndef EXEC_TEMPFILE_ONLY
  654   if(info->child>0)
  655     {
  656       if(waitpid(info->child,&info->progreturn,0)!=0 &&
  657      WIFEXITED(info->progreturn))
  658     ret=WEXITSTATUS(info->progreturn);
  659       else
  660     {
  661       log_error(_("unnatural exit of external program\n"));
  662       ret=127;
  663     }
  664     }
  665 #endif
  666 
  667   if(info->flags.madedir && !info->flags.keep_temp_files)
  668     {
  669       if(info->tempfile_in)
  670     {
  671       if(unlink(info->tempfile_in)==-1)
  672         log_info(_("WARNING: unable to remove tempfile (%s) '%s': %s\n"),
  673              "in",info->tempfile_in,strerror(errno));
  674     }
  675 
  676       if(info->tempfile_out)
  677     {
  678       if(unlink(info->tempfile_out)==-1)
  679         log_info(_("WARNING: unable to remove tempfile (%s) '%s': %s\n"),
  680              "out",info->tempfile_out,strerror(errno));
  681     }
  682 
  683       if(rmdir(info->tempdir)==-1)
  684     log_info(_("WARNING: unable to remove temp directory '%s': %s\n"),
  685          info->tempdir,strerror(errno));
  686     }
  687 
  688   xfree(info->command);
  689   xfree(info->name);
  690   xfree(info->tempdir);
  691   xfree(info->tempfile_in);
  692   xfree(info->tempfile_out);
  693   xfree(info);
  694 
  695   return ret;
  696 }
  697 #endif /* ! NO_EXEC */