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