2008-02-09 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / common / sysutils.c
blob869dc2a1061b52e35cf5dbf6fd5a748e8d1afc05
1 /* sysutils.c - system helpers
2 * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004,
3 * 2007 Free Software Foundation, Inc.
5 * This file is part of GnuPG.
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.
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.
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/>.
21 #include <config.h>
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
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 #include <fcntl.h>
53 #include "util.h"
54 #include "i18n.h"
56 #include "sysutils.h"
58 #define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
61 #if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2
62 #warning using trap_unaligned
63 static int
64 setsysinfo(unsigned long op, void *buffer, unsigned long size,
65 int *start, void *arg, unsigned long flag)
67 return syscall(__NR_osf_setsysinfo, op, buffer, size, start, arg, flag);
70 void
71 trap_unaligned(void)
73 unsigned int buf[2];
75 buf[0] = SSIN_UACPROC;
76 buf[1] = UAC_SIGBUS | UAC_NOPRINT;
77 setsysinfo(SSI_NVPAIRS, buf, 1, 0, 0, 0);
79 #else
80 void
81 trap_unaligned(void)
82 { /* dummy */
84 #endif
87 int
88 disable_core_dumps (void)
90 #ifdef HAVE_DOSISH_SYSTEM
91 return 0;
92 #else
93 # ifdef HAVE_SETRLIMIT
94 struct rlimit limit;
96 /* We only set the current limit unless we were not able to
97 retrieve the old value. */
98 if (getrlimit (RLIMIT_CORE, &limit))
99 limit.rlim_max = 0;
100 limit.rlim_cur = 0;
101 if( !setrlimit (RLIMIT_CORE, &limit) )
102 return 0;
103 if( errno != EINVAL && errno != ENOSYS )
104 log_fatal (_("can't disable core dumps: %s\n"), strerror(errno) );
105 #endif
106 return 1;
107 #endif
111 enable_core_dumps (void)
113 #ifdef HAVE_DOSISH_SYSTEM
114 return 0;
115 #else
116 # ifdef HAVE_SETRLIMIT
117 struct rlimit limit;
119 if (getrlimit (RLIMIT_CORE, &limit))
120 return 1;
121 limit.rlim_cur = limit.rlim_max;
122 setrlimit (RLIMIT_CORE, &limit);
123 return 1; /* We always return true because this function is
124 merely a debugging aid. */
125 # endif
126 return 1;
127 #endif
132 /* Return a string which is used as a kind of process ID */
133 const byte *
134 get_session_marker( size_t *rlen )
136 static byte marker[SIZEOF_UNSIGNED_LONG*2];
137 static int initialized;
139 if ( !initialized ) {
140 volatile ulong aa, bb; /* we really want the uninitialized value */
141 ulong a, b;
143 initialized = 1;
144 /* Although this marker is guessable it is not easy to use
145 * for a faked control packet because an attacker does not
146 * have enough control about the time the verification does
147 * take place. Of course, we can add just more random but
148 * than we need the random generator even for verification
149 * tasks - which does not make sense. */
150 a = aa ^ (ulong)getpid();
151 b = bb ^ (ulong)time(NULL);
152 memcpy( marker, &a, SIZEOF_UNSIGNED_LONG );
153 memcpy( marker+SIZEOF_UNSIGNED_LONG, &b, SIZEOF_UNSIGNED_LONG );
155 *rlen = sizeof(marker);
156 return marker;
160 #if 0 /* not yet needed - Note that this will require inclusion of
161 cmacros.am in Makefile.am */
163 check_permissions(const char *path,int extension,int checkonly)
165 #if defined(HAVE_STAT) && !defined(HAVE_DOSISH_SYSTEM)
166 char *tmppath;
167 struct stat statbuf;
168 int ret=1;
169 int isdir=0;
171 if(opt.no_perm_warn)
172 return 0;
174 if(extension && path[0]!=DIRSEP_C)
176 if(strchr(path,DIRSEP_C))
177 tmppath=make_filename(path,NULL);
178 else
179 tmppath=make_filename(GNUPG_LIBDIR,path,NULL);
181 else
182 tmppath=m_strdup(path);
184 /* It's okay if the file doesn't exist */
185 if(stat(tmppath,&statbuf)!=0)
187 ret=0;
188 goto end;
191 isdir=S_ISDIR(statbuf.st_mode);
193 /* Per-user files must be owned by the user. Extensions must be
194 owned by the user or root. */
195 if((!extension && statbuf.st_uid != getuid()) ||
196 (extension && statbuf.st_uid!=0 && statbuf.st_uid!=getuid()))
198 if(!checkonly)
199 log_info(_("Warning: unsafe ownership on %s \"%s\"\n"),
200 isdir?"directory":extension?"extension":"file",path);
201 goto end;
204 /* This works for both directories and files - basically, we don't
205 care what the owner permissions are, so long as the group and
206 other permissions are 0 for per-user files, and non-writable for
207 extensions. */
208 if((extension && (statbuf.st_mode & (S_IWGRP|S_IWOTH)) !=0) ||
209 (!extension && (statbuf.st_mode & (S_IRWXG|S_IRWXO)) != 0))
211 char *dir;
213 /* However, if the directory the directory/file is in is owned
214 by the user and is 700, then this is not a problem.
215 Theoretically, we could walk this test up to the root
216 directory /, but for the sake of sanity, I'm stopping at one
217 level down. */
219 dir= make_dirname (tmppath);
220 if(stat(dir,&statbuf)==0 && statbuf.st_uid==getuid() &&
221 S_ISDIR(statbuf.st_mode) && (statbuf.st_mode & (S_IRWXG|S_IRWXO))==0)
223 xfree (dir);
224 ret=0;
225 goto end;
228 m_free(dir);
230 if(!checkonly)
231 log_info(_("Warning: unsafe permissions on %s \"%s\"\n"),
232 isdir?"directory":extension?"extension":"file",path);
233 goto end;
236 ret=0;
238 end:
239 m_free(tmppath);
241 return ret;
243 #endif /* HAVE_STAT && !HAVE_DOSISH_SYSTEM */
245 return 0;
247 #endif
250 /* Wrapper around the usual sleep fucntion. This one won't wake up
251 before the sleep time has really elapsed. When build with Pth it
252 merely calls pth_sleep and thus suspends only the current
253 thread. */
254 void
255 gnupg_sleep (unsigned int seconds)
257 #ifdef HAVE_PTH
258 /* With Pth we force a regular sleep for seconds == 0 so that also
259 the process will give up its timeslot. */
260 if (!seconds)
262 # ifdef HAVE_W32_SYSTEM
263 Sleep (0);
264 # else
265 sleep (0);
266 # endif
268 pth_sleep (seconds);
269 #else
270 /* Fixme: make sure that a sleep won't wake up to early. */
271 # ifdef HAVE_W32_SYSTEM
272 Sleep (seconds*1000);
273 # else
274 sleep (seconds);
275 # endif
276 #endif
280 /* This function is a NOP for POSIX systems but required under Windows
281 as the file handles as returned by OS calls (like CreateFile) are
282 different from the libc file descriptors (like open). This function
283 translates system file handles to libc file handles. FOR_WRITE
284 gives the direction of the handle. */
286 translate_sys2libc_fd (gnupg_fd_t fd, int for_write)
288 #ifdef HAVE_W32_SYSTEM
289 int x;
291 if (fd == GNUPG_INVALID_FD)
292 return -1;
294 /* Note that _open_osfhandle is currently defined to take and return
295 a long. */
296 x = _open_osfhandle ((long)fd, for_write ? 1 : 0);
297 if (x == -1)
298 log_error ("failed to translate osfhandle %p\n", (void *) fd);
299 return x;
300 #else /*!HAVE_W32_SYSTEM */
301 return fd;
302 #endif
305 /* This is the same as translate_sys2libc_fd but takes an integer
306 which is assumed to be such an system handle. */
308 translate_sys2libc_fd_int (int fd, int for_write)
310 #ifdef HAVE_W32_SYSTEM
311 if (fd <= 2)
312 return fd; /* Do not do this for error, stdin, stdout, stderr. */
314 return translate_sys2libc_fd ((void*)fd, for_write);
315 #else
316 return fd;
317 #endif
322 /* Replacement for tmpfile(). This is required because the tmpfile
323 function of Windows' runtime library is broken, insecure, ignores
324 TMPDIR and so on. In addition we create a file with an inheritable
325 handle. */
326 FILE *
327 gnupg_tmpfile (void)
329 #ifdef HAVE_W32_SYSTEM
330 int attempts, n;
331 char buffer[MAX_PATH+7+12+1];
332 char *name, *p;
333 HANDLE file;
334 int pid = GetCurrentProcessId ();
335 unsigned int value;
336 int i;
337 SECURITY_ATTRIBUTES sec_attr;
339 memset (&sec_attr, 0, sizeof sec_attr );
340 sec_attr.nLength = sizeof sec_attr;
341 sec_attr.bInheritHandle = TRUE;
343 n = GetTempPath (MAX_PATH+1, buffer);
344 if (!n || n > MAX_PATH || strlen (buffer) > MAX_PATH)
346 errno = ENOENT;
347 return NULL;
349 p = buffer + strlen (buffer);
350 p = stpcpy (p, "_gnupg");
351 /* We try to create the directory but don't care about an error as
352 it may already exist and the CreateFile would throw an error
353 anyway. */
354 CreateDirectory (buffer, NULL);
355 *p++ = '\\';
356 name = p;
357 for (attempts=0; attempts < 10; attempts++)
359 p = name;
360 value = (GetTickCount () ^ ((pid<<16) & 0xffff0000));
361 for (i=0; i < 8; i++)
363 *p++ = tohex (((value >> 28) & 0x0f));
364 value <<= 4;
366 strcpy (p, ".tmp");
367 file = CreateFile (buffer,
368 GENERIC_READ | GENERIC_WRITE,
370 &sec_attr,
371 CREATE_NEW,
372 FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
373 NULL);
374 if (file != INVALID_HANDLE_VALUE)
376 FILE *fp;
377 int fd = _open_osfhandle ((long)file, 0);
378 if (fd == -1)
380 CloseHandle (file);
381 return NULL;
383 fp = fdopen (fd, "w+b");
384 if (!fp)
386 int save = errno;
387 close (fd);
388 errno = save;
389 return NULL;
391 return fp;
393 Sleep (1); /* One ms as this is the granularity of GetTickCount. */
395 errno = ENOENT;
396 return NULL;
397 #else /*!HAVE_W32_SYSTEM*/
398 return tmpfile ();
399 #endif /*!HAVE_W32_SYSTEM*/
403 /* Make sure that the standard file descriptors are opened. Obviously
404 some folks close them before an exec and the next file we open will
405 get one of them assigned and thus any output (i.e. diagnostics) end
406 up in that file (e.g. the trustdb). Not actually a gpg problem as
407 this will hapen with almost all utilities when called in a wrong
408 way. However we try to minimize the damage here and raise
409 awareness of the problem.
411 Must be called before we open any files! */
412 void
413 gnupg_reopen_std (const char *pgmname)
415 #if defined(HAVE_STAT) && !defined(HAVE_W32_SYSTEM)
416 struct stat statbuf;
417 int did_stdin = 0;
418 int did_stdout = 0;
419 int did_stderr = 0;
420 FILE *complain;
422 if (fstat (STDIN_FILENO, &statbuf) == -1 && errno ==EBADF)
424 if (open ("/dev/null",O_RDONLY) == STDIN_FILENO)
425 did_stdin = 1;
426 else
427 did_stdin = 2;
430 if (fstat (STDOUT_FILENO, &statbuf) == -1 && errno == EBADF)
432 if (open ("/dev/null",O_WRONLY) == STDOUT_FILENO)
433 did_stdout = 1;
434 else
435 did_stdout = 2;
438 if (fstat (STDERR_FILENO, &statbuf)==-1 && errno==EBADF)
440 if (open ("/dev/null", O_WRONLY) == STDERR_FILENO)
441 did_stderr = 1;
442 else
443 did_stderr = 2;
446 /* It's hard to log this sort of thing since the filehandle we would
447 complain to may be closed... */
448 if (!did_stderr)
449 complain = stderr;
450 else if (!did_stdout)
451 complain = stdout;
452 else
453 complain = NULL;
455 if (complain)
457 if (did_stdin == 1)
458 fprintf (complain, "%s: WARNING: standard input reopened\n", pgmname);
459 if (did_stdout == 1)
460 fprintf (complain, "%s: WARNING: standard output reopened\n", pgmname);
461 if (did_stderr == 1)
462 fprintf (complain, "%s: WARNING: standard error reopened\n", pgmname);
464 if (did_stdin == 2 || did_stdout == 2 || did_stderr == 2)
465 fprintf(complain,"%s: fatal: unable to reopen standard input,"
466 " output, or error\n", pgmname);
469 if (did_stdin == 2 || did_stdout == 2 || did_stderr == 2)
470 exit (3);
471 #endif /* HAVE_STAT && !HAVE_W32_SYSTEM */