6ad5e27a9b661ceaa3df7af9b789d0420610449e
[gnupg.git] / common / sysutils.c
1 /* sysutils.c -  system helpers
2  * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004,
3  *               2007, 2008  Free Software Foundation, Inc.
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22
23 #ifdef WITHOUT_GNU_PTH /* Give the Makefile a chance to build without Pth.  */
24 # undef HAVE_PTH
25 # undef USE_GNU_PTH
26 #endif
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <errno.h>
33 #ifdef HAVE_STAT
34 # include <sys/stat.h>
35 #endif
36 #if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2
37 # include <asm/sysinfo.h>
38 # include <asm/unistd.h>
39 #endif
40 #ifdef HAVE_SETRLIMIT
41 # include <time.h>
42 # include <sys/time.h>
43 # include <sys/resource.h>
44 #endif
45 #ifdef HAVE_W32_SYSTEM
46 # define WINVER 0x0500  /* Required for AllowSetForegroundWindow.  */
47 # include <windows.h>
48 #endif
49 #ifdef HAVE_PTH      
50 # include <pth.h>
51 #endif
52 #include <fcntl.h>
53
54 #include "setenv.h"   /* Gnulib replacement.  */
55
56 #include "util.h"
57 #include "i18n.h"
58
59 #include "sysutils.h"
60
61 #define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
62
63
64 #if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2
65 #warning using trap_unaligned
66 static int
67 setsysinfo(unsigned long op, void *buffer, unsigned long size,
68                      int *start, void *arg, unsigned long flag)
69 {
70     return syscall(__NR_osf_setsysinfo, op, buffer, size, start, arg, flag);
71 }
72
73 void
74 trap_unaligned(void)
75 {
76     unsigned int buf[2];
77
78     buf[0] = SSIN_UACPROC;
79     buf[1] = UAC_SIGBUS | UAC_NOPRINT;
80     setsysinfo(SSI_NVPAIRS, buf, 1, 0, 0, 0);
81 }
82 #else
83 void
84 trap_unaligned(void)
85 {  /* dummy */
86 }
87 #endif
88
89
90 int
91 disable_core_dumps (void)
92 {
93 #ifdef HAVE_DOSISH_SYSTEM
94     return 0;
95 #else
96 # ifdef HAVE_SETRLIMIT
97     struct rlimit limit;
98
99     /* We only set the current limit unless we were not able to
100        retrieve the old value. */
101     if (getrlimit (RLIMIT_CORE, &limit))
102       limit.rlim_max = 0;
103     limit.rlim_cur = 0;
104     if( !setrlimit (RLIMIT_CORE, &limit) )
105         return 0;
106     if( errno != EINVAL && errno != ENOSYS )
107         log_fatal (_("can't disable core dumps: %s\n"), strerror(errno) );
108 #endif
109     return 1;
110 #endif
111 }
112
113 int
114 enable_core_dumps (void)
115 {
116 #ifdef HAVE_DOSISH_SYSTEM
117     return 0;
118 #else
119 # ifdef HAVE_SETRLIMIT
120     struct rlimit limit;
121
122     if (getrlimit (RLIMIT_CORE, &limit))
123       return 1;
124     limit.rlim_cur = limit.rlim_max;
125     setrlimit (RLIMIT_CORE, &limit);
126     return 1; /* We always return true because this function is
127                  merely a debugging aid. */
128 # endif
129     return 1;
130 #endif
131 }
132
133
134
135 /* Return a string which is used as a kind of process ID.  */
136 const byte *
137 get_session_marker (size_t *rlen)
138 {
139   static byte marker[SIZEOF_UNSIGNED_LONG*2];
140   static int initialized;
141   
142   if (!initialized)
143     {
144       gcry_create_nonce (marker, sizeof marker);
145       initialized = 1;
146     }
147   *rlen = sizeof (marker);
148   return marker;
149 }
150
151
152 #if 0 /* not yet needed - Note that this will require inclusion of
153          cmacros.am in Makefile.am */
154 int
155 check_permissions(const char *path,int extension,int checkonly)
156 {
157 #if defined(HAVE_STAT) && !defined(HAVE_DOSISH_SYSTEM)
158   char *tmppath;
159   struct stat statbuf;
160   int ret=1;
161   int isdir=0;
162
163   if(opt.no_perm_warn)
164     return 0;
165
166   if(extension && path[0]!=DIRSEP_C)
167     {
168       if(strchr(path,DIRSEP_C))
169         tmppath=make_filename(path,NULL);
170       else
171         tmppath=make_filename(GNUPG_LIBDIR,path,NULL);
172     }
173   else
174     tmppath=m_strdup(path);
175
176   /* It's okay if the file doesn't exist */
177   if(stat(tmppath,&statbuf)!=0)
178     {
179       ret=0;
180       goto end;
181     }
182
183   isdir=S_ISDIR(statbuf.st_mode);
184
185   /* Per-user files must be owned by the user.  Extensions must be
186      owned by the user or root. */
187   if((!extension && statbuf.st_uid != getuid()) ||
188      (extension && statbuf.st_uid!=0 && statbuf.st_uid!=getuid()))
189     {
190       if(!checkonly)
191         log_info(_("Warning: unsafe ownership on %s \"%s\"\n"),
192                  isdir?"directory":extension?"extension":"file",path);
193       goto end;
194     }
195
196   /* This works for both directories and files - basically, we don't
197      care what the owner permissions are, so long as the group and
198      other permissions are 0 for per-user files, and non-writable for
199      extensions. */
200   if((extension && (statbuf.st_mode & (S_IWGRP|S_IWOTH)) !=0) ||
201      (!extension && (statbuf.st_mode & (S_IRWXG|S_IRWXO)) != 0))
202     {
203       char *dir;
204
205       /* However, if the directory the directory/file is in is owned
206          by the user and is 700, then this is not a problem.
207          Theoretically, we could walk this test up to the root
208          directory /, but for the sake of sanity, I'm stopping at one
209          level down. */
210
211       dir= make_dirname (tmppath);
212       if(stat(dir,&statbuf)==0 && statbuf.st_uid==getuid() &&
213          S_ISDIR(statbuf.st_mode) && (statbuf.st_mode & (S_IRWXG|S_IRWXO))==0)
214         {
215           xfree (dir);
216           ret=0;
217           goto end;
218         }
219
220       m_free(dir);
221
222       if(!checkonly)
223         log_info(_("Warning: unsafe permissions on %s \"%s\"\n"),
224                  isdir?"directory":extension?"extension":"file",path);
225       goto end;
226     }
227
228   ret=0;
229
230  end:
231   m_free(tmppath);
232
233   return ret;
234
235 #endif /* HAVE_STAT && !HAVE_DOSISH_SYSTEM */
236
237   return 0;
238 }
239 #endif
240
241
242 /* Wrapper around the usual sleep fucntion.  This one won't wake up
243    before the sleep time has really elapsed.  When build with Pth it
244    merely calls pth_sleep and thus suspends only the current
245    thread. */
246 void
247 gnupg_sleep (unsigned int seconds)
248 {
249 #ifdef HAVE_PTH
250   /* With Pth we force a regular sleep for seconds == 0 so that also
251      the process will give up its timeslot.  */
252   if (!seconds)
253     {
254 # ifdef HAVE_W32_SYSTEM    
255       Sleep (0);
256 # else
257       sleep (0);
258 # endif
259     }
260   pth_sleep (seconds);
261 #else
262   /* Fixme:  make sure that a sleep won't wake up to early.  */
263 # ifdef HAVE_W32_SYSTEM    
264   Sleep (seconds*1000);
265 # else
266   sleep (seconds);
267 # endif
268 #endif
269 }
270
271
272 /* This function is a NOP for POSIX systems but required under Windows
273    as the file handles as returned by OS calls (like CreateFile) are
274    different from the libc file descriptors (like open). This function
275    translates system file handles to libc file handles.  FOR_WRITE
276    gives the direction of the handle.  */
277 int
278 translate_sys2libc_fd (gnupg_fd_t fd, int for_write)
279 {
280 #if defined(HAVE_W32CE_SYSTEM)
281   (void)for_write;
282   return (int)fd;
283 #elif defined(HAVE_W32_SYSTEM)
284   int x;
285
286   if (fd == GNUPG_INVALID_FD)
287     return -1;
288   
289   /* Note that _open_osfhandle is currently defined to take and return
290      a long.  */
291   x = _open_osfhandle ((long)fd, for_write ? 1 : 0);
292   if (x == -1)
293     log_error ("failed to translate osfhandle %p\n", (void *) fd);
294   return x;
295 #else /*!HAVE_W32_SYSTEM */
296   (void)for_write;
297   return fd;
298 #endif
299 }
300
301 /* This is the same as translate_sys2libc_fd but takes an integer
302    which is assumed to be such an system handle.  */
303 int
304 translate_sys2libc_fd_int (int fd, int for_write)
305 {
306 #ifdef HAVE_W32_SYSTEM
307   if (fd <= 2)
308     return fd;  /* Do not do this for error, stdin, stdout, stderr. */
309
310   return translate_sys2libc_fd ((void*)fd, for_write);
311 #else
312   (void)for_write;
313   return fd;
314 #endif
315 }
316
317
318
319 /* Replacement for tmpfile().  This is required because the tmpfile
320    function of Windows' runtime library is broken, insecure, ignores
321    TMPDIR and so on.  In addition we create a file with an inheritable
322    handle.  */
323 FILE *
324 gnupg_tmpfile (void)
325 {
326 #ifdef HAVE_W32_SYSTEM
327   int attempts, n;
328 #ifdef HAVE_W32CE_SYSTEM
329   wchar_t buffer[MAX_PATH+7+12+1];
330 # define mystrlen(a) wcslen (a)
331   wchar_t *name, *p;
332 #else
333   char buffer[MAX_PATH+7+12+1];
334 # define mystrlen(a) strlen (a)
335   char *name, *p;
336 #endif
337   HANDLE file;
338   int pid = GetCurrentProcessId ();
339   unsigned int value;
340   int i;
341   SECURITY_ATTRIBUTES sec_attr;
342
343   memset (&sec_attr, 0, sizeof sec_attr );
344   sec_attr.nLength = sizeof sec_attr;
345   sec_attr.bInheritHandle = TRUE;
346
347   n = GetTempPath (MAX_PATH+1, buffer);
348   if (!n || n > MAX_PATH || mystrlen (buffer) > MAX_PATH)
349     {
350       gpg_err_set_errno (ENOENT);
351       return NULL;
352     }
353   p = buffer + mystrlen (buffer);
354 #ifdef HAVE_W32CE_SYSTEM
355   wcscpy (p, L"_gnupg");
356   p += 7;
357 #else
358   p = stpcpy (p, "_gnupg");
359 #endif
360   /* We try to create the directory but don't care about an error as
361      it may already exist and the CreateFile would throw an error
362      anyway.  */
363   CreateDirectory (buffer, NULL);
364   *p++ = '\\';
365   name = p;
366   for (attempts=0; attempts < 10; attempts++)
367     {
368       p = name;
369       value = (GetTickCount () ^ ((pid<<16) & 0xffff0000));
370       for (i=0; i < 8; i++)
371         {
372           *p++ = tohex (((value >> 28) & 0x0f));
373           value <<= 4;
374         }
375 #ifdef HAVE_W32CE_SYSTEM
376       wcscpy (p, L".tmp");
377 #else
378       strcpy (p, ".tmp");
379 #endif
380       file = CreateFile (buffer,
381                          GENERIC_READ | GENERIC_WRITE,
382                          0,
383                          &sec_attr,
384                          CREATE_NEW,
385                          FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
386                          NULL);
387       if (file != INVALID_HANDLE_VALUE)
388         {
389           FILE *fp;
390 #ifdef HAVE_W32CE_SYSTEM
391           int fd = (int)file;
392           fp = _wfdopen (fd, L"w+b");
393 #else
394           int fd = _open_osfhandle ((long)file, 0);
395           if (fd == -1)
396             {
397               CloseHandle (file);
398               return NULL;
399             }
400           fp = fdopen (fd, "w+b");
401 #endif
402           if (!fp)
403             {
404               int save = errno;
405               close (fd);
406               gpg_err_set_errno (save);
407               return NULL;
408             }
409           return fp;
410         }
411       Sleep (1); /* One ms as this is the granularity of GetTickCount.  */
412     }
413   gpg_err_set_errno (ENOENT);
414   return NULL;
415 #undef mystrlen
416 #else /*!HAVE_W32_SYSTEM*/
417   return tmpfile ();
418 #endif /*!HAVE_W32_SYSTEM*/
419 }
420
421
422 /* Make sure that the standard file descriptors are opened. Obviously
423    some folks close them before an exec and the next file we open will
424    get one of them assigned and thus any output (i.e. diagnostics) end
425    up in that file (e.g. the trustdb).  Not actually a gpg problem as
426    this will hapen with almost all utilities when called in a wrong
427    way.  However we try to minimize the damage here and raise
428    awareness of the problem.
429
430    Must be called before we open any files! */
431 void
432 gnupg_reopen_std (const char *pgmname)
433 {  
434 #if defined(HAVE_STAT) && !defined(HAVE_W32_SYSTEM)
435   struct stat statbuf;
436   int did_stdin = 0;
437   int did_stdout = 0;
438   int did_stderr = 0;
439   FILE *complain;
440
441   if (fstat (STDIN_FILENO, &statbuf) == -1 && errno ==EBADF)
442     {
443       if (open ("/dev/null",O_RDONLY) == STDIN_FILENO)
444         did_stdin = 1;
445       else
446         did_stdin = 2;
447     }
448   
449   if (fstat (STDOUT_FILENO, &statbuf) == -1 && errno == EBADF)
450     {
451       if (open ("/dev/null",O_WRONLY) == STDOUT_FILENO)
452         did_stdout = 1;
453       else
454         did_stdout = 2;
455     }
456
457   if (fstat (STDERR_FILENO, &statbuf)==-1 && errno==EBADF)
458     {
459       if (open ("/dev/null", O_WRONLY) == STDERR_FILENO)
460         did_stderr = 1;
461       else
462         did_stderr = 2;
463     }
464
465   /* It's hard to log this sort of thing since the filehandle we would
466      complain to may be closed... */
467   if (!did_stderr)
468     complain = stderr;
469   else if (!did_stdout)
470     complain = stdout;
471   else
472     complain = NULL;
473
474   if (complain)
475     {
476       if (did_stdin == 1)
477         fprintf (complain, "%s: WARNING: standard input reopened\n", pgmname);
478       if (did_stdout == 1)
479         fprintf (complain, "%s: WARNING: standard output reopened\n", pgmname);
480       if (did_stderr == 1)
481         fprintf (complain, "%s: WARNING: standard error reopened\n", pgmname);
482
483       if (did_stdin == 2 || did_stdout == 2 || did_stderr == 2)
484         fprintf(complain,"%s: fatal: unable to reopen standard input,"
485                 " output, or error\n", pgmname);
486     }
487
488   if (did_stdin == 2 || did_stdout == 2 || did_stderr == 2)
489     exit (3);
490 #else /* !(HAVE_STAT && !HAVE_W32_SYSTEM) */
491   (void)pgmname;
492 #endif
493 }
494
495
496 /* Hack required for Windows.  */
497 void 
498 gnupg_allow_set_foregound_window (pid_t pid)
499 {
500   if (!pid)
501     log_info ("%s called with invalid pid %lu\n",
502               "gnupg_allow_set_foregound_window", (unsigned long)pid);
503 #if defined(HAVE_W32_SYSTEM) && !defined(HAVE_W32CE_SYSTEM)
504   else if (!AllowSetForegroundWindow ((pid_t)pid == (pid_t)(-1)?ASFW_ANY:pid))
505     log_info ("AllowSetForegroundWindow(%lu) failed: %s\n",
506                (unsigned long)pid, w32_strerror (-1));
507 #endif
508 }
509
510 int
511 gnupg_remove (const char *fname)
512 {
513 #ifdef HAVE_W32CE_SYSTEM
514   int rc;
515   wchar_t *wfname;
516
517   wfname = utf8_to_wchar (fname);
518   if (!wfname)
519     rc = 0;
520   else
521     {
522       rc = DeleteFile (wfname);
523       xfree (wfname);
524     }
525   if (!rc)
526     gpg_err_set_errno (EIO);
527   return !rc;
528 #else
529   return remove;
530 #endif
531 }
532
533
534 /* A wrapper around mkdir which takes a string for the mode argument.
535    This makes it easier to handle the mode argument which is not
536    defined on all systems.  The format of the modestring is
537
538       "-rwxrwxrwx"
539       
540    '-' is a don't care or not set.  'r', 'w', 'x' are read allowed,
541    write allowed, execution allowed with the first group for the user,
542    the second for the group and the third for all others.  If the
543    string is shorter than above the missing mode characters are meant
544    to be not set.  */
545 int
546 gnupg_mkdir (const char *name, const char *modestr)
547 {
548 #ifdef HAVE_W32CE_SYSTEM
549   wchar_t *wname;
550   (void)modestr;
551   
552   wname = utf8_to_wchar (name);
553   if (!wname)
554     return -1;
555   if (!CreateDirectoryW (wname, NULL))
556     {
557       xfree (wname);
558       return -1;  /* ERRNO is automagically provided by gpg-error.h.  */
559     }
560   xfree (wname);
561   return 0;
562 #elif MKDIR_TAKES_ONE_ARG
563   (void)modestr;
564   /* Note: In the case of W32 we better use CreateDirectory and try to
565      set appropriate permissions.  However using mkdir is easier
566      because this sets ERRNO.  */
567   return mkdir (name);
568 #else
569   mode_t mode = 0;
570
571   if (modestr && *modestr)
572     {
573       modestr++;
574       if (*modestr && *modestr++ == 'r')
575         mode |= S_IRUSR;
576       if (*modestr && *modestr++ == 'w')
577         mode |= S_IWUSR;
578       if (*modestr && *modestr++ == 'x')
579         mode |= S_IXUSR;
580       if (*modestr && *modestr++ == 'r')
581         mode |= S_IRGRP;
582       if (*modestr && *modestr++ == 'w')
583         mode |= S_IWGRP;
584       if (*modestr && *modestr++ == 'x')
585         mode |= S_IXGRP;
586       if (*modestr && *modestr++ == 'r')
587         mode |= S_IROTH;
588       if (*modestr && *modestr++ == 'w')
589         mode |= S_IWOTH;
590       if (*modestr && *modestr++ == 'x')
591         mode |= S_IXOTH;
592     }
593   return mkdir (home, mode)
594 #endif
595 }
596
597
598 int
599 gnupg_setenv (const char *name, const char *value, int overwrite)
600 {
601 #ifdef HAVE_W32CE_SYSTEM
602   (void)name;
603   (void)value;
604   (void)overwrite;
605   return 0;
606 #else
607   setenv (name, value, overwrite);
608 #endif
609 }
610
611 int 
612 gnupg_unsetenv (const char *name)
613 {
614 #ifdef HAVE_W32CE_SYSTEM
615   (void)name;
616   return 0;
617 #else
618 # ifdef HAVE_UNSETENV
619   unsetenv (name);
620 # else
621   putenv (name);
622 # endif
623 #endif
624 }
625
626
627 #ifdef HAVE_W32CE_SYSTEM
628 /* Replacement for getenv which takes care of the our use of getenv.
629    The code is not thread safe but we expect it to work in all cases
630    because it is called for the first time early enough.  */
631 char *
632 _gnupg_getenv (const char *name)
633 {
634   static int initialized;
635   static char *assuan_debug;
636   
637   if (!initialized)
638     {
639       assuan_debug = read_w32_registry_string (NULL, 
640                                                "\\Software\\GNU\\libassuan",
641                                                "debug");
642       initialized = 1;
643     }
644
645   if (!strcmp (name, "ASSUAN_DEBUG"))
646     return assuan_debug;
647   else
648     return NULL;
649 }
650
651 #endif /*HAVE_W32CE_SYSTEM*/
652