18625d0ffffc0e1777d98c64912ceda912b13414
[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 mkdir 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   return 0;
640 #else
641   return chmod (name, modestr_to_mode (modestr));
642 #endif
643 }
644
645
646 /* Our version of mkdtemp.  The API is identical to POSIX.1-2008
647    version.  We do not use a system provided mkdtemp because we have a
648    good RNG instantly available and this way we don't have diverging
649    versions.  */
650 char *
651 gnupg_mkdtemp (char *tmpl)
652 {
653   /* A lower bound on the number of temporary files to attempt to
654      generate.  The maximum total number of temporary file names that
655      can exist for a given template is 62**6 (5*36**3 for Windows).
656      It should never be necessary to try all these combinations.
657      Instead if a reasonable number of names is tried (we define
658      reasonable as 62**3 or 5*36**3) fail to give the system
659      administrator the chance to remove the problems.  */
660 #ifdef HAVE_W32_SYSTEM
661   static const char letters[] =
662     "abcdefghijklmnopqrstuvwxyz0123456789";
663 # define NUMBER_OF_LETTERS 36
664 # define ATTEMPTS_MIN (5 * 36 * 36 * 36)
665 #else
666   static const char letters[] =
667     "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
668 # define NUMBER_OF_LETTERS 62
669 # define ATTEMPTS_MIN (62 * 62 * 62)
670 #endif
671   int len;
672   char *XXXXXX;
673   uint64_t value;
674   unsigned int count;
675   int save_errno = errno;
676   /* The number of times to attempt to generate a temporary file.  To
677      conform to POSIX, this must be no smaller than TMP_MAX.  */
678 #if ATTEMPTS_MIN < TMP_MAX
679   unsigned int attempts = TMP_MAX;
680 #else
681   unsigned int attempts = ATTEMPTS_MIN;
682 #endif
683
684   len = strlen (tmpl);
685   if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX"))
686     {
687       gpg_err_set_errno (EINVAL);
688       return NULL;
689     }
690
691   /* This is where the Xs start.  */
692   XXXXXX = &tmpl[len - 6];
693
694   /* Get a random start value.  */
695   gcry_create_nonce (&value, sizeof value);
696
697   /* Loop until a directory was created.  */
698   for (count = 0; count < attempts; value += 7777, ++count)
699     {
700       uint64_t v = value;
701
702       /* Fill in the random bits.  */
703       XXXXXX[0] = letters[v % NUMBER_OF_LETTERS];
704       v /= NUMBER_OF_LETTERS;
705       XXXXXX[1] = letters[v % NUMBER_OF_LETTERS];
706       v /= NUMBER_OF_LETTERS;
707       XXXXXX[2] = letters[v % NUMBER_OF_LETTERS];
708       v /= NUMBER_OF_LETTERS;
709       XXXXXX[3] = letters[v % NUMBER_OF_LETTERS];
710       v /= NUMBER_OF_LETTERS;
711       XXXXXX[4] = letters[v % NUMBER_OF_LETTERS];
712       v /= NUMBER_OF_LETTERS;
713       XXXXXX[5] = letters[v % NUMBER_OF_LETTERS];
714
715       if (!gnupg_mkdir (tmpl, "-rwx"))
716         {
717           gpg_err_set_errno (save_errno);
718           return tmpl;
719         }
720       if (errno != EEXIST)
721         return NULL;
722     }
723
724   /* We got out of the loop because we ran out of combinations to try.  */
725   gpg_err_set_errno (EEXIST);
726   return NULL;
727 }
728
729
730 int
731 gnupg_setenv (const char *name, const char *value, int overwrite)
732 {
733 #ifdef HAVE_W32CE_SYSTEM
734   (void)name;
735   (void)value;
736   (void)overwrite;
737   return 0;
738 #elif defined(HAVE_W32_SYSTEM)
739   if (!overwrite)
740     {
741       char tmpbuf[10];
742       if (GetEnvironmentVariable (name, tmpbuf, sizeof tmpbuf))
743         return 0; /* Exists but overwrite was not requested.  */
744     }
745   if (!SetEnvironmentVariable (name, value))
746     {
747       gpg_err_set_errno (EINVAL); /* (Might also be ENOMEM.) */
748       return -1;
749     }
750   return 0;
751 #elif defined(HAVE_SETENV)
752   return setenv (name, value, overwrite);
753 #else
754   char *buf;
755
756   (void)overwrite;
757   if (!name || !value)
758     {
759       gpg_err_set_errno (EINVAL);
760       return -1;
761     }
762   buf = xtrymalloc (strlen (name) + 1 + strlen (value) + 1);
763   if (!buf)
764     return -1;
765   strcpy (stpcpy (stpcpy (buf, name), "="), value);
766 #if __GNUC__
767 # warning no setenv - using putenv but leaking memory.
768 #endif
769   return putenv (buf);
770 #endif
771 }
772
773
774 int
775 gnupg_unsetenv (const char *name)
776 {
777 #ifdef HAVE_W32CE_SYSTEM
778   (void)name;
779   return 0;
780 #elif defined(HAVE_W32_SYSTEM)
781   if (!SetEnvironmentVariable (name, NULL))
782     {
783       gpg_err_set_errno (EINVAL); /* (Might also be ENOMEM.) */
784       return -1;
785     }
786   return 0;
787 #elif defined(HAVE_UNSETENV)
788   return unsetenv (name);
789 #else
790   char *buf;
791
792   if (!name)
793     {
794       gpg_err_set_errno (EINVAL);
795       return -1;
796     }
797   buf = xtrystrdup (name);
798   if (!buf)
799     return -1;
800 #if __GNUC__
801 # warning no unsetenv - trying putenv but leaking memory.
802 #endif
803   return putenv (buf);
804 #endif
805 }
806
807
808 /* Return the current working directory as a malloced string.  Return
809    NULL and sets ERRNo on error.  */
810 char *
811 gnupg_getcwd (void)
812 {
813   char *buffer;
814   size_t size = 100;
815
816   for (;;)
817     {
818       buffer = xtrymalloc (size+1);
819       if (!buffer)
820         return NULL;
821 #ifdef HAVE_W32CE_SYSTEM
822       strcpy (buffer, "/");  /* Always "/".  */
823       return buffer;
824 #else
825       if (getcwd (buffer, size) == buffer)
826         return buffer;
827       xfree (buffer);
828       if (errno != ERANGE)
829         return NULL;
830       size *= 2;
831 #endif
832     }
833 }
834
835
836 \f
837 #ifdef HAVE_W32CE_SYSTEM
838 /* There is a isatty function declaration in cegcc but it does not
839    make sense, thus we redefine it.  */
840 int
841 _gnupg_isatty (int fd)
842 {
843   (void)fd;
844   return 0;
845 }
846 #endif
847
848
849 #ifdef HAVE_W32CE_SYSTEM
850 /* Replacement for getenv which takes care of the our use of getenv.
851    The code is not thread safe but we expect it to work in all cases
852    because it is called for the first time early enough.  */
853 char *
854 _gnupg_getenv (const char *name)
855 {
856   static int initialized;
857   static char *assuan_debug;
858
859   if (!initialized)
860     {
861       assuan_debug = read_w32_registry_string (NULL,
862                                                "\\Software\\GNU\\libassuan",
863                                                "debug");
864       initialized = 1;
865     }
866
867   if (!strcmp (name, "ASSUAN_DEBUG"))
868     return assuan_debug;
869   else
870     return NULL;
871 }
872
873 #endif /*HAVE_W32CE_SYSTEM*/
874
875
876 #ifdef HAVE_W32_SYSTEM
877 /* Return the user's security identifier from the current process.  */
878 PSID
879 w32_get_user_sid (void)
880 {
881   int okay = 0;
882   HANDLE proc = NULL;
883   HANDLE token = NULL;
884   TOKEN_USER *user = NULL;
885   PSID sid = NULL;
886   DWORD tokenlen, sidlen;
887
888   proc = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId());
889   if (!proc)
890     goto leave;
891
892   if (!OpenProcessToken (proc, TOKEN_QUERY, &token))
893     goto leave;
894
895   if (!GetTokenInformation (token, TokenUser, NULL, 0, &tokenlen)
896       && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
897     goto leave;
898
899   user = xtrymalloc (tokenlen);
900   if (!user)
901     goto leave;
902
903   if (!GetTokenInformation (token, TokenUser, user, tokenlen, &tokenlen))
904     goto leave;
905   if (!IsValidSid (user->User.Sid))
906     goto leave;
907   sidlen = GetLengthSid (user->User.Sid);
908   sid = xtrymalloc (sidlen);
909   if (!sid)
910     goto leave;
911   if (!CopySid (sidlen, sid, user->User.Sid))
912     goto leave;
913   okay = 1;
914
915  leave:
916   xfree (user);
917   if (token)
918     CloseHandle (token);
919   if (proc)
920     CloseHandle (proc);
921
922   if (!okay)
923     {
924       xfree (sid);
925       sid = NULL;
926     }
927   return sid;
928 }
929 #endif /*HAVE_W32_SYSTEM*/