chiark / gitweb /
dirmngr: New debug message on correctly initialized libdns.
[gnupg2.git] / g10 / exec.c
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 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   p=xmalloc(5+strlen(path)+1);
122   strcpy(p,"PATH=");
123   strcat(p,path);
124
125   if(DBG_EXTPROG)
126     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   if(putenv(p)!=0)
133     return GPG_ERR_GENERAL;
134   else
135     return 0;
136 #endif
137 }
138
139 /* Makes a temp directory and filenames */
140 static int
141 make_tempdir(struct exec_info *info)
142 {
143   char *tmp=opt.temp_dir,*namein=info->name,*nameout;
144
145   if(!namein)
146     namein=info->flags.binary?"tempin" EXTSEP_S "bin":"tempin" EXTSEP_S "txt";
147
148   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   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       tmp=getenv("TMPDIR");
174       if(tmp==NULL)
175         {
176           tmp=getenv("TMP");
177           if(tmp==NULL)
178             {
179 #ifdef __riscos__
180               tmp="<Wimp$ScrapDir>.GnuPG";
181               mkdir(tmp,0700); /* Error checks occur later on */
182 #else
183               tmp="/tmp";
184 #endif
185             }
186         }
187 #endif
188     }
189
190   info->tempdir=xmalloc(strlen(tmp)+strlen(DIRSEP_S)+10+1);
191
192   sprintf(info->tempdir,"%s" DIRSEP_S "gpg-XXXXXX",tmp);
193
194 #if defined (_WIN32)
195   xfree(tmp);
196 #endif
197
198   if (!gnupg_mkdtemp(info->tempdir))
199     log_error(_("can't create directory '%s': %s\n"),
200               info->tempdir,strerror(errno));
201   else
202     {
203       info->flags.madedir=1;
204
205       info->tempfile_in=xmalloc(strlen(info->tempdir)+
206                                 strlen(DIRSEP_S)+strlen(namein)+1);
207       sprintf(info->tempfile_in,"%s" DIRSEP_S "%s",info->tempdir,namein);
208
209       if(!info->flags.writeonly)
210         {
211           info->tempfile_out=xmalloc(strlen(info->tempdir)+
212                                      strlen(DIRSEP_S)+strlen(nameout)+1);
213           sprintf(info->tempfile_out,"%s" DIRSEP_S "%s",info->tempdir,nameout);
214         }
215     }
216
217   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 expand_args(struct exec_info *info,const char *args_in)
224 {
225   const char *ch = args_in;
226   membuf_t command;
227
228   info->flags.use_temp_files=0;
229   info->flags.keep_temp_files=0;
230
231   if(DBG_EXTPROG)
232     log_debug("expanding string \"%s\"\n",args_in);
233
234   init_membuf (&command, 100);
235
236   while(*ch!='\0')
237     {
238       if(*ch=='%')
239         {
240           char *append=NULL;
241
242           ch++;
243
244           switch(*ch)
245             {
246             case 'O':
247               info->flags.keep_temp_files=1;
248               /* fall through */
249
250             case 'o': /* out */
251               if(!info->flags.madedir)
252                 {
253                   if(make_tempdir(info))
254                     goto fail;
255                 }
256               append=info->tempfile_out;
257               info->flags.use_temp_files=1;
258               break;
259
260             case 'I':
261               info->flags.keep_temp_files=1;
262               /* fall through */
263
264             case 'i': /* in */
265               if(!info->flags.madedir)
266                 {
267                   if(make_tempdir(info))
268                     goto fail;
269                 }
270               append=info->tempfile_in;
271               info->flags.use_temp_files=1;
272               break;
273
274             case '%':
275               append="%";
276               break;
277             }
278
279           if(append)
280             put_membuf_str (&command, append);
281         }
282       else
283         put_membuf (&command, ch, 1);
284
285       ch++;
286     }
287
288   put_membuf (&command, "", 1);  /* Terminate string.  */
289
290   info->command = get_membuf (&command, NULL);
291   if (!info->command)
292     return gpg_error_from_syserror ();
293
294   if(DBG_EXTPROG)
295     log_debug("args expanded to \"%s\", use %u, keep %u\n",info->command,
296               info->flags.use_temp_files,info->flags.keep_temp_files);
297
298   return 0;
299
300  fail:
301   xfree (get_membuf (&command, NULL));
302   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 exec_write(struct exec_info **info,const char *program,
313            const char *args_in,const char *name,int writeonly,int binary)
314 {
315   int ret = GPG_ERR_GENERAL;
316
317   if(opt.exec_disable && !opt.no_perm_warn)
318     {
319       log_info(_("external program calls are disabled due to unsafe "
320                  "options file permissions\n"));
321
322       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   if(program==NULL && args_in==NULL)
333     BUG();
334
335   *info=xmalloc_clear(sizeof(struct exec_info));
336
337   if(name)
338     (*info)->name=xstrdup(name);
339   (*info)->flags.binary=binary;
340   (*info)->flags.writeonly=writeonly;
341
342   /* Expand the args, if any */
343   if(args_in && expand_args(*info,args_in))
344     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   if(args_in==NULL || (*info)->flags.use_temp_files==0)
359     {
360       int to[2],from[2];
361
362       if(pipe(to)==-1)
363         goto fail;
364
365       if(pipe(from)==-1)
366         {
367           close(to[0]);
368           close(to[1]);
369           goto fail;
370         }
371
372       if(((*info)->child=fork())==-1)
373         {
374           close(to[0]);
375           close(to[1]);
376           close(from[0]);
377           close(from[1]);
378           goto fail;
379         }
380
381       if((*info)->child==0)
382         {
383           char *shell=getenv("SHELL");
384
385           if(shell==NULL)
386             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           if(!(*info)->flags.writeonly)
393             {
394               /* implied close of STDERR */
395               if(dup2(STDOUT_FILENO,STDERR_FILENO)==-1)
396                 _exit(1);
397
398               /* implied close of STDOUT */
399               close(from[0]);
400               if(dup2(from[1],STDOUT_FILENO)==-1)
401                 _exit(1);
402             }
403
404           /* implied close of STDIN */
405           close(to[1]);
406           if(dup2(to[0],STDIN_FILENO)==-1)
407             _exit(1);
408
409           if(args_in==NULL)
410             {
411               if(DBG_EXTPROG)
412                 log_debug("execlp: %s\n",program);
413
414               execlp(program,program,(void *)NULL);
415             }
416           else
417             {
418               if(DBG_EXTPROG)
419                 log_debug("execlp: %s -c %s\n",shell,(*info)->command);
420
421               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           if(args_in==NULL)
427             log_error(_("unable to execute program '%s': %s\n"),
428                       program,strerror(errno));
429           else
430             log_error(_("unable to execute shell '%s': %s\n"),
431                       shell,strerror(errno));
432
433           /* This mimics the POSIX sh behavior - 127 means "not found"
434              from the shell. */
435           if(errno==ENOENT)
436             _exit(127);
437
438           _exit(1);
439         }
440
441       /* I'm the parent */
442
443       close(to[0]);
444
445       (*info)->tochild=fdopen(to[1],binary?"wb":"w");
446       if((*info)->tochild==NULL)
447         {
448           ret = gpg_error_from_syserror ();
449           close(to[1]);
450           goto fail;
451         }
452
453       close(from[1]);
454
455       (*info)->fromchild=iobuf_fdopen(from[0],"r");
456       if((*info)->fromchild==NULL)
457         {
458           ret = gpg_error_from_syserror ();
459           close(from[0]);
460           goto fail;
461         }
462
463       /* fd iobufs are cached! */
464       iobuf_ioctl((*info)->fromchild, IOBUF_IOCTL_NO_CACHE, 1, NULL);
465
466       return 0;
467     }
468 #endif /* !EXEC_TEMPFILE_ONLY */
469
470   if(DBG_EXTPROG)
471     log_debug("using temp file '%s'\n",(*info)->tempfile_in);
472
473   /* It's not fork/exec/pipe, so create a temp file */
474   if( is_secured_filename ((*info)->tempfile_in) )
475     {
476       (*info)->tochild = NULL;
477       gpg_err_set_errno (EPERM);
478     }
479   else
480     (*info)->tochild=fopen((*info)->tempfile_in,binary?"wb":"w");
481   if((*info)->tochild==NULL)
482     {
483       ret = gpg_error_from_syserror ();
484       log_error(_("can't create '%s': %s\n"),
485                 (*info)->tempfile_in,strerror(errno));
486       goto fail;
487     }
488
489   ret=0;
490
491  fail:
492   if (ret)
493     {
494       xfree (*info);
495       *info = NULL;
496     }
497   return ret;
498 }
499
500 int
501 exec_read(struct exec_info *info)
502 {
503   int ret = GPG_ERR_GENERAL;
504
505   fclose(info->tochild);
506   info->tochild=NULL;
507
508   if(info->flags.use_temp_files)
509     {
510       if(DBG_EXTPROG)
511         log_debug("system() command is %s\n",info->command);
512
513 #if defined (_WIN32)
514       info->progreturn=w32_system(info->command);
515 #else
516       info->progreturn=system(info->command);
517 #endif
518
519       if(info->progreturn==-1)
520         {
521           log_error(_("system error while calling external program: %s\n"),
522                     strerror(errno));
523           info->progreturn=127;
524           goto fail;
525         }
526
527 #if defined(WIFEXITED) && defined(WEXITSTATUS)
528       if(WIFEXITED(info->progreturn))
529         info->progreturn=WEXITSTATUS(info->progreturn);
530       else
531         {
532           log_error(_("unnatural exit of external program\n"));
533           info->progreturn=127;
534           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       if(info->progreturn==127)
546         {
547           log_error(_("unable to execute external program\n"));
548           goto fail;
549         }
550
551       if(!info->flags.writeonly)
552         {
553           info->fromchild=iobuf_open(info->tempfile_out);
554           if (info->fromchild
555               && is_secured_file (iobuf_get_fd (info->fromchild)))
556             {
557               iobuf_close (info->fromchild);
558               info->fromchild = NULL;
559               gpg_err_set_errno (EPERM);
560             }
561           if(info->fromchild==NULL)
562             {
563               ret = gpg_error_from_syserror ();
564               log_error(_("unable to read external program response: %s\n"),
565                         strerror(errno));
566               goto fail;
567             }
568
569           /* Do not cache this iobuf on close */
570           iobuf_ioctl(info->fromchild, IOBUF_IOCTL_NO_CACHE, 1, NULL);
571         }
572     }
573
574   ret=0;
575
576  fail:
577   return ret;
578 }
579
580 int
581 exec_finish(struct exec_info *info)
582 {
583   int ret=info->progreturn;
584
585   if(info->fromchild)
586     iobuf_close(info->fromchild);
587
588   if(info->tochild)
589     fclose(info->tochild);
590
591 #ifndef EXEC_TEMPFILE_ONLY
592   if(info->child>0)
593     {
594       if(waitpid(info->child,&info->progreturn,0)!=0 &&
595          WIFEXITED(info->progreturn))
596         ret=WEXITSTATUS(info->progreturn);
597       else
598         {
599           log_error(_("unnatural exit of external program\n"));
600           ret=127;
601         }
602     }
603 #endif
604
605   if(info->flags.madedir && !info->flags.keep_temp_files)
606     {
607       if(info->tempfile_in)
608         {
609           if(unlink(info->tempfile_in)==-1)
610             log_info(_("WARNING: unable to remove tempfile (%s) '%s': %s\n"),
611                      "in",info->tempfile_in,strerror(errno));
612         }
613
614       if(info->tempfile_out)
615         {
616           if(unlink(info->tempfile_out)==-1)
617             log_info(_("WARNING: unable to remove tempfile (%s) '%s': %s\n"),
618                      "out",info->tempfile_out,strerror(errno));
619         }
620
621       if(rmdir(info->tempdir)==-1)
622         log_info(_("WARNING: unable to remove temp directory '%s': %s\n"),
623                  info->tempdir,strerror(errno));
624     }
625
626   xfree(info->command);
627   xfree(info->name);
628   xfree(info->tempdir);
629   xfree(info->tempfile_in);
630   xfree(info->tempfile_out);
631   xfree(info);
632
633   return ret;
634 }
635 #endif /* ! NO_EXEC */