Updated estream.
[gnupg.git] / common / sysutils.c
1 /* sysutils.c -  system helpers
2  * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004,
3  *               2007  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 # include <windows.h>
47 #endif
48 #ifdef HAVE_PTH      
49 # include <pth.h>
50 #endif
51
52 #include "util.h"
53 #include "i18n.h"
54
55 #include "sysutils.h"
56
57 #define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
58
59
60 #if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2
61 #warning using trap_unaligned
62 static int
63 setsysinfo(unsigned long op, void *buffer, unsigned long size,
64                      int *start, void *arg, unsigned long flag)
65 {
66     return syscall(__NR_osf_setsysinfo, op, buffer, size, start, arg, flag);
67 }
68
69 void
70 trap_unaligned(void)
71 {
72     unsigned int buf[2];
73
74     buf[0] = SSIN_UACPROC;
75     buf[1] = UAC_SIGBUS | UAC_NOPRINT;
76     setsysinfo(SSI_NVPAIRS, buf, 1, 0, 0, 0);
77 }
78 #else
79 void
80 trap_unaligned(void)
81 {  /* dummy */
82 }
83 #endif
84
85
86 int
87 disable_core_dumps (void)
88 {
89 #ifdef HAVE_DOSISH_SYSTEM
90     return 0;
91 #else
92 # ifdef HAVE_SETRLIMIT
93     struct rlimit limit;
94
95     /* We only set the current limit unless we were not able to
96        retrieve the old value. */
97     if (getrlimit (RLIMIT_CORE, &limit))
98       limit.rlim_max = 0;
99     limit.rlim_cur = 0;
100     if( !setrlimit (RLIMIT_CORE, &limit) )
101         return 0;
102     if( errno != EINVAL && errno != ENOSYS )
103         log_fatal (_("can't disable core dumps: %s\n"), strerror(errno) );
104 #endif
105     return 1;
106 #endif
107 }
108
109 int
110 enable_core_dumps (void)
111 {
112 #ifdef HAVE_DOSISH_SYSTEM
113     return 0;
114 #else
115 # ifdef HAVE_SETRLIMIT
116     struct rlimit limit;
117
118     if (getrlimit (RLIMIT_CORE, &limit))
119       return 1;
120     limit.rlim_cur = limit.rlim_max;
121     setrlimit (RLIMIT_CORE, &limit);
122     return 1; /* We always return true because trhis function is
123                  merely a debugging aid. */
124 # endif
125     return 1;
126 #endif
127 }
128
129
130
131 /* Return a string which is used as a kind of process ID */
132 const byte *
133 get_session_marker( size_t *rlen )
134 {
135     static byte marker[SIZEOF_UNSIGNED_LONG*2];
136     static int initialized;
137
138     if ( !initialized ) {
139         volatile ulong aa, bb; /* we really want the uninitialized value */
140         ulong a, b;
141
142         initialized = 1;
143         /* Although this marker is guessable it is not easy to use
144          * for a faked control packet because an attacker does not
145          * have enough control about the time the verification does 
146          * take place.  Of course, we can add just more random but 
147          * than we need the random generator even for verification
148          * tasks - which does not make sense. */
149         a = aa ^ (ulong)getpid();
150         b = bb ^ (ulong)time(NULL);
151         memcpy( marker, &a, SIZEOF_UNSIGNED_LONG );
152         memcpy( marker+SIZEOF_UNSIGNED_LONG, &b, SIZEOF_UNSIGNED_LONG );
153     }
154     *rlen = sizeof(marker);
155     return marker;
156 }
157
158
159 #if 0 /* not yet needed - Note that this will require inclusion of
160          cmacros.am in Makefile.am */
161 int
162 check_permissions(const char *path,int extension,int checkonly)
163 {
164 #if defined(HAVE_STAT) && !defined(HAVE_DOSISH_SYSTEM)
165   char *tmppath;
166   struct stat statbuf;
167   int ret=1;
168   int isdir=0;
169
170   if(opt.no_perm_warn)
171     return 0;
172
173   if(extension && path[0]!=DIRSEP_C)
174     {
175       if(strchr(path,DIRSEP_C))
176         tmppath=make_filename(path,NULL);
177       else
178         tmppath=make_filename(GNUPG_LIBDIR,path,NULL);
179     }
180   else
181     tmppath=m_strdup(path);
182
183   /* It's okay if the file doesn't exist */
184   if(stat(tmppath,&statbuf)!=0)
185     {
186       ret=0;
187       goto end;
188     }
189
190   isdir=S_ISDIR(statbuf.st_mode);
191
192   /* Per-user files must be owned by the user.  Extensions must be
193      owned by the user or root. */
194   if((!extension && statbuf.st_uid != getuid()) ||
195      (extension && statbuf.st_uid!=0 && statbuf.st_uid!=getuid()))
196     {
197       if(!checkonly)
198         log_info(_("Warning: unsafe ownership on %s \"%s\"\n"),
199                  isdir?"directory":extension?"extension":"file",path);
200       goto end;
201     }
202
203   /* This works for both directories and files - basically, we don't
204      care what the owner permissions are, so long as the group and
205      other permissions are 0 for per-user files, and non-writable for
206      extensions. */
207   if((extension && (statbuf.st_mode & (S_IWGRP|S_IWOTH)) !=0) ||
208      (!extension && (statbuf.st_mode & (S_IRWXG|S_IRWXO)) != 0))
209     {
210       char *dir;
211
212       /* However, if the directory the directory/file is in is owned
213          by the user and is 700, then this is not a problem.
214          Theoretically, we could walk this test up to the root
215          directory /, but for the sake of sanity, I'm stopping at one
216          level down. */
217
218       dir= make_dirname (tmppath);
219       if(stat(dir,&statbuf)==0 && statbuf.st_uid==getuid() &&
220          S_ISDIR(statbuf.st_mode) && (statbuf.st_mode & (S_IRWXG|S_IRWXO))==0)
221         {
222           xfree (dir);
223           ret=0;
224           goto end;
225         }
226
227       m_free(dir);
228
229       if(!checkonly)
230         log_info(_("Warning: unsafe permissions on %s \"%s\"\n"),
231                  isdir?"directory":extension?"extension":"file",path);
232       goto end;
233     }
234
235   ret=0;
236
237  end:
238   m_free(tmppath);
239
240   return ret;
241
242 #endif /* HAVE_STAT && !HAVE_DOSISH_SYSTEM */
243
244   return 0;
245 }
246 #endif
247
248
249 /* Wrapper around the usual sleep fucntion.  This one won't wake up
250    before the sleep time has really elapsed.  When build with Pth it
251    merely calls pth_sleep and thus suspends only the current
252    thread. */
253 void
254 gnupg_sleep (unsigned int seconds)
255 {
256 #ifdef HAVE_PTH
257   /* With Pth we force a regular sleep for seconds == 0 so that also
258      the process will give up its timeslot.  */
259   if (!seconds)
260     {
261 # ifdef HAVE_W32_SYSTEM    
262       Sleep (0);
263 # else
264       sleep (0);
265 # endif
266     }
267   pth_sleep (seconds);
268 #else
269   /* Fixme:  make sure that a sleep won't wake up to early.  */
270 # ifdef HAVE_W32_SYSTEM    
271   Sleep (seconds*1000);
272 # else
273   sleep (seconds);
274 # endif
275 #endif
276 }
277
278
279 /* This function is a NOP for POSIX systems but required under Windows
280    as the file handles as returned by OS calls (like CreateFile) are
281    different from the libc file descriptors (like open). This function
282    translates system file handles to libc file handles.  FOR_WRITE
283    gives the direction of the handle.  */
284 int
285 translate_sys2libc_fd (gnupg_fd_t fd, int for_write)
286 {
287 #ifdef HAVE_W32_SYSTEM
288   int x;
289
290   if (fd == GNUPG_INVALID_FD)
291     return -1;
292   
293   /* Note that _open_osfhandle is currently defined to take and return
294      a long.  */
295   x = _open_osfhandle ((long)fd, for_write ? 1 : 0);
296   if (x == -1)
297     log_error ("failed to translate osfhandle %p\n", (void *) fd);
298   return x;
299 #else /*!HAVE_W32_SYSTEM */
300   return fd;
301 #endif
302 }
303
304 /* This is the same as translate_sys2libc_fd but takes an integer
305    which is assumed to be such an system handle.  */
306 int
307 translate_sys2libc_fd_int (int fd, int for_write)
308 {
309 #ifdef HAVE_W32_SYSTEM
310   if (fd <= 2)
311     return fd;  /* Do not do this for error, stdin, stdout, stderr. */
312
313   return translate_sys2libc_fd ((void*)fd, for_write);
314 #else
315   return fd;
316 #endif
317 }
318
319
320
321 /* Replacement for tmpfile().  This is required because the tmpfile
322    function of Windows' runtime library is broken, insecure, ignores
323    TMPDIR and so on.  In addition we create a file with an inheritable
324    handle.  */
325 FILE *
326 gnupg_tmpfile (void)
327 {
328 #ifdef HAVE_W32_SYSTEM
329   int attempts, n;
330   char buffer[MAX_PATH+7+12+1];
331   char *name, *p;
332   HANDLE file;
333   int pid = GetCurrentProcessId ();
334   unsigned int value;
335   int i;
336   SECURITY_ATTRIBUTES sec_attr;
337
338   memset (&sec_attr, 0, sizeof sec_attr );
339   sec_attr.nLength = sizeof sec_attr;
340   sec_attr.bInheritHandle = TRUE;
341
342   n = GetTempPath (MAX_PATH+1, buffer);
343   if (!n || n > MAX_PATH || strlen (buffer) > MAX_PATH)
344     {
345       errno = ENOENT;
346       return NULL;
347     }
348   p = buffer + strlen (buffer);
349   p = stpcpy (p, "_gnupg");
350   /* We try to create the directory but don't care about an error as
351      it may already exist and the CreateFile would throw an error
352      anyway.  */
353   CreateDirectory (buffer, NULL);
354   *p++ = '\\';
355   name = p;
356   for (attempts=0; attempts < 10; attempts++)
357     {
358       p = name;
359       value = (GetTickCount () ^ ((pid<<16) & 0xffff0000));
360       for (i=0; i < 8; i++)
361         {
362           *p++ = tohex (((value >> 28) & 0x0f));
363           value <<= 4;
364         }
365       strcpy (p, ".tmp");
366       file = CreateFile (buffer,
367                          GENERIC_READ | GENERIC_WRITE,
368                          0,
369                          &sec_attr,
370                          CREATE_NEW,
371                          FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
372                          NULL);
373       if (file != INVALID_HANDLE_VALUE)
374         {
375           FILE *fp;
376           int fd = _open_osfhandle ((long)file, 0);
377           if (fd == -1)
378             {
379               CloseHandle (file);
380               return NULL;
381             }
382           fp = fdopen (fd, "w+b");
383           if (!fp)
384             {
385               int save = errno;
386               close (fd);
387               errno = save;
388               return NULL;
389             }
390           return fp;
391         }
392       Sleep (1); /* One ms as this is the granularity of GetTickCount.  */
393     }
394   errno = ENOENT;
395   return NULL;
396 #else /*!HAVE_W32_SYSTEM*/
397   return tmpfile ();
398 #endif /*!HAVE_W32_SYSTEM*/
399 }