Line data Source code
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 1331 : trap_unaligned(void)
102 : { /* dummy */
103 1331 : }
104 : #endif
105 :
106 :
107 : int
108 1337 : 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 1337 : if (getrlimit (RLIMIT_CORE, &limit))
119 0 : limit.rlim_max = 0;
120 1337 : limit.rlim_cur = 0;
121 1337 : if( !setrlimit (RLIMIT_CORE, &limit) )
122 1337 : return 0;
123 0 : if( errno != EINVAL && errno != ENOSYS )
124 0 : log_fatal (_("can't disable core dumps: %s\n"), strerror(errno) );
125 : #endif
126 0 : return 1;
127 : #endif
128 : }
129 :
130 : int
131 0 : 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 0 : if (getrlimit (RLIMIT_CORE, &limit))
140 0 : return 1;
141 0 : limit.rlim_cur = limit.rlim_max;
142 0 : setrlimit (RLIMIT_CORE, &limit);
143 0 : 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 32 : get_session_marker (size_t *rlen)
155 : {
156 : static byte marker[SIZEOF_UNSIGNED_LONG*2];
157 : static int initialized;
158 :
159 32 : if (!initialized)
160 : {
161 14 : gcry_create_nonce (marker, sizeof marker);
162 14 : initialized = 1;
163 : }
164 32 : *rlen = sizeof (marker);
165 32 : return marker;
166 : }
167 :
168 : /* Return a random number in an unsigned int. */
169 : unsigned int
170 0 : get_uint_nonce (void)
171 : {
172 : unsigned int value;
173 :
174 0 : gcry_create_nonce (&value, sizeof value);
175 0 : 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 fucntion. 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 1 : gnupg_sleep (unsigned int seconds)
276 : {
277 : #ifdef USE_NPTH
278 0 : 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 1 : sleep (seconds);
285 : # endif
286 : #endif
287 1 : }
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 0 : 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 0 : 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 493 : 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 493 : 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 10 : 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 10 : 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 hapen 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 1334 : gnupg_reopen_std (const char *pgmname)
456 : {
457 : #if defined(HAVE_STAT) && !defined(HAVE_W32_SYSTEM)
458 : struct stat statbuf;
459 1334 : int did_stdin = 0;
460 1334 : int did_stdout = 0;
461 1334 : int did_stderr = 0;
462 : FILE *complain;
463 :
464 1334 : if (fstat (STDIN_FILENO, &statbuf) == -1 && errno ==EBADF)
465 : {
466 0 : if (open ("/dev/null",O_RDONLY) == STDIN_FILENO)
467 0 : did_stdin = 1;
468 : else
469 0 : did_stdin = 2;
470 : }
471 :
472 1334 : if (fstat (STDOUT_FILENO, &statbuf) == -1 && errno == EBADF)
473 : {
474 0 : if (open ("/dev/null",O_WRONLY) == STDOUT_FILENO)
475 0 : did_stdout = 1;
476 : else
477 0 : did_stdout = 2;
478 : }
479 :
480 1334 : if (fstat (STDERR_FILENO, &statbuf)==-1 && errno==EBADF)
481 : {
482 0 : if (open ("/dev/null", O_WRONLY) == STDERR_FILENO)
483 0 : did_stderr = 1;
484 : else
485 0 : 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 1334 : if (!did_stderr)
491 1334 : complain = stderr;
492 0 : else if (!did_stdout)
493 0 : complain = stdout;
494 : else
495 0 : complain = NULL;
496 :
497 1334 : if (complain)
498 : {
499 1334 : if (did_stdin == 1)
500 0 : fprintf (complain, "%s: WARNING: standard input reopened\n", pgmname);
501 1334 : if (did_stdout == 1)
502 0 : fprintf (complain, "%s: WARNING: standard output reopened\n", pgmname);
503 1334 : if (did_stderr == 1)
504 0 : fprintf (complain, "%s: WARNING: standard error reopened\n", pgmname);
505 :
506 1334 : if (did_stdin == 2 || did_stdout == 2 || did_stderr == 2)
507 0 : fprintf(complain,"%s: fatal: unable to reopen standard input,"
508 : " output, or error\n", pgmname);
509 : }
510 :
511 1334 : if (did_stdin == 2 || did_stdout == 2 || did_stderr == 2)
512 0 : exit (3);
513 : #else /* !(HAVE_STAT && !HAVE_W32_SYSTEM) */
514 : (void)pgmname;
515 : #endif
516 1334 : }
517 :
518 :
519 : /* Hack required for Windows. */
520 : void
521 0 : gnupg_allow_set_foregound_window (pid_t pid)
522 : {
523 0 : if (!pid)
524 0 : 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 0 : }
532 :
533 : int
534 2 : 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 2 : return remove (fname);
553 : #endif
554 : }
555 :
556 :
557 : /* A wrapper around mkdir which takes a string for the mode argument.
558 : This makes it easier to handle the mode argument which is not
559 : defined on all systems. The format of the modestring is
560 :
561 : "-rwxrwxrwx"
562 :
563 : '-' is a don't care or not set. 'r', 'w', 'x' are read allowed,
564 : write allowed, execution allowed with the first group for the user,
565 : the second for the group and the third for all others. If the
566 : string is shorter than above the missing mode characters are meant
567 : to be not set. */
568 : int
569 9 : gnupg_mkdir (const char *name, const char *modestr)
570 : {
571 : #ifdef HAVE_W32CE_SYSTEM
572 : wchar_t *wname;
573 : (void)modestr;
574 :
575 : wname = utf8_to_wchar (name);
576 : if (!wname)
577 : return -1;
578 : if (!CreateDirectoryW (wname, NULL))
579 : {
580 : xfree (wname);
581 : return -1; /* ERRNO is automagically provided by gpg-error.h. */
582 : }
583 : xfree (wname);
584 : return 0;
585 : #elif MKDIR_TAKES_ONE_ARG
586 : (void)modestr;
587 : /* Note: In the case of W32 we better use CreateDirectory and try to
588 : set appropriate permissions. However using mkdir is easier
589 : because this sets ERRNO. */
590 : return mkdir (name);
591 : #else
592 9 : mode_t mode = 0;
593 :
594 9 : if (modestr && *modestr)
595 : {
596 9 : modestr++;
597 9 : if (*modestr && *modestr++ == 'r')
598 9 : mode |= S_IRUSR;
599 9 : if (*modestr && *modestr++ == 'w')
600 9 : mode |= S_IWUSR;
601 9 : if (*modestr && *modestr++ == 'x')
602 9 : mode |= S_IXUSR;
603 9 : if (*modestr && *modestr++ == 'r')
604 0 : mode |= S_IRGRP;
605 9 : if (*modestr && *modestr++ == 'w')
606 0 : mode |= S_IWGRP;
607 9 : if (*modestr && *modestr++ == 'x')
608 0 : mode |= S_IXGRP;
609 9 : if (*modestr && *modestr++ == 'r')
610 0 : mode |= S_IROTH;
611 9 : if (*modestr && *modestr++ == 'w')
612 0 : mode |= S_IWOTH;
613 9 : if (*modestr && *modestr++ == 'x')
614 0 : mode |= S_IXOTH;
615 : }
616 9 : return mkdir (name, mode);
617 : #endif
618 : }
619 :
620 :
621 : /* Our version of mkdtemp. The API is identical to POSIX.1-2008
622 : version. We do not use a system provided mkdtemp because we have a
623 : good RNG instantly available and this way we don't have diverging
624 : versions. */
625 : char *
626 0 : gnupg_mkdtemp (char *tmpl)
627 : {
628 : /* A lower bound on the number of temporary files to attempt to
629 : generate. The maximum total number of temporary file names that
630 : can exist for a given template is 62**6 (5*36**3 for Windows).
631 : It should never be necessary to try all these combinations.
632 : Instead if a reasonable number of names is tried (we define
633 : reasonable as 62**3 or 5*36**3) fail to give the system
634 : administrator the chance to remove the problems. */
635 : #ifdef HAVE_W32_SYSTEM
636 : static const char letters[] =
637 : "abcdefghijklmnopqrstuvwxyz0123456789";
638 : # define NUMBER_OF_LETTERS 36
639 : # define ATTEMPTS_MIN (5 * 36 * 36 * 36)
640 : #else
641 : static const char letters[] =
642 : "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
643 : # define NUMBER_OF_LETTERS 62
644 : # define ATTEMPTS_MIN (62 * 62 * 62)
645 : #endif
646 : int len;
647 : char *XXXXXX;
648 : uint64_t value;
649 : unsigned int count;
650 0 : int save_errno = errno;
651 : /* The number of times to attempt to generate a temporary file. To
652 : conform to POSIX, this must be no smaller than TMP_MAX. */
653 : #if ATTEMPTS_MIN < TMP_MAX
654 : unsigned int attempts = TMP_MAX;
655 : #else
656 0 : unsigned int attempts = ATTEMPTS_MIN;
657 : #endif
658 :
659 0 : len = strlen (tmpl);
660 0 : if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX"))
661 : {
662 0 : gpg_err_set_errno (EINVAL);
663 0 : return NULL;
664 : }
665 :
666 : /* This is where the Xs start. */
667 0 : XXXXXX = &tmpl[len - 6];
668 :
669 : /* Get a random start value. */
670 0 : gcry_create_nonce (&value, sizeof value);
671 :
672 : /* Loop until a directory was created. */
673 0 : for (count = 0; count < attempts; value += 7777, ++count)
674 : {
675 0 : uint64_t v = value;
676 :
677 : /* Fill in the random bits. */
678 0 : XXXXXX[0] = letters[v % NUMBER_OF_LETTERS];
679 0 : v /= NUMBER_OF_LETTERS;
680 0 : XXXXXX[1] = letters[v % NUMBER_OF_LETTERS];
681 0 : v /= NUMBER_OF_LETTERS;
682 0 : XXXXXX[2] = letters[v % NUMBER_OF_LETTERS];
683 0 : v /= NUMBER_OF_LETTERS;
684 0 : XXXXXX[3] = letters[v % NUMBER_OF_LETTERS];
685 0 : v /= NUMBER_OF_LETTERS;
686 0 : XXXXXX[4] = letters[v % NUMBER_OF_LETTERS];
687 0 : v /= NUMBER_OF_LETTERS;
688 0 : XXXXXX[5] = letters[v % NUMBER_OF_LETTERS];
689 :
690 0 : if (!gnupg_mkdir (tmpl, "-rwx"))
691 : {
692 0 : gpg_err_set_errno (save_errno);
693 0 : return tmpl;
694 : }
695 0 : if (errno != EEXIST)
696 0 : return NULL;
697 : }
698 :
699 : /* We got out of the loop because we ran out of combinations to try. */
700 0 : gpg_err_set_errno (EEXIST);
701 0 : return NULL;
702 : }
703 :
704 :
705 : int
706 0 : gnupg_setenv (const char *name, const char *value, int overwrite)
707 : {
708 : #ifdef HAVE_W32CE_SYSTEM
709 : (void)name;
710 : (void)value;
711 : (void)overwrite;
712 : return 0;
713 : #elif defined(HAVE_W32_SYSTEM)
714 : if (!overwrite)
715 : {
716 : char tmpbuf[10];
717 : if (GetEnvironmentVariable (name, tmpbuf, sizeof tmpbuf))
718 : return 0; /* Exists but overwrite was not requested. */
719 : }
720 : if (!SetEnvironmentVariable (name, value))
721 : {
722 : gpg_err_set_errno (EINVAL); /* (Might also be ENOMEM.) */
723 : return -1;
724 : }
725 : return 0;
726 : #elif defined(HAVE_SETENV)
727 0 : return setenv (name, value, overwrite);
728 : #else
729 : char *buf;
730 :
731 : (void)overwrite;
732 : if (!name || !value)
733 : {
734 : gpg_err_set_errno (EINVAL);
735 : return -1;
736 : }
737 : buf = xtrymalloc (strlen (name) + 1 + strlen (value) + 1);
738 : if (!buf)
739 : return -1;
740 : strcpy (stpcpy (stpcpy (buf, name), "="), value);
741 : #if __GNUC__
742 : # warning no setenv - using putenv but leaking memory.
743 : #endif
744 : return putenv (buf);
745 : #endif
746 : }
747 :
748 :
749 : int
750 2 : gnupg_unsetenv (const char *name)
751 : {
752 : #ifdef HAVE_W32CE_SYSTEM
753 : (void)name;
754 : return 0;
755 : #elif defined(HAVE_W32_SYSTEM)
756 : if (!SetEnvironmentVariable (name, NULL))
757 : {
758 : gpg_err_set_errno (EINVAL); /* (Might also be ENOMEM.) */
759 : return -1;
760 : }
761 : return 0;
762 : #elif defined(HAVE_UNSETENV)
763 2 : return unsetenv (name);
764 : #else
765 : char *buf;
766 :
767 : if (!name)
768 : {
769 : gpg_err_set_errno (EINVAL);
770 : return -1;
771 : }
772 : buf = xtrystrdup (name);
773 : if (!buf)
774 : return -1;
775 : #if __GNUC__
776 : # warning no unsetenv - trying putenv but leaking memory.
777 : #endif
778 : return putenv (buf);
779 : #endif
780 : }
781 :
782 :
783 : /* Return the current working directory as a malloced string. Return
784 : NULL and sets ERRNo on error. */
785 : char *
786 3 : gnupg_getcwd (void)
787 : {
788 : char *buffer;
789 3 : size_t size = 100;
790 :
791 : for (;;)
792 : {
793 3 : buffer = xtrymalloc (size+1);
794 3 : if (!buffer)
795 0 : return NULL;
796 : #ifdef HAVE_W32CE_SYSTEM
797 : strcpy (buffer, "/"); /* Always "/". */
798 : return buffer;
799 : #else
800 3 : if (getcwd (buffer, size) == buffer)
801 3 : return buffer;
802 0 : xfree (buffer);
803 0 : if (errno != ERANGE)
804 0 : return NULL;
805 0 : size *= 2;
806 : #endif
807 0 : }
808 : }
809 :
810 :
811 :
812 : #ifdef HAVE_W32CE_SYSTEM
813 : /* There is a isatty function declaration in cegcc but it does not
814 : make sense, thus we redefine it. */
815 : int
816 : _gnupg_isatty (int fd)
817 : {
818 : (void)fd;
819 : return 0;
820 : }
821 : #endif
822 :
823 :
824 : #ifdef HAVE_W32CE_SYSTEM
825 : /* Replacement for getenv which takes care of the our use of getenv.
826 : The code is not thread safe but we expect it to work in all cases
827 : because it is called for the first time early enough. */
828 : char *
829 : _gnupg_getenv (const char *name)
830 : {
831 : static int initialized;
832 : static char *assuan_debug;
833 :
834 : if (!initialized)
835 : {
836 : assuan_debug = read_w32_registry_string (NULL,
837 : "\\Software\\GNU\\libassuan",
838 : "debug");
839 : initialized = 1;
840 : }
841 :
842 : if (!strcmp (name, "ASSUAN_DEBUG"))
843 : return assuan_debug;
844 : else
845 : return NULL;
846 : }
847 :
848 : #endif /*HAVE_W32CE_SYSTEM*/
849 :
850 :
851 : #ifdef HAVE_W32_SYSTEM
852 : /* Return the user's security identifier from the current process. */
853 : PSID
854 : w32_get_user_sid (void)
855 : {
856 : int okay = 0;
857 : HANDLE proc = NULL;
858 : HANDLE token = NULL;
859 : TOKEN_USER *user = NULL;
860 : PSID sid = NULL;
861 : DWORD tokenlen, sidlen;
862 :
863 : proc = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId());
864 : if (!proc)
865 : goto leave;
866 :
867 : if (!OpenProcessToken (proc, TOKEN_QUERY, &token))
868 : goto leave;
869 :
870 : if (!GetTokenInformation (token, TokenUser, NULL, 0, &tokenlen)
871 : && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
872 : goto leave;
873 :
874 : user = xtrymalloc (tokenlen);
875 : if (!user)
876 : goto leave;
877 :
878 : if (!GetTokenInformation (token, TokenUser, user, tokenlen, &tokenlen))
879 : goto leave;
880 : if (!IsValidSid (user->User.Sid))
881 : goto leave;
882 : sidlen = GetLengthSid (user->User.Sid);
883 : sid = xtrymalloc (sidlen);
884 : if (!sid)
885 : goto leave;
886 : if (!CopySid (sidlen, sid, user->User.Sid))
887 : goto leave;
888 : okay = 1;
889 :
890 : leave:
891 : xfree (user);
892 : if (token)
893 : CloseHandle (token);
894 : if (proc)
895 : CloseHandle (proc);
896 :
897 : if (!okay)
898 : {
899 : xfree (sid);
900 : sid = NULL;
901 : }
902 : return sid;
903 : }
904 : #endif /*HAVE_W32_SYSTEM*/
|