build: Require latest released libraries
[gnupg.git] / common / sysutils.c
1 /* sysutils.c -  system helpers
2  * Copyright (C) 1991-2001, 2003-2004,
3  *               2006-2008  Free Software Foundation, Inc.
4  * Copyright (C) 2013-2014 Werner Koch
5  *
6  * This file is part of GnuPG.
7  *
8  * This file is free software; you can redistribute it and/or modify
9  * it under the terms of either
10  *
11  *   - the GNU Lesser General Public License as published by the Free
12  *     Software Foundation; either version 3 of the License, or (at
13  *     your option) any later version.
14  *
15  * or
16  *
17  *   - the GNU General Public License as published by the Free
18  *     Software Foundation; either version 2 of the License, or (at
19  *     your option) any later version.
20  *
21  * or both in parallel, as here.
22  *
23  * This file is distributed in the hope that it will be useful,
24  * but WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26  * GNU General Public License for more details.
27  *
28  * You should have received a copy of the GNU General Public License
29  * along with this program; if not, see <http://www.gnu.org/licenses/>.
30  */
31
32 #include <config.h>
33
34 #ifdef WITHOUT_NPTH /* Give the Makefile a chance to build without Pth.  */
35 # undef HAVE_NPTH
36 # undef USE_NPTH
37 #endif
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <stdint.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <errno.h>
45 #ifdef HAVE_STAT
46 # include <sys/stat.h>
47 #endif
48 #if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2
49 # include <asm/sysinfo.h>
50 # include <asm/unistd.h>
51 #endif
52 #ifdef HAVE_SETRLIMIT
53 # include <time.h>
54 # include <sys/time.h>
55 # include <sys/resource.h>
56 #endif
57 #ifdef HAVE_W32_SYSTEM
58 # if WINVER < 0x0500
59 #   define WINVER 0x0500  /* Required for AllowSetForegroundWindow.  */
60 # endif
61 # ifdef HAVE_WINSOCK2_H
62 #  include <winsock2.h>
63 # endif
64 # include <windows.h>
65 #endif
66 #ifdef HAVE_NPTH
67 # include <npth.h>
68 #endif
69 #include <fcntl.h>
70
71 #include <assuan.h>
72
73 #include "util.h"
74 #include "i18n.h"
75
76 #include "sysutils.h"
77
78 #define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
79
80
81 #if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2
82 #warning using trap_unaligned
83 static int
84 setsysinfo(unsigned long op, void *buffer, unsigned long size,
85                      int *start, void *arg, unsigned long flag)
86 {
87     return syscall(__NR_osf_setsysinfo, op, buffer, size, start, arg, flag);
88 }
89
90 void
91 trap_unaligned(void)
92 {
93     unsigned int buf[2];
94
95     buf[0] = SSIN_UACPROC;
96     buf[1] = UAC_SIGBUS | UAC_NOPRINT;
97     setsysinfo(SSI_NVPAIRS, buf, 1, 0, 0, 0);
98 }
99 #else
100 void
101 trap_unaligned(void)
102 {  /* dummy */
103 }
104 #endif
105
106
107 int
108 disable_core_dumps (void)
109 {
110 #ifdef HAVE_DOSISH_SYSTEM
111     return 0;
112 #else
113 # ifdef HAVE_SETRLIMIT
114     struct rlimit limit;
115
116     /* We only set the current limit unless we were not able to
117        retrieve the old value. */
118     if (getrlimit (RLIMIT_CORE, &limit))
119       limit.rlim_max = 0;
120     limit.rlim_cur = 0;
121     if( !setrlimit (RLIMIT_CORE, &limit) )
122         return 0;
123     if( errno != EINVAL && errno != ENOSYS )
124         log_fatal (_("can't disable core dumps: %s\n"), strerror(errno) );
125 #endif
126     return 1;
127 #endif
128 }
129
130 int
131 enable_core_dumps (void)
132 {
133 #ifdef HAVE_DOSISH_SYSTEM
134     return 0;
135 #else
136 # ifdef HAVE_SETRLIMIT
137     struct rlimit limit;
138
139     if (getrlimit (RLIMIT_CORE, &limit))
140       return 1;
141     limit.rlim_cur = limit.rlim_max;
142     setrlimit (RLIMIT_CORE, &limit);
143     return 1; /* We always return true because this function is
144                  merely a debugging aid. */
145 # endif
146     return 1;
147 #endif
148 }
149
150
151
152 /* Return a string which is used as a kind of process ID.  */
153 const byte *
154 get_session_marker (size_t *rlen)
155 {
156   static byte marker[SIZEOF_UNSIGNED_LONG*2];
157   static int initialized;
158
159   if (!initialized)
160     {
161       gcry_create_nonce (marker, sizeof marker);
162       initialized = 1;
163     }
164   *rlen = sizeof (marker);
165   return marker;
166 }
167
168 /* Return a random number in an unsigned int. */
169 unsigned int
170 get_uint_nonce (void)
171 {
172   unsigned int value;
173
174   gcry_create_nonce (&value, sizeof value);
175   return value;
176 }
177
178
179
180 #if 0 /* not yet needed - Note that this will require inclusion of
181          cmacros.am in Makefile.am */
182 int
183 check_permissions(const char *path,int extension,int checkonly)
184 {
185 #if defined(HAVE_STAT) && !defined(HAVE_DOSISH_SYSTEM)
186   char *tmppath;
187   struct stat statbuf;
188   int ret=1;
189   int isdir=0;
190
191   if(opt.no_perm_warn)
192     return 0;
193
194   if(extension && path[0]!=DIRSEP_C)
195     {
196       if(strchr(path,DIRSEP_C))
197         tmppath=make_filename(path,NULL);
198       else
199         tmppath=make_filename(GNUPG_LIBDIR,path,NULL);
200     }
201   else
202     tmppath=m_strdup(path);
203
204   /* It's okay if the file doesn't exist */
205   if(stat(tmppath,&statbuf)!=0)
206     {
207       ret=0;
208       goto end;
209     }
210
211   isdir=S_ISDIR(statbuf.st_mode);
212
213   /* Per-user files must be owned by the user.  Extensions must be
214      owned by the user or root. */
215   if((!extension && statbuf.st_uid != getuid()) ||
216      (extension && statbuf.st_uid!=0 && statbuf.st_uid!=getuid()))
217     {
218       if(!checkonly)
219         log_info(_("Warning: unsafe ownership on %s \"%s\"\n"),
220                  isdir?"directory":extension?"extension":"file",path);
221       goto end;
222     }
223
224   /* This works for both directories and files - basically, we don't
225      care what the owner permissions are, so long as the group and
226      other permissions are 0 for per-user files, and non-writable for
227      extensions. */
228   if((extension && (statbuf.st_mode & (S_IWGRP|S_IWOTH)) !=0) ||
229      (!extension && (statbuf.st_mode & (S_IRWXG|S_IRWXO)) != 0))
230     {
231       char *dir;
232
233       /* However, if the directory the directory/file is in is owned
234          by the user and is 700, then this is not a problem.
235          Theoretically, we could walk this test up to the root
236          directory /, but for the sake of sanity, I'm stopping at one
237          level down. */
238
239       dir= make_dirname (tmppath);
240       if(stat(dir,&statbuf)==0 && statbuf.st_uid==getuid() &&
241          S_ISDIR(statbuf.st_mode) && (statbuf.st_mode & (S_IRWXG|S_IRWXO))==0)
242         {
243           xfree (dir);
244           ret=0;
245           goto end;
246         }
247
248       m_free(dir);
249
250       if(!checkonly)
251         log_info(_("Warning: unsafe permissions on %s \"%s\"\n"),
252                  isdir?"directory":extension?"extension":"file",path);
253       goto end;
254     }
255
256   ret=0;
257
258  end:
259   m_free(tmppath);
260
261   return ret;
262
263 #endif /* HAVE_STAT && !HAVE_DOSISH_SYSTEM */
264
265   return 0;
266 }
267 #endif
268
269
270 /* Wrapper around the usual sleep function.  This one won't wake up
271    before the sleep time has really elapsed.  When build with Pth it
272    merely calls pth_sleep and thus suspends only the current
273    thread. */
274 void
275 gnupg_sleep (unsigned int seconds)
276 {
277 #ifdef USE_NPTH
278   npth_sleep (seconds);
279 #else
280   /* Fixme:  make sure that a sleep won't wake up to early.  */
281 # ifdef HAVE_W32_SYSTEM
282   Sleep (seconds*1000);
283 # else
284   sleep (seconds);
285 # endif
286 #endif
287 }
288
289
290 /* This function is a NOP for POSIX systems but required under Windows
291    as the file handles as returned by OS calls (like CreateFile) are
292    different from the libc file descriptors (like open). This function
293    translates system file handles to libc file handles.  FOR_WRITE
294    gives the direction of the handle.  */
295 int
296 translate_sys2libc_fd (gnupg_fd_t fd, int for_write)
297 {
298 #if defined(HAVE_W32CE_SYSTEM)
299   (void)for_write;
300   return (int) fd;
301 #elif defined(HAVE_W32_SYSTEM)
302   int x;
303
304   if (fd == GNUPG_INVALID_FD)
305     return -1;
306
307   /* Note that _open_osfhandle is currently defined to take and return
308      a long.  */
309   x = _open_osfhandle ((long)fd, for_write ? 1 : 0);
310   if (x == -1)
311     log_error ("failed to translate osfhandle %p\n", (void *) fd);
312   return x;
313 #else /*!HAVE_W32_SYSTEM */
314   (void)for_write;
315   return fd;
316 #endif
317 }
318
319 /* This is the same as translate_sys2libc_fd but takes an integer
320    which is assumed to be such an system handle.  On WindowsCE the
321    passed FD is a rendezvous ID and the function finishes the pipe
322    creation. */
323 int
324 translate_sys2libc_fd_int (int fd, int for_write)
325 {
326 #if HAVE_W32CE_SYSTEM
327   fd = (int) _assuan_w32ce_finish_pipe (fd, for_write);
328   return translate_sys2libc_fd ((void*)fd, for_write);
329 #elif HAVE_W32_SYSTEM
330   if (fd <= 2)
331     return fd;  /* Do not do this for error, stdin, stdout, stderr. */
332
333   return translate_sys2libc_fd ((void*)fd, for_write);
334 #else
335   (void)for_write;
336   return fd;
337 #endif
338 }
339
340
341
342 /* Replacement for tmpfile().  This is required because the tmpfile
343    function of Windows' runtime library is broken, insecure, ignores
344    TMPDIR and so on.  In addition we create a file with an inheritable
345    handle.  */
346 FILE *
347 gnupg_tmpfile (void)
348 {
349 #ifdef HAVE_W32_SYSTEM
350   int attempts, n;
351 #ifdef HAVE_W32CE_SYSTEM
352   wchar_t buffer[MAX_PATH+7+12+1];
353 # define mystrlen(a) wcslen (a)
354   wchar_t *name, *p;
355 #else
356   char buffer[MAX_PATH+7+12+1];
357 # define mystrlen(a) strlen (a)
358   char *name, *p;
359 #endif
360   HANDLE file;
361   int pid = GetCurrentProcessId ();
362   unsigned int value;
363   int i;
364   SECURITY_ATTRIBUTES sec_attr;
365
366   memset (&sec_attr, 0, sizeof sec_attr );
367   sec_attr.nLength = sizeof sec_attr;
368   sec_attr.bInheritHandle = TRUE;
369
370   n = GetTempPath (MAX_PATH+1, buffer);
371   if (!n || n > MAX_PATH || mystrlen (buffer) > MAX_PATH)
372     {
373       gpg_err_set_errno (ENOENT);
374       return NULL;
375     }
376   p = buffer + mystrlen (buffer);
377 #ifdef HAVE_W32CE_SYSTEM
378   wcscpy (p, L"_gnupg");
379   p += 7;
380 #else
381   p = stpcpy (p, "_gnupg");
382 #endif
383   /* We try to create the directory but don't care about an error as
384      it may already exist and the CreateFile would throw an error
385      anyway.  */
386   CreateDirectory (buffer, NULL);
387   *p++ = '\\';
388   name = p;
389   for (attempts=0; attempts < 10; attempts++)
390     {
391       p = name;
392       value = (GetTickCount () ^ ((pid<<16) & 0xffff0000));
393       for (i=0; i < 8; i++)
394         {
395           *p++ = tohex (((value >> 28) & 0x0f));
396           value <<= 4;
397         }
398 #ifdef HAVE_W32CE_SYSTEM
399       wcscpy (p, L".tmp");
400 #else
401       strcpy (p, ".tmp");
402 #endif
403       file = CreateFile (buffer,
404                          GENERIC_READ | GENERIC_WRITE,
405                          0,
406                          &sec_attr,
407                          CREATE_NEW,
408                          FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
409                          NULL);
410       if (file != INVALID_HANDLE_VALUE)
411         {
412           FILE *fp;
413 #ifdef HAVE_W32CE_SYSTEM
414           int fd = (int)file;
415           fp = _wfdopen (fd, L"w+b");
416 #else
417           int fd = _open_osfhandle ((long)file, 0);
418           if (fd == -1)
419             {
420               CloseHandle (file);
421               return NULL;
422             }
423           fp = fdopen (fd, "w+b");
424 #endif
425           if (!fp)
426             {
427               int save = errno;
428               close (fd);
429               gpg_err_set_errno (save);
430               return NULL;
431             }
432           return fp;
433         }
434       Sleep (1); /* One ms as this is the granularity of GetTickCount.  */
435     }
436   gpg_err_set_errno (ENOENT);
437   return NULL;
438 #undef mystrlen
439 #else /*!HAVE_W32_SYSTEM*/
440   return tmpfile ();
441 #endif /*!HAVE_W32_SYSTEM*/
442 }
443
444
445 /* Make sure that the standard file descriptors are opened. Obviously
446    some folks close them before an exec and the next file we open will
447    get one of them assigned and thus any output (i.e. diagnostics) end
448    up in that file (e.g. the trustdb).  Not actually a gpg problem as
449    this will happen with almost all utilities when called in a wrong
450    way.  However we try to minimize the damage here and raise
451    awareness of the problem.
452
453    Must be called before we open any files! */
454 void
455 gnupg_reopen_std (const char *pgmname)
456 {
457 #if defined(HAVE_STAT) && !defined(HAVE_W32_SYSTEM)
458   struct stat statbuf;
459   int did_stdin = 0;
460   int did_stdout = 0;
461   int did_stderr = 0;
462   FILE *complain;
463
464   if (fstat (STDIN_FILENO, &statbuf) == -1 && errno ==EBADF)
465     {
466       if (open ("/dev/null",O_RDONLY) == STDIN_FILENO)
467         did_stdin = 1;
468       else
469         did_stdin = 2;
470     }
471
472   if (fstat (STDOUT_FILENO, &statbuf) == -1 && errno == EBADF)
473     {
474       if (open ("/dev/null",O_WRONLY) == STDOUT_FILENO)
475         did_stdout = 1;
476       else
477         did_stdout = 2;
478     }
479
480   if (fstat (STDERR_FILENO, &statbuf)==-1 && errno==EBADF)
481     {
482       if (open ("/dev/null", O_WRONLY) == STDERR_FILENO)
483         did_stderr = 1;
484       else
485         did_stderr = 2;
486     }
487
488   /* It's hard to log this sort of thing since the filehandle we would
489      complain to may be closed... */
490   if (!did_stderr)
491     complain = stderr;
492   else if (!did_stdout)
493     complain = stdout;
494   else
495     complain = NULL;
496
497   if (complain)
498     {
499       if (did_stdin == 1)
500         fprintf (complain, "%s: WARNING: standard input reopened\n", pgmname);
501       if (did_stdout == 1)
502         fprintf (complain, "%s: WARNING: standard output reopened\n", pgmname);
503       if (did_stderr == 1)
504         fprintf (complain, "%s: WARNING: standard error reopened\n", pgmname);
505
506       if (did_stdin == 2 || did_stdout == 2 || did_stderr == 2)
507         fprintf(complain,"%s: fatal: unable to reopen standard input,"
508                 " output, or error\n", pgmname);
509     }
510
511   if (did_stdin == 2 || did_stdout == 2 || did_stderr == 2)
512     exit (3);
513 #else /* !(HAVE_STAT && !HAVE_W32_SYSTEM) */
514   (void)pgmname;
515 #endif
516 }
517
518
519 /* Hack required for Windows.  */
520 void
521 gnupg_allow_set_foregound_window (pid_t pid)
522 {
523   if (!pid)
524     log_info ("%s called with invalid pid %lu\n",
525               "gnupg_allow_set_foregound_window", (unsigned long)pid);
526 #if defined(HAVE_W32_SYSTEM) && !defined(HAVE_W32CE_SYSTEM)
527   else if (!AllowSetForegroundWindow ((pid_t)pid == (pid_t)(-1)?ASFW_ANY:pid))
528     log_info ("AllowSetForegroundWindow(%lu) failed: %s\n",
529                (unsigned long)pid, w32_strerror (-1));
530 #endif
531 }
532
533 int
534 gnupg_remove (const char *fname)
535 {
536 #ifdef HAVE_W32CE_SYSTEM
537   int rc;
538   wchar_t *wfname;
539
540   wfname = utf8_to_wchar (fname);
541   if (!wfname)
542     rc = 0;
543   else
544     {
545       rc = DeleteFile (wfname);
546       xfree (wfname);
547     }
548   if (!rc)
549     return -1; /* ERRNO is automagically provided by gpg-error.h.  */
550   return 0;
551 #else
552   return remove (fname);
553 #endif
554 }
555
556
557 #ifndef HAVE_W32_SYSTEM
558 static mode_t
559 modestr_to_mode (const char *modestr)
560 {
561   mode_t mode = 0;
562
563   if (modestr && *modestr)
564     {
565       modestr++;
566       if (*modestr && *modestr++ == 'r')
567         mode |= S_IRUSR;
568       if (*modestr && *modestr++ == 'w')
569         mode |= S_IWUSR;
570       if (*modestr && *modestr++ == 'x')
571         mode |= S_IXUSR;
572       if (*modestr && *modestr++ == 'r')
573         mode |= S_IRGRP;
574       if (*modestr && *modestr++ == 'w')
575         mode |= S_IWGRP;
576       if (*modestr && *modestr++ == 'x')
577         mode |= S_IXGRP;
578       if (*modestr && *modestr++ == 'r')
579         mode |= S_IROTH;
580       if (*modestr && *modestr++ == 'w')
581         mode |= S_IWOTH;
582       if (*modestr && *modestr++ == 'x')
583         mode |= S_IXOTH;
584     }
585
586   return mode;
587 }
588 #endif
589
590
591 /* A wrapper around mkdir which takes a string for the mode argument.
592    This makes it easier to handle the mode argument which is not
593    defined on all systems.  The format of the modestring is
594
595       "-rwxrwxrwx"
596
597    '-' is a don't care or not set.  'r', 'w', 'x' are read allowed,
598    write allowed, execution allowed with the first group for the user,
599    the second for the group and the third for all others.  If the
600    string is shorter than above the missing mode characters are meant
601    to be not set.  */
602 int
603 gnupg_mkdir (const char *name, const char *modestr)
604 {
605 #ifdef HAVE_W32CE_SYSTEM
606   wchar_t *wname;
607   (void)modestr;
608
609   wname = utf8_to_wchar (name);
610   if (!wname)
611     return -1;
612   if (!CreateDirectoryW (wname, NULL))
613     {
614       xfree (wname);
615       return -1;  /* ERRNO is automagically provided by gpg-error.h.  */
616     }
617   xfree (wname);
618   return 0;
619 #elif MKDIR_TAKES_ONE_ARG
620   (void)modestr;
621   /* Note: In the case of W32 we better use CreateDirectory and try to
622      set appropriate permissions.  However using mkdir is easier
623      because this sets ERRNO.  */
624   return mkdir (name);
625 #else
626   return mkdir (name, modestr_to_mode (modestr));
627 #endif
628 }
629
630
631 /* A wrapper around chmod which takes a string for the mode argument.
632    This makes it easier to handle the mode argument which is not
633    defined on all systems.  The format of the modestring is the same
634    as for gnupg_mkdir.  */
635 int
636 gnupg_chmod (const char *name, const char *modestr)
637 {
638 #ifdef HAVE_W32_SYSTEM
639   (void)name;
640   (void)modestr;
641   return 0;
642 #else
643   return chmod (name, modestr_to_mode (modestr));
644 #endif
645 }
646
647
648 /* Our version of mkdtemp.  The API is identical to POSIX.1-2008
649    version.  We do not use a system provided mkdtemp because we have a
650    good RNG instantly available and this way we don't have diverging
651    versions.  */
652 char *
653 gnupg_mkdtemp (char *tmpl)
654 {
655   /* A lower bound on the number of temporary files to attempt to
656      generate.  The maximum total number of temporary file names that
657      can exist for a given template is 62**6 (5*36**3 for Windows).
658      It should never be necessary to try all these combinations.
659      Instead if a reasonable number of names is tried (we define
660      reasonable as 62**3 or 5*36**3) fail to give the system
661      administrator the chance to remove the problems.  */
662 #ifdef HAVE_W32_SYSTEM
663   static const char letters[] =
664     "abcdefghijklmnopqrstuvwxyz0123456789";
665 # define NUMBER_OF_LETTERS 36
666 # define ATTEMPTS_MIN (5 * 36 * 36 * 36)
667 #else
668   static const char letters[] =
669     "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
670 # define NUMBER_OF_LETTERS 62
671 # define ATTEMPTS_MIN (62 * 62 * 62)
672 #endif
673   int len;
674   char *XXXXXX;
675   uint64_t value;
676   unsigned int count;
677   int save_errno = errno;
678   /* The number of times to attempt to generate a temporary file.  To
679      conform to POSIX, this must be no smaller than TMP_MAX.  */
680 #if ATTEMPTS_MIN < TMP_MAX
681   unsigned int attempts = TMP_MAX;
682 #else
683   unsigned int attempts = ATTEMPTS_MIN;
684 #endif
685
686   len = strlen (tmpl);
687   if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX"))
688     {
689       gpg_err_set_errno (EINVAL);
690       return NULL;
691     }
692
693   /* This is where the Xs start.  */
694   XXXXXX = &tmpl[len - 6];
695
696   /* Get a random start value.  */
697   gcry_create_nonce (&value, sizeof value);
698
699   /* Loop until a directory was created.  */
700   for (count = 0; count < attempts; value += 7777, ++count)
701     {
702       uint64_t v = value;
703
704       /* Fill in the random bits.  */
705       XXXXXX[0] = letters[v % NUMBER_OF_LETTERS];
706       v /= NUMBER_OF_LETTERS;
707       XXXXXX[1] = letters[v % NUMBER_OF_LETTERS];
708       v /= NUMBER_OF_LETTERS;
709       XXXXXX[2] = letters[v % NUMBER_OF_LETTERS];
710       v /= NUMBER_OF_LETTERS;
711       XXXXXX[3] = letters[v % NUMBER_OF_LETTERS];
712       v /= NUMBER_OF_LETTERS;
713       XXXXXX[4] = letters[v % NUMBER_OF_LETTERS];
714       v /= NUMBER_OF_LETTERS;
715       XXXXXX[5] = letters[v % NUMBER_OF_LETTERS];
716
717       if (!gnupg_mkdir (tmpl, "-rwx"))
718         {
719           gpg_err_set_errno (save_errno);
720           return tmpl;
721         }
722       if (errno != EEXIST)
723         return NULL;
724     }
725
726   /* We got out of the loop because we ran out of combinations to try.  */
727   gpg_err_set_errno (EEXIST);
728   return NULL;
729 }
730
731
732 int
733 gnupg_setenv (const char *name, const char *value, int overwrite)
734 {
735 #ifdef HAVE_W32CE_SYSTEM
736   (void)name;
737   (void)value;
738   (void)overwrite;
739   return 0;
740 #elif defined(HAVE_W32_SYSTEM)
741   if (!overwrite)
742     {
743       char tmpbuf[10];
744       if (GetEnvironmentVariable (name, tmpbuf, sizeof tmpbuf))
745         return 0; /* Exists but overwrite was not requested.  */
746     }
747   if (!SetEnvironmentVariable (name, value))
748     {
749       gpg_err_set_errno (EINVAL); /* (Might also be ENOMEM.) */
750       return -1;
751     }
752   return 0;
753 #elif defined(HAVE_SETENV)
754   return setenv (name, value, overwrite);
755 #else
756   char *buf;
757
758   (void)overwrite;
759   if (!name || !value)
760     {
761       gpg_err_set_errno (EINVAL);
762       return -1;
763     }
764   buf = xtrymalloc (strlen (name) + 1 + strlen (value) + 1);
765   if (!buf)
766     return -1;
767   strcpy (stpcpy (stpcpy (buf, name), "="), value);
768 #if __GNUC__
769 # warning no setenv - using putenv but leaking memory.
770 #endif
771   return putenv (buf);
772 #endif
773 }
774
775
776 int
777 gnupg_unsetenv (const char *name)
778 {
779 #ifdef HAVE_W32CE_SYSTEM
780   (void)name;
781   return 0;
782 #elif defined(HAVE_W32_SYSTEM)
783   if (!SetEnvironmentVariable (name, NULL))
784     {
785       gpg_err_set_errno (EINVAL); /* (Might also be ENOMEM.) */
786       return -1;
787     }
788   return 0;
789 #elif defined(HAVE_UNSETENV)
790   return unsetenv (name);
791 #else
792   char *buf;
793
794   if (!name)
795     {
796       gpg_err_set_errno (EINVAL);
797       return -1;
798     }
799   buf = xtrystrdup (name);
800   if (!buf)
801     return -1;
802 #if __GNUC__
803 # warning no unsetenv - trying putenv but leaking memory.
804 #endif
805   return putenv (buf);
806 #endif
807 }
808
809
810 /* Return the current working directory as a malloced string.  Return
811    NULL and sets ERRNo on error.  */
812 char *
813 gnupg_getcwd (void)
814 {
815   char *buffer;
816   size_t size = 100;
817
818   for (;;)
819     {
820       buffer = xtrymalloc (size+1);
821       if (!buffer)
822         return NULL;
823 #ifdef HAVE_W32CE_SYSTEM
824       strcpy (buffer, "/");  /* Always "/".  */
825       return buffer;
826 #else
827       if (getcwd (buffer, size) == buffer)
828         return buffer;
829       xfree (buffer);
830       if (errno != ERANGE)
831         return NULL;
832       size *= 2;
833 #endif
834     }
835 }
836
837
838 \f
839 #ifdef HAVE_W32CE_SYSTEM
840 /* There is a isatty function declaration in cegcc but it does not
841    make sense, thus we redefine it.  */
842 int
843 _gnupg_isatty (int fd)
844 {
845   (void)fd;
846   return 0;
847 }
848 #endif
849
850
851 #ifdef HAVE_W32CE_SYSTEM
852 /* Replacement for getenv which takes care of the our use of getenv.
853    The code is not thread safe but we expect it to work in all cases
854    because it is called for the first time early enough.  */
855 char *
856 _gnupg_getenv (const char *name)
857 {
858   static int initialized;
859   static char *assuan_debug;
860
861   if (!initialized)
862     {
863       assuan_debug = read_w32_registry_string (NULL,
864                                                "\\Software\\GNU\\libassuan",
865                                                "debug");
866       initialized = 1;
867     }
868
869   if (!strcmp (name, "ASSUAN_DEBUG"))
870     return assuan_debug;
871   else
872     return NULL;
873 }
874
875 #endif /*HAVE_W32CE_SYSTEM*/
876
877
878 #ifdef HAVE_W32_SYSTEM
879 /* Return the user's security identifier from the current process.  */
880 PSID
881 w32_get_user_sid (void)
882 {
883   int okay = 0;
884   HANDLE proc = NULL;
885   HANDLE token = NULL;
886   TOKEN_USER *user = NULL;
887   PSID sid = NULL;
888   DWORD tokenlen, sidlen;
889
890   proc = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId());
891   if (!proc)
892     goto leave;
893
894   if (!OpenProcessToken (proc, TOKEN_QUERY, &token))
895     goto leave;
896
897   if (!GetTokenInformation (token, TokenUser, NULL, 0, &tokenlen)
898       && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
899     goto leave;
900
901   user = xtrymalloc (tokenlen);
902   if (!user)
903     goto leave;
904
905   if (!GetTokenInformation (token, TokenUser, user, tokenlen, &tokenlen))
906     goto leave;
907   if (!IsValidSid (user->User.Sid))
908     goto leave;
909   sidlen = GetLengthSid (user->User.Sid);
910   sid = xtrymalloc (sidlen);
911   if (!sid)
912     goto leave;
913   if (!CopySid (sidlen, sid, user->User.Sid))
914     goto leave;
915   okay = 1;
916
917  leave:
918   xfree (user);
919   if (token)
920     CloseHandle (token);
921   if (proc)
922     CloseHandle (proc);
923
924   if (!okay)
925     {
926       xfree (sid);
927       sid = NULL;
928     }
929   return sid;
930 }
931 #endif /*HAVE_W32_SYSTEM*/