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 1827 : trap_unaligned(void)
102 : { /* dummy */
103 1827 : }
104 : #endif
105 :
106 :
107 : int
108 1878 : 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 1878 : if (getrlimit (RLIMIT_CORE, &limit))
119 0 : limit.rlim_max = 0;
120 1878 : limit.rlim_cur = 0;
121 1878 : if( !setrlimit (RLIMIT_CORE, &limit) )
122 1878 : 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 34 : get_session_marker (size_t *rlen)
155 : {
156 : static byte marker[SIZEOF_UNSIGNED_LONG*2];
157 : static int initialized;
158 :
159 34 : if (!initialized)
160 : {
161 16 : gcry_create_nonce (marker, sizeof marker);
162 16 : initialized = 1;
163 : }
164 34 : *rlen = sizeof (marker);
165 34 : 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 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 48 : 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 48 : sleep (seconds);
285 : # endif
286 : #endif
287 48 : }
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 523 : 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 523 : 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 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 1906 : gnupg_reopen_std (const char *pgmname)
456 : {
457 : #if defined(HAVE_STAT) && !defined(HAVE_W32_SYSTEM)
458 : struct stat statbuf;
459 1906 : int did_stdin = 0;
460 1906 : int did_stdout = 0;
461 1906 : int did_stderr = 0;
462 : FILE *complain;
463 :
464 1906 : 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 1906 : 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 1906 : 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 1906 : if (!did_stderr)
491 1906 : complain = stderr;
492 0 : else if (!did_stdout)
493 0 : complain = stdout;
494 : else
495 0 : complain = NULL;
496 :
497 1906 : if (complain)
498 : {
499 1906 : if (did_stdin == 1)
500 0 : fprintf (complain, "%s: WARNING: standard input reopened\n", pgmname);
501 1906 : if (did_stdout == 1)
502 0 : fprintf (complain, "%s: WARNING: standard output reopened\n", pgmname);
503 1906 : if (did_stderr == 1)
504 0 : fprintf (complain, "%s: WARNING: standard error reopened\n", pgmname);
505 :
506 1906 : 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 1906 : 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 1906 : }
517 :
518 :
519 : /* Hack required for Windows. */
520 : void
521 1 : gnupg_allow_set_foregound_window (pid_t pid)
522 : {
523 1 : 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 1 : }
532 :
533 : int
534 89 : 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 89 : return remove (fname);
553 : #endif
554 : }
555 :
556 :
557 : #ifndef HAVE_W32_SYSTEM
558 : static mode_t
559 1395 : modestr_to_mode (const char *modestr)
560 : {
561 1395 : mode_t mode = 0;
562 :
563 1395 : if (modestr && *modestr)
564 : {
565 1394 : modestr++;
566 1394 : if (*modestr && *modestr++ == 'r')
567 1394 : mode |= S_IRUSR;
568 1394 : if (*modestr && *modestr++ == 'w')
569 1394 : mode |= S_IWUSR;
570 1394 : if (*modestr && *modestr++ == 'x')
571 1394 : mode |= S_IXUSR;
572 1394 : if (*modestr && *modestr++ == 'r')
573 0 : mode |= S_IRGRP;
574 1394 : if (*modestr && *modestr++ == 'w')
575 0 : mode |= S_IWGRP;
576 1394 : if (*modestr && *modestr++ == 'x')
577 0 : mode |= S_IXGRP;
578 1394 : if (*modestr && *modestr++ == 'r')
579 0 : mode |= S_IROTH;
580 1394 : if (*modestr && *modestr++ == 'w')
581 0 : mode |= S_IWOTH;
582 1394 : if (*modestr && *modestr++ == 'x')
583 0 : mode |= S_IXOTH;
584 : }
585 :
586 1395 : 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 1255 : 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 1255 : 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 140 : 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 140 : 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 1206 : 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 1206 : 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 1206 : unsigned int attempts = ATTEMPTS_MIN;
684 : #endif
685 :
686 1206 : len = strlen (tmpl);
687 1206 : if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX"))
688 : {
689 0 : gpg_err_set_errno (EINVAL);
690 0 : return NULL;
691 : }
692 :
693 : /* This is where the Xs start. */
694 1206 : XXXXXX = &tmpl[len - 6];
695 :
696 : /* Get a random start value. */
697 1206 : gcry_create_nonce (&value, sizeof value);
698 :
699 : /* Loop until a directory was created. */
700 1206 : for (count = 0; count < attempts; value += 7777, ++count)
701 : {
702 1206 : uint64_t v = value;
703 :
704 : /* Fill in the random bits. */
705 1206 : XXXXXX[0] = letters[v % NUMBER_OF_LETTERS];
706 1206 : v /= NUMBER_OF_LETTERS;
707 1206 : XXXXXX[1] = letters[v % NUMBER_OF_LETTERS];
708 1206 : v /= NUMBER_OF_LETTERS;
709 1206 : XXXXXX[2] = letters[v % NUMBER_OF_LETTERS];
710 1206 : v /= NUMBER_OF_LETTERS;
711 1206 : XXXXXX[3] = letters[v % NUMBER_OF_LETTERS];
712 1206 : v /= NUMBER_OF_LETTERS;
713 1206 : XXXXXX[4] = letters[v % NUMBER_OF_LETTERS];
714 1206 : v /= NUMBER_OF_LETTERS;
715 1206 : XXXXXX[5] = letters[v % NUMBER_OF_LETTERS];
716 :
717 1206 : if (!gnupg_mkdir (tmpl, "-rwx"))
718 : {
719 1206 : gpg_err_set_errno (save_errno);
720 1206 : return tmpl;
721 : }
722 0 : if (errno != EEXIST)
723 0 : return NULL;
724 : }
725 :
726 : /* We got out of the loop because we ran out of combinations to try. */
727 0 : gpg_err_set_errno (EEXIST);
728 0 : return NULL;
729 : }
730 :
731 :
732 : int
733 263 : 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 263 : 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 96 : 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 96 : 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 291 : gnupg_getcwd (void)
814 : {
815 : char *buffer;
816 291 : size_t size = 100;
817 :
818 : for (;;)
819 : {
820 291 : buffer = xtrymalloc (size+1);
821 291 : if (!buffer)
822 0 : return NULL;
823 : #ifdef HAVE_W32CE_SYSTEM
824 : strcpy (buffer, "/"); /* Always "/". */
825 : return buffer;
826 : #else
827 291 : if (getcwd (buffer, size) == buffer)
828 291 : return buffer;
829 0 : xfree (buffer);
830 0 : if (errno != ERANGE)
831 0 : return NULL;
832 0 : size *= 2;
833 : #endif
834 0 : }
835 : }
836 :
837 :
838 :
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*/
|