Fix last change
[gnupg.git] / common / sysutils.c
blob8e0c75c1ab17cb833c512cc3fdc55841ec1f383a
1 /* sysutils.c - system helpers
2 * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004,
3 * 2007, 2008 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 # 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>
54 #include "util.h"
55 #include "i18n.h"
57 #include "sysutils.h"
59 #define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
62 #if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2
63 #warning using trap_unaligned
64 static int
65 setsysinfo(unsigned long op, void *buffer, unsigned long size,
66 int *start, void *arg, unsigned long flag)
68 return syscall(__NR_osf_setsysinfo, op, buffer, size, start, arg, flag);
71 void
72 trap_unaligned(void)
74 unsigned int buf[2];
76 buf[0] = SSIN_UACPROC;
77 buf[1] = UAC_SIGBUS | UAC_NOPRINT;
78 setsysinfo(SSI_NVPAIRS, buf, 1, 0, 0, 0);
80 #else
81 void
82 trap_unaligned(void)
83 { /* dummy */
85 #endif
88 int
89 disable_core_dumps (void)
91 #ifdef HAVE_DOSISH_SYSTEM
92 return 0;
93 #else
94 # ifdef HAVE_SETRLIMIT
95 struct rlimit limit;
97 /* We only set the current limit unless we were not able to
98 retrieve the old value. */
99 if (getrlimit (RLIMIT_CORE, &limit))
100 limit.rlim_max = 0;
101 limit.rlim_cur = 0;
102 if( !setrlimit (RLIMIT_CORE, &limit) )
103 return 0;
104 if( errno != EINVAL && errno != ENOSYS )
105 log_fatal (_("can't disable core dumps: %s\n"), strerror(errno) );
106 #endif
107 return 1;
108 #endif
112 enable_core_dumps (void)
114 #ifdef HAVE_DOSISH_SYSTEM
115 return 0;
116 #else
117 # ifdef HAVE_SETRLIMIT
118 struct rlimit limit;
120 if (getrlimit (RLIMIT_CORE, &limit))
121 return 1;
122 limit.rlim_cur = limit.rlim_max;
123 setrlimit (RLIMIT_CORE, &limit);
124 return 1; /* We always return true because this function is
125 merely a debugging aid. */
126 # endif
127 return 1;
128 #endif
133 /* Return a string which is used as a kind of process ID */
134 const byte *
135 get_session_marker( size_t *rlen )
137 static byte marker[SIZEOF_UNSIGNED_LONG*2];
138 static int initialized;
140 if ( !initialized ) {
141 volatile ulong aa, bb; /* we really want the uninitialized value */
142 ulong a, b;
144 initialized = 1;
145 /* Although this marker is guessable it is not easy to use
146 * for a faked control packet because an attacker does not
147 * have enough control about the time the verification does
148 * take place. Of course, we can add just more random but
149 * than we need the random generator even for verification
150 * tasks - which does not make sense. */
151 a = aa ^ (ulong)getpid();
152 b = bb ^ (ulong)time(NULL);
153 memcpy( marker, &a, SIZEOF_UNSIGNED_LONG );
154 memcpy( marker+SIZEOF_UNSIGNED_LONG, &b, SIZEOF_UNSIGNED_LONG );
156 *rlen = sizeof(marker);
157 return marker;
161 #if 0 /* not yet needed - Note that this will require inclusion of
162 cmacros.am in Makefile.am */
164 check_permissions(const char *path,int extension,int checkonly)
166 #if defined(HAVE_STAT) && !defined(HAVE_DOSISH_SYSTEM)
167 char *tmppath;
168 struct stat statbuf;
169 int ret=1;
170 int isdir=0;
172 if(opt.no_perm_warn)
173 return 0;
175 if(extension && path[0]!=DIRSEP_C)
177 if(strchr(path,DIRSEP_C))
178 tmppath=make_filename(path,NULL);
179 else
180 tmppath=make_filename(GNUPG_LIBDIR,path,NULL);
182 else
183 tmppath=m_strdup(path);
185 /* It's okay if the file doesn't exist */
186 if(stat(tmppath,&statbuf)!=0)
188 ret=0;
189 goto end;
192 isdir=S_ISDIR(statbuf.st_mode);
194 /* Per-user files must be owned by the user. Extensions must be
195 owned by the user or root. */
196 if((!extension && statbuf.st_uid != getuid()) ||
197 (extension && statbuf.st_uid!=0 && statbuf.st_uid!=getuid()))
199 if(!checkonly)
200 log_info(_("Warning: unsafe ownership on %s \"%s\"\n"),
201 isdir?"directory":extension?"extension":"file",path);
202 goto end;
205 /* This works for both directories and files - basically, we don't
206 care what the owner permissions are, so long as the group and
207 other permissions are 0 for per-user files, and non-writable for
208 extensions. */
209 if((extension && (statbuf.st_mode & (S_IWGRP|S_IWOTH)) !=0) ||
210 (!extension && (statbuf.st_mode & (S_IRWXG|S_IRWXO)) != 0))
212 char *dir;
214 /* However, if the directory the directory/file is in is owned
215 by the user and is 700, then this is not a problem.
216 Theoretically, we could walk this test up to the root
217 directory /, but for the sake of sanity, I'm stopping at one
218 level down. */
220 dir= make_dirname (tmppath);
221 if(stat(dir,&statbuf)==0 && statbuf.st_uid==getuid() &&
222 S_ISDIR(statbuf.st_mode) && (statbuf.st_mode & (S_IRWXG|S_IRWXO))==0)
224 xfree (dir);
225 ret=0;
226 goto end;
229 m_free(dir);
231 if(!checkonly)
232 log_info(_("Warning: unsafe permissions on %s \"%s\"\n"),
233 isdir?"directory":extension?"extension":"file",path);
234 goto end;
237 ret=0;
239 end:
240 m_free(tmppath);
242 return ret;
244 #endif /* HAVE_STAT && !HAVE_DOSISH_SYSTEM */
246 return 0;
248 #endif
251 /* Wrapper around the usual sleep fucntion. This one won't wake up
252 before the sleep time has really elapsed. When build with Pth it
253 merely calls pth_sleep and thus suspends only the current
254 thread. */
255 void
256 gnupg_sleep (unsigned int seconds)
258 #ifdef HAVE_PTH
259 /* With Pth we force a regular sleep for seconds == 0 so that also
260 the process will give up its timeslot. */
261 if (!seconds)
263 # ifdef HAVE_W32_SYSTEM
264 Sleep (0);
265 # else
266 sleep (0);
267 # endif
269 pth_sleep (seconds);
270 #else
271 /* Fixme: make sure that a sleep won't wake up to early. */
272 # ifdef HAVE_W32_SYSTEM
273 Sleep (seconds*1000);
274 # else
275 sleep (seconds);
276 # endif
277 #endif
281 /* This function is a NOP for POSIX systems but required under Windows
282 as the file handles as returned by OS calls (like CreateFile) are
283 different from the libc file descriptors (like open). This function
284 translates system file handles to libc file handles. FOR_WRITE
285 gives the direction of the handle. */
287 translate_sys2libc_fd (gnupg_fd_t fd, int for_write)
289 #ifdef HAVE_W32_SYSTEM
290 int x;
292 if (fd == GNUPG_INVALID_FD)
293 return -1;
295 /* Note that _open_osfhandle is currently defined to take and return
296 a long. */
297 x = _open_osfhandle ((long)fd, for_write ? 1 : 0);
298 if (x == -1)
299 log_error ("failed to translate osfhandle %p\n", (void *) fd);
300 return x;
301 #else /*!HAVE_W32_SYSTEM */
302 (void)for_write;
303 return fd;
304 #endif
307 /* This is the same as translate_sys2libc_fd but takes an integer
308 which is assumed to be such an system handle. */
310 translate_sys2libc_fd_int (int fd, int for_write)
312 #ifdef HAVE_W32_SYSTEM
313 if (fd <= 2)
314 return fd; /* Do not do this for error, stdin, stdout, stderr. */
316 return translate_sys2libc_fd ((void*)fd, for_write);
317 #else
318 (void)for_write;
319 return fd;
320 #endif
325 /* Replacement for tmpfile(). This is required because the tmpfile
326 function of Windows' runtime library is broken, insecure, ignores
327 TMPDIR and so on. In addition we create a file with an inheritable
328 handle. */
329 FILE *
330 gnupg_tmpfile (void)
332 #ifdef HAVE_W32_SYSTEM
333 int attempts, n;
334 char buffer[MAX_PATH+7+12+1];
335 char *name, *p;
336 HANDLE file;
337 int pid = GetCurrentProcessId ();
338 unsigned int value;
339 int i;
340 SECURITY_ATTRIBUTES sec_attr;
342 memset (&sec_attr, 0, sizeof sec_attr );
343 sec_attr.nLength = sizeof sec_attr;
344 sec_attr.bInheritHandle = TRUE;
346 n = GetTempPath (MAX_PATH+1, buffer);
347 if (!n || n > MAX_PATH || strlen (buffer) > MAX_PATH)
349 errno = ENOENT;
350 return NULL;
352 p = buffer + strlen (buffer);
353 p = stpcpy (p, "_gnupg");
354 /* We try to create the directory but don't care about an error as
355 it may already exist and the CreateFile would throw an error
356 anyway. */
357 CreateDirectory (buffer, NULL);
358 *p++ = '\\';
359 name = p;
360 for (attempts=0; attempts < 10; attempts++)
362 p = name;
363 value = (GetTickCount () ^ ((pid<<16) & 0xffff0000));
364 for (i=0; i < 8; i++)
366 *p++ = tohex (((value >> 28) & 0x0f));
367 value <<= 4;
369 strcpy (p, ".tmp");
370 file = CreateFile (buffer,
371 GENERIC_READ | GENERIC_WRITE,
373 &sec_attr,
374 CREATE_NEW,
375 FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
376 NULL);
377 if (file != INVALID_HANDLE_VALUE)
379 FILE *fp;
380 int fd = _open_osfhandle ((long)file, 0);
381 if (fd == -1)
383 CloseHandle (file);
384 return NULL;
386 fp = fdopen (fd, "w+b");
387 if (!fp)
389 int save = errno;
390 close (fd);
391 errno = save;
392 return NULL;
394 return fp;
396 Sleep (1); /* One ms as this is the granularity of GetTickCount. */
398 errno = ENOENT;
399 return NULL;
400 #else /*!HAVE_W32_SYSTEM*/
401 return tmpfile ();
402 #endif /*!HAVE_W32_SYSTEM*/
406 /* Make sure that the standard file descriptors are opened. Obviously
407 some folks close them before an exec and the next file we open will
408 get one of them assigned and thus any output (i.e. diagnostics) end
409 up in that file (e.g. the trustdb). Not actually a gpg problem as
410 this will hapen with almost all utilities when called in a wrong
411 way. However we try to minimize the damage here and raise
412 awareness of the problem.
414 Must be called before we open any files! */
415 void
416 gnupg_reopen_std (const char *pgmname)
418 #if defined(HAVE_STAT) && !defined(HAVE_W32_SYSTEM)
419 struct stat statbuf;
420 int did_stdin = 0;
421 int did_stdout = 0;
422 int did_stderr = 0;
423 FILE *complain;
425 if (fstat (STDIN_FILENO, &statbuf) == -1 && errno ==EBADF)
427 if (open ("/dev/null",O_RDONLY) == STDIN_FILENO)
428 did_stdin = 1;
429 else
430 did_stdin = 2;
433 if (fstat (STDOUT_FILENO, &statbuf) == -1 && errno == EBADF)
435 if (open ("/dev/null",O_WRONLY) == STDOUT_FILENO)
436 did_stdout = 1;
437 else
438 did_stdout = 2;
441 if (fstat (STDERR_FILENO, &statbuf)==-1 && errno==EBADF)
443 if (open ("/dev/null", O_WRONLY) == STDERR_FILENO)
444 did_stderr = 1;
445 else
446 did_stderr = 2;
449 /* It's hard to log this sort of thing since the filehandle we would
450 complain to may be closed... */
451 if (!did_stderr)
452 complain = stderr;
453 else if (!did_stdout)
454 complain = stdout;
455 else
456 complain = NULL;
458 if (complain)
460 if (did_stdin == 1)
461 fprintf (complain, "%s: WARNING: standard input reopened\n", pgmname);
462 if (did_stdout == 1)
463 fprintf (complain, "%s: WARNING: standard output reopened\n", pgmname);
464 if (did_stderr == 1)
465 fprintf (complain, "%s: WARNING: standard error reopened\n", pgmname);
467 if (did_stdin == 2 || did_stdout == 2 || did_stderr == 2)
468 fprintf(complain,"%s: fatal: unable to reopen standard input,"
469 " output, or error\n", pgmname);
472 if (did_stdin == 2 || did_stdout == 2 || did_stderr == 2)
473 exit (3);
474 #else /* !(HAVE_STAT && !HAVE_W32_SYSTEM) */
475 (void)pgmname;
476 #endif
480 /* Hack required for Windows. */
481 void
482 gnupg_allow_set_foregound_window (pid_t pid)
484 if (!pid)
485 log_info ("%s called with invalid pid %lu\n",
486 "gnupg_allow_set_foregound_window", (unsigned long)pid);
487 #ifdef HAVE_W32_SYSTEM
488 else if (!AllowSetForegroundWindow ((pid_t)pid == (pid_t)(-1)?ASFW_ANY:pid))
489 log_info ("AllowSetForegroundWindow(%lu) failed: %s\n",
490 (unsigned long)pid, w32_strerror (-1));
491 #endif