1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-sysdeps.c Wrappers around system/libc features (internal to D-BUS implementation)
3 *
4 * Copyright (C) 2002, 2003 Red Hat, Inc.
5 * Copyright (C) 2003 CodeFactory AB
6 * Copyright (C) 2005 Novell, Inc.
7 * Copyright (C) 2006 Ralf Habacker <ralf.habacker@freenet.de>
8 * Copyright (C) 2006 Peter Kümmel <syntheticpp@gmx.net>
9 * Copyright (C) 2006 Christian Ehrlicher <ch.ehrlicher@gmx.de>
10 *
11 * Licensed under the Academic Free License version 2.1
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26 *
27 */
28
29 #include <config.h>
30
31 #define STRSAFE_NO_DEPRECATE
32
33 #ifndef DBUS_WINCE
34 #ifndef _WIN32_WINNT
35 #define _WIN32_WINNT 0x0501
36 #endif
37 #endif
38
39 #include "dbus-internals.h"
40 #include "dbus-sysdeps.h"
41 #include "dbus-threads.h"
42 #include "dbus-protocol.h"
43 #include "dbus-string.h"
44 #include "dbus-sysdeps-win.h"
45 #include "dbus-protocol.h"
46 #include "dbus-hash.h"
47 #include "dbus-sockets-win.h"
48 #include "dbus-list.h"
49 #include "dbus-nonce.h"
50 #include "dbus-credentials.h"
51
52 #include <windows.h>
53 #include <ws2tcpip.h>
54 #include <wincrypt.h>
55
56 /* Declarations missing in mingw's headers */
57 extern BOOL WINAPI ConvertStringSidToSidA (LPCSTR StringSid, PSID *Sid);
58 extern BOOL WINAPI ConvertSidToStringSidA (PSID Sid, LPSTR *StringSid);
59
60 #include <stdio.h>
61
62 #include <string.h>
63 #if HAVE_ERRNO_H
64 #include <errno.h>
65 #endif
66 #ifndef DBUS_WINCE
67 #include <mbstring.h>
68 #include <sys/stat.h>
69 #include <sys/types.h>
70 #endif
71
72 #ifdef HAVE_WS2TCPIP_H
73 /* getaddrinfo for Windows CE (and Windows). */
74 #include <ws2tcpip.h>
75 #endif
76
77 #ifdef HAVE_WSPIAPI_H
78 // needed for w2k compatibility (getaddrinfo/freeaddrinfo/getnameinfo)
79 #ifdef __GNUC__
80 #define _inline
81 #include "wspiapi.h"
82 #else
83 #include <wspiapi.h>
84 #endif
85 #endif // HAVE_WSPIAPI_H
86
87 #ifndef O_BINARY
88 #define O_BINARY 0
89 #endif
90
91 typedef int socklen_t;
92
93
94 void
_dbus_win_set_errno(int err)95 _dbus_win_set_errno (int err)
96 {
97 #ifdef DBUS_WINCE
98 SetLastError (err);
99 #else
100 errno = err;
101 #endif
102 }
103
104
105 /* Convert GetLastError() to a dbus error. */
106 const char*
_dbus_win_error_from_last_error(void)107 _dbus_win_error_from_last_error (void)
108 {
109 switch (GetLastError())
110 {
111 case 0:
112 return DBUS_ERROR_FAILED;
113
114 case ERROR_NO_MORE_FILES:
115 case ERROR_TOO_MANY_OPEN_FILES:
116 return DBUS_ERROR_LIMITS_EXCEEDED; /* kernel out of memory */
117
118 case ERROR_ACCESS_DENIED:
119 case ERROR_CANNOT_MAKE:
120 return DBUS_ERROR_ACCESS_DENIED;
121
122 case ERROR_NOT_ENOUGH_MEMORY:
123 return DBUS_ERROR_NO_MEMORY;
124
125 case ERROR_FILE_EXISTS:
126 return DBUS_ERROR_FILE_EXISTS;
127
128 case ERROR_FILE_NOT_FOUND:
129 case ERROR_PATH_NOT_FOUND:
130 return DBUS_ERROR_FILE_NOT_FOUND;
131 }
132
133 return DBUS_ERROR_FAILED;
134 }
135
136
137 char*
_dbus_win_error_string(int error_number)138 _dbus_win_error_string (int error_number)
139 {
140 char *msg;
141
142 FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER |
143 FORMAT_MESSAGE_IGNORE_INSERTS |
144 FORMAT_MESSAGE_FROM_SYSTEM,
145 NULL, error_number, 0,
146 (LPSTR) &msg, 0, NULL);
147
148 if (msg[strlen (msg) - 1] == '\n')
149 msg[strlen (msg) - 1] = '\0';
150 if (msg[strlen (msg) - 1] == '\r')
151 msg[strlen (msg) - 1] = '\0';
152
153 return msg;
154 }
155
156 void
_dbus_win_free_error_string(char * string)157 _dbus_win_free_error_string (char *string)
158 {
159 LocalFree (string);
160 }
161
162 /**
163 * Socket interface
164 *
165 */
166
167 /**
168 * Thin wrapper around the read() system call that appends
169 * the data it reads to the DBusString buffer. It appends
170 * up to the given count, and returns the same value
171 * and same errno as read(). The only exception is that
172 * _dbus_read_socket() handles EINTR for you.
173 * _dbus_read_socket() can return ENOMEM, even though
174 * regular UNIX read doesn't.
175 *
176 * @param fd the file descriptor to read from
177 * @param buffer the buffer to append data to
178 * @param count the amount of data to read
179 * @returns the number of bytes read or -1
180 */
181
182 int
_dbus_read_socket(int fd,DBusString * buffer,int count)183 _dbus_read_socket (int fd,
184 DBusString *buffer,
185 int count)
186 {
187 int bytes_read;
188 int start;
189 char *data;
190
191 _dbus_assert (count >= 0);
192
193 start = _dbus_string_get_length (buffer);
194
195 if (!_dbus_string_lengthen (buffer, count))
196 {
197 _dbus_win_set_errno (ENOMEM);
198 return -1;
199 }
200
201 data = _dbus_string_get_data_len (buffer, start, count);
202
203 again:
204
205 _dbus_verbose ("recv: count=%d fd=%d\n", count, fd);
206 bytes_read = recv (fd, data, count, 0);
207
208 if (bytes_read == SOCKET_ERROR)
209 {
210 DBUS_SOCKET_SET_ERRNO();
211 _dbus_verbose ("recv: failed: %s (%d)\n", _dbus_strerror (errno), errno);
212 bytes_read = -1;
213 }
214 else
215 _dbus_verbose ("recv: = %d\n", bytes_read);
216
217 if (bytes_read < 0)
218 {
219 if (errno == EINTR)
220 goto again;
221 else
222 {
223 /* put length back (note that this doesn't actually realloc anything) */
224 _dbus_string_set_length (buffer, start);
225 return -1;
226 }
227 }
228 else
229 {
230 /* put length back (doesn't actually realloc) */
231 _dbus_string_set_length (buffer, start + bytes_read);
232
233 #if 0
234 if (bytes_read > 0)
235 _dbus_verbose_bytes_of_string (buffer, start, bytes_read);
236 #endif
237
238 return bytes_read;
239 }
240 }
241
242 /**
243 * Thin wrapper around the write() system call that writes a part of a
244 * DBusString and handles EINTR for you.
245 *
246 * @param fd the file descriptor to write
247 * @param buffer the buffer to write data from
248 * @param start the first byte in the buffer to write
249 * @param len the number of bytes to try to write
250 * @returns the number of bytes written or -1 on error
251 */
252 int
_dbus_write_socket(int fd,const DBusString * buffer,int start,int len)253 _dbus_write_socket (int fd,
254 const DBusString *buffer,
255 int start,
256 int len)
257 {
258 const char *data;
259 int bytes_written;
260
261 data = _dbus_string_get_const_data_len (buffer, start, len);
262
263 again:
264
265 _dbus_verbose ("send: len=%d fd=%d\n", len, fd);
266 bytes_written = send (fd, data, len, 0);
267
268 if (bytes_written == SOCKET_ERROR)
269 {
270 DBUS_SOCKET_SET_ERRNO();
271 _dbus_verbose ("send: failed: %s\n", _dbus_strerror_from_errno ());
272 bytes_written = -1;
273 }
274 else
275 _dbus_verbose ("send: = %d\n", bytes_written);
276
277 if (bytes_written < 0 && errno == EINTR)
278 goto again;
279
280 #if 0
281 if (bytes_written > 0)
282 _dbus_verbose_bytes_of_string (buffer, start, bytes_written);
283 #endif
284
285 return bytes_written;
286 }
287
288
289 /**
290 * Closes a file descriptor.
291 *
292 * @param fd the file descriptor
293 * @param error error object
294 * @returns #FALSE if error set
295 */
296 dbus_bool_t
_dbus_close_socket(int fd,DBusError * error)297 _dbus_close_socket (int fd,
298 DBusError *error)
299 {
300 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
301
302 again:
303 if (closesocket (fd) == SOCKET_ERROR)
304 {
305 DBUS_SOCKET_SET_ERRNO ();
306
307 if (errno == EINTR)
308 goto again;
309
310 dbus_set_error (error, _dbus_error_from_errno (errno),
311 "Could not close socket: socket=%d, , %s",
312 fd, _dbus_strerror_from_errno ());
313 return FALSE;
314 }
315 _dbus_verbose ("_dbus_close_socket: socket=%d, \n", fd);
316
317 return TRUE;
318 }
319
320 /**
321 * Sets the file descriptor to be close
322 * on exec. Should be called for all file
323 * descriptors in D-Bus code.
324 *
325 * @param fd the file descriptor
326 */
327 void
_dbus_fd_set_close_on_exec(intptr_t handle)328 _dbus_fd_set_close_on_exec (intptr_t handle)
329 {
330 if ( !SetHandleInformation( (HANDLE) handle,
331 HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE,
332 0 /*disable both flags*/ ) )
333 {
334 _dbus_win_warn_win_error ("Disabling socket handle inheritance failed:", GetLastError());
335 }
336 }
337
338 /**
339 * Sets a file descriptor to be nonblocking.
340 *
341 * @param fd the file descriptor.
342 * @param error address of error location.
343 * @returns #TRUE on success.
344 */
345 dbus_bool_t
_dbus_set_fd_nonblocking(int handle,DBusError * error)346 _dbus_set_fd_nonblocking (int handle,
347 DBusError *error)
348 {
349 u_long one = 1;
350
351 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
352
353 if (ioctlsocket (handle, FIONBIO, &one) == SOCKET_ERROR)
354 {
355 DBUS_SOCKET_SET_ERRNO ();
356 dbus_set_error (error, _dbus_error_from_errno (errno),
357 "Failed to set socket %d:%d to nonblocking: %s", handle,
358 _dbus_strerror_from_errno ());
359 return FALSE;
360 }
361
362 return TRUE;
363 }
364
365
366 /**
367 * Like _dbus_write() but will use writev() if possible
368 * to write both buffers in sequence. The return value
369 * is the number of bytes written in the first buffer,
370 * plus the number written in the second. If the first
371 * buffer is written successfully and an error occurs
372 * writing the second, the number of bytes in the first
373 * is returned (i.e. the error is ignored), on systems that
374 * don't have writev. Handles EINTR for you.
375 * The second buffer may be #NULL.
376 *
377 * @param fd the file descriptor
378 * @param buffer1 first buffer
379 * @param start1 first byte to write in first buffer
380 * @param len1 number of bytes to write from first buffer
381 * @param buffer2 second buffer, or #NULL
382 * @param start2 first byte to write in second buffer
383 * @param len2 number of bytes to write in second buffer
384 * @returns total bytes written from both buffers, or -1 on error
385 */
386 int
_dbus_write_socket_two(int fd,const DBusString * buffer1,int start1,int len1,const DBusString * buffer2,int start2,int len2)387 _dbus_write_socket_two (int fd,
388 const DBusString *buffer1,
389 int start1,
390 int len1,
391 const DBusString *buffer2,
392 int start2,
393 int len2)
394 {
395 WSABUF vectors[2];
396 const char *data1;
397 const char *data2;
398 int rc;
399 DWORD bytes_written;
400
401 _dbus_assert (buffer1 != NULL);
402 _dbus_assert (start1 >= 0);
403 _dbus_assert (start2 >= 0);
404 _dbus_assert (len1 >= 0);
405 _dbus_assert (len2 >= 0);
406
407
408 data1 = _dbus_string_get_const_data_len (buffer1, start1, len1);
409
410 if (buffer2 != NULL)
411 data2 = _dbus_string_get_const_data_len (buffer2, start2, len2);
412 else
413 {
414 data2 = NULL;
415 start2 = 0;
416 len2 = 0;
417 }
418
419 vectors[0].buf = (char*) data1;
420 vectors[0].len = len1;
421 vectors[1].buf = (char*) data2;
422 vectors[1].len = len2;
423
424 again:
425
426 _dbus_verbose ("WSASend: len1+2=%d+%d fd=%d\n", len1, len2, fd);
427 rc = WSASend (fd,
428 vectors,
429 data2 ? 2 : 1,
430 &bytes_written,
431 0,
432 NULL,
433 NULL);
434
435 if (rc == SOCKET_ERROR)
436 {
437 DBUS_SOCKET_SET_ERRNO ();
438 _dbus_verbose ("WSASend: failed: %s\n", _dbus_strerror_from_errno ());
439 bytes_written = -1;
440 }
441 else
442 _dbus_verbose ("WSASend: = %ld\n", bytes_written);
443
444 if (bytes_written < 0 && errno == EINTR)
445 goto again;
446
447 return bytes_written;
448 }
449
450 dbus_bool_t
_dbus_socket_is_invalid(int fd)451 _dbus_socket_is_invalid (int fd)
452 {
453 return fd == INVALID_SOCKET ? TRUE : FALSE;
454 }
455
456 #if 0
457
458 /**
459 * Opens the client side of a Windows named pipe. The connection D-BUS
460 * file descriptor index is returned. It is set up as nonblocking.
461 *
462 * @param path the path to named pipe socket
463 * @param error return location for error code
464 * @returns connection D-BUS file descriptor or -1 on error
465 */
466 int
467 _dbus_connect_named_pipe (const char *path,
468 DBusError *error)
469 {
470 _dbus_assert_not_reached ("not implemented");
471 }
472
473 #endif
474
475
476
477 void
_dbus_win_startup_winsock(void)478 _dbus_win_startup_winsock (void)
479 {
480 /* Straight from MSDN, deuglified */
481
482 static dbus_bool_t beenhere = FALSE;
483
484 WORD wVersionRequested;
485 WSADATA wsaData;
486 int err;
487
488 if (beenhere)
489 return;
490
491 wVersionRequested = MAKEWORD (2, 0);
492
493 err = WSAStartup (wVersionRequested, &wsaData);
494 if (err != 0)
495 {
496 _dbus_assert_not_reached ("Could not initialize WinSock");
497 _dbus_abort ();
498 }
499
500 /* Confirm that the WinSock DLL supports 2.0. Note that if the DLL
501 * supports versions greater than 2.0 in addition to 2.0, it will
502 * still return 2.0 in wVersion since that is the version we
503 * requested.
504 */
505 if (LOBYTE (wsaData.wVersion) != 2 ||
506 HIBYTE (wsaData.wVersion) != 0)
507 {
508 _dbus_assert_not_reached ("No usable WinSock found");
509 _dbus_abort ();
510 }
511
512 beenhere = TRUE;
513 }
514
515
516
517
518
519
520
521
522
523 /************************************************************************
524
525 UTF / string code
526
527 ************************************************************************/
528
529 /**
530 * Measure the message length without terminating nul
531 */
_dbus_printf_string_upper_bound(const char * format,va_list args)532 int _dbus_printf_string_upper_bound (const char *format,
533 va_list args)
534 {
535 /* MSVCRT's vsnprintf semantics are a bit different */
536 char buf[1024];
537 int bufsize;
538 int len;
539
540 bufsize = sizeof (buf);
541 len = _vsnprintf (buf, bufsize - 1, format, args);
542
543 while (len == -1) /* try again */
544 {
545 char *p;
546
547 bufsize *= 2;
548
549 p = malloc (bufsize);
550 len = _vsnprintf (p, bufsize - 1, format, args);
551 free (p);
552 }
553
554 return len;
555 }
556
557
558 /**
559 * Returns the UTF-16 form of a UTF-8 string. The result should be
560 * freed with dbus_free() when no longer needed.
561 *
562 * @param str the UTF-8 string
563 * @param error return location for error code
564 */
565 wchar_t *
_dbus_win_utf8_to_utf16(const char * str,DBusError * error)566 _dbus_win_utf8_to_utf16 (const char *str,
567 DBusError *error)
568 {
569 DBusString s;
570 int n;
571 wchar_t *retval;
572
573 _dbus_string_init_const (&s, str);
574
575 if (!_dbus_string_validate_utf8 (&s, 0, _dbus_string_get_length (&s)))
576 {
577 dbus_set_error_const (error, DBUS_ERROR_FAILED, "Invalid UTF-8");
578 return NULL;
579 }
580
581 n = MultiByteToWideChar (CP_UTF8, 0, str, -1, NULL, 0);
582
583 if (n == 0)
584 {
585 _dbus_win_set_error_from_win_error (error, GetLastError ());
586 return NULL;
587 }
588
589 retval = dbus_new (wchar_t, n);
590
591 if (!retval)
592 {
593 _DBUS_SET_OOM (error);
594 return NULL;
595 }
596
597 if (MultiByteToWideChar (CP_UTF8, 0, str, -1, retval, n) != n)
598 {
599 dbus_free (retval);
600 dbus_set_error_const (error, DBUS_ERROR_FAILED, "MultiByteToWideChar inconsistency");
601 return NULL;
602 }
603
604 return retval;
605 }
606
607 /**
608 * Returns the UTF-8 form of a UTF-16 string. The result should be
609 * freed with dbus_free() when no longer needed.
610 *
611 * @param str the UTF-16 string
612 * @param error return location for error code
613 */
614 char *
_dbus_win_utf16_to_utf8(const wchar_t * str,DBusError * error)615 _dbus_win_utf16_to_utf8 (const wchar_t *str,
616 DBusError *error)
617 {
618 int n;
619 char *retval;
620
621 n = WideCharToMultiByte (CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL);
622
623 if (n == 0)
624 {
625 _dbus_win_set_error_from_win_error (error, GetLastError ());
626 return NULL;
627 }
628
629 retval = dbus_malloc (n);
630
631 if (!retval)
632 {
633 _DBUS_SET_OOM (error);
634 return NULL;
635 }
636
637 if (WideCharToMultiByte (CP_UTF8, 0, str, -1, retval, n, NULL, NULL) != n)
638 {
639 dbus_free (retval);
640 dbus_set_error_const (error, DBUS_ERROR_FAILED, "WideCharToMultiByte inconsistency");
641 return NULL;
642 }
643
644 return retval;
645 }
646
647
648
649
650
651
652 /************************************************************************
653
654
655 ************************************************************************/
656
657 dbus_bool_t
_dbus_win_account_to_sid(const wchar_t * waccount,void ** ppsid,DBusError * error)658 _dbus_win_account_to_sid (const wchar_t *waccount,
659 void **ppsid,
660 DBusError *error)
661 {
662 dbus_bool_t retval = FALSE;
663 DWORD sid_length, wdomain_length;
664 SID_NAME_USE use;
665 wchar_t *wdomain;
666
667 *ppsid = NULL;
668
669 sid_length = 0;
670 wdomain_length = 0;
671 if (!LookupAccountNameW (NULL, waccount, NULL, &sid_length,
672 NULL, &wdomain_length, &use) &&
673 GetLastError () != ERROR_INSUFFICIENT_BUFFER)
674 {
675 _dbus_win_set_error_from_win_error (error, GetLastError ());
676 return FALSE;
677 }
678
679 *ppsid = dbus_malloc (sid_length);
680 if (!*ppsid)
681 {
682 _DBUS_SET_OOM (error);
683 return FALSE;
684 }
685
686 wdomain = dbus_new (wchar_t, wdomain_length);
687 if (!wdomain)
688 {
689 _DBUS_SET_OOM (error);
690 goto out1;
691 }
692
693 if (!LookupAccountNameW (NULL, waccount, (PSID) *ppsid, &sid_length,
694 wdomain, &wdomain_length, &use))
695 {
696 _dbus_win_set_error_from_win_error (error, GetLastError ());
697 goto out2;
698 }
699
700 if (!IsValidSid ((PSID) *ppsid))
701 {
702 dbus_set_error_const (error, DBUS_ERROR_FAILED, "Invalid SID");
703 goto out2;
704 }
705
706 retval = TRUE;
707
708 out2:
709 dbus_free (wdomain);
710 out1:
711 if (!retval)
712 {
713 dbus_free (*ppsid);
714 *ppsid = NULL;
715 }
716
717 return retval;
718 }
719
720 /** @} end of sysdeps-win */
721
722
723 /**
724 * The only reason this is separate from _dbus_getpid() is to allow it
725 * on Windows for logging but not for other purposes.
726 *
727 * @returns process ID to put in log messages
728 */
729 unsigned long
_dbus_pid_for_log(void)730 _dbus_pid_for_log (void)
731 {
732 return _dbus_getpid ();
733 }
734
735
736 #ifndef DBUS_WINCE
737 /** Gets our SID
738 * @param points to sid buffer, need to be freed with LocalFree()
739 * @returns process sid
740 */
741 static dbus_bool_t
_dbus_getsid(char ** sid)742 _dbus_getsid(char **sid)
743 {
744 HANDLE process_token = INVALID_HANDLE_VALUE;
745 TOKEN_USER *token_user = NULL;
746 DWORD n;
747 PSID psid;
748 int retval = FALSE;
749
750 if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &process_token))
751 {
752 _dbus_win_warn_win_error ("OpenProcessToken failed", GetLastError ());
753 goto failed;
754 }
755 if ((!GetTokenInformation (process_token, TokenUser, NULL, 0, &n)
756 && GetLastError () != ERROR_INSUFFICIENT_BUFFER)
757 || (token_user = alloca (n)) == NULL
758 || !GetTokenInformation (process_token, TokenUser, token_user, n, &n))
759 {
760 _dbus_win_warn_win_error ("GetTokenInformation failed", GetLastError ());
761 goto failed;
762 }
763 psid = token_user->User.Sid;
764 if (!IsValidSid (psid))
765 {
766 _dbus_verbose("%s invalid sid\n",__FUNCTION__);
767 goto failed;
768 }
769 if (!ConvertSidToStringSidA (psid, sid))
770 {
771 _dbus_verbose("%s invalid sid\n",__FUNCTION__);
772 goto failed;
773 }
774 //okay:
775 retval = TRUE;
776
777 failed:
778 if (process_token != INVALID_HANDLE_VALUE)
779 CloseHandle (process_token);
780
781 _dbus_verbose("_dbus_getsid() returns %d\n",retval);
782 return retval;
783 }
784 #endif
785
786 /************************************************************************
787
788 pipes
789
790 ************************************************************************/
791
792 /**
793 * Creates a full-duplex pipe (as in socketpair()).
794 * Sets both ends of the pipe nonblocking.
795 *
796 * @todo libdbus only uses this for the debug-pipe server, so in
797 * principle it could be in dbus-sysdeps-util.c, except that
798 * dbus-sysdeps-util.c isn't in libdbus when tests are enabled and the
799 * debug-pipe server is used.
800 *
801 * @param fd1 return location for one end
802 * @param fd2 return location for the other end
803 * @param blocking #TRUE if pipe should be blocking
804 * @param error error return
805 * @returns #FALSE on failure (if error is set)
806 */
807 dbus_bool_t
_dbus_full_duplex_pipe(int * fd1,int * fd2,dbus_bool_t blocking,DBusError * error)808 _dbus_full_duplex_pipe (int *fd1,
809 int *fd2,
810 dbus_bool_t blocking,
811 DBusError *error)
812 {
813 SOCKET temp, socket1 = -1, socket2 = -1;
814 struct sockaddr_in saddr;
815 int len;
816 u_long arg;
817 fd_set read_set, write_set;
818 struct timeval tv;
819 int res;
820
821 _dbus_win_startup_winsock ();
822
823 temp = socket (AF_INET, SOCK_STREAM, 0);
824 if (temp == INVALID_SOCKET)
825 {
826 DBUS_SOCKET_SET_ERRNO ();
827 goto out0;
828 }
829
830 _DBUS_ZERO (saddr);
831 saddr.sin_family = AF_INET;
832 saddr.sin_port = 0;
833 saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
834
835 if (bind (temp, (struct sockaddr *)&saddr, sizeof (saddr)) == SOCKET_ERROR)
836 {
837 DBUS_SOCKET_SET_ERRNO ();
838 goto out0;
839 }
840
841 if (listen (temp, 1) == SOCKET_ERROR)
842 {
843 DBUS_SOCKET_SET_ERRNO ();
844 goto out0;
845 }
846
847 len = sizeof (saddr);
848 if (getsockname (temp, (struct sockaddr *)&saddr, &len) == SOCKET_ERROR)
849 {
850 DBUS_SOCKET_SET_ERRNO ();
851 goto out0;
852 }
853
854 socket1 = socket (AF_INET, SOCK_STREAM, 0);
855 if (socket1 == INVALID_SOCKET)
856 {
857 DBUS_SOCKET_SET_ERRNO ();
858 goto out0;
859 }
860
861 if (connect (socket1, (struct sockaddr *)&saddr, len) == SOCKET_ERROR)
862 {
863 DBUS_SOCKET_SET_ERRNO ();
864 goto out1;
865 }
866
867 socket2 = accept (temp, (struct sockaddr *) &saddr, &len);
868 if (socket2 == INVALID_SOCKET)
869 {
870 DBUS_SOCKET_SET_ERRNO ();
871 goto out1;
872 }
873
874 if (!blocking)
875 {
876 arg = 1;
877 if (ioctlsocket (socket1, FIONBIO, &arg) == SOCKET_ERROR)
878 {
879 DBUS_SOCKET_SET_ERRNO ();
880 goto out2;
881 }
882
883 arg = 1;
884 if (ioctlsocket (socket2, FIONBIO, &arg) == SOCKET_ERROR)
885 {
886 DBUS_SOCKET_SET_ERRNO ();
887 goto out2;
888 }
889 }
890
891 *fd1 = socket1;
892 *fd2 = socket2;
893
894 _dbus_verbose ("full-duplex pipe %d:%d <-> %d:%d\n",
895 *fd1, socket1, *fd2, socket2);
896
897 closesocket (temp);
898
899 return TRUE;
900
901 out2:
902 closesocket (socket2);
903 out1:
904 closesocket (socket1);
905 out0:
906 closesocket (temp);
907
908 dbus_set_error (error, _dbus_error_from_errno (errno),
909 "Could not setup socket pair: %s",
910 _dbus_strerror_from_errno ());
911
912 return FALSE;
913 }
914
915 /**
916 * Wrapper for poll().
917 *
918 * @param fds the file descriptors to poll
919 * @param n_fds number of descriptors in the array
920 * @param timeout_milliseconds timeout or -1 for infinite
921 * @returns numbers of fds with revents, or <0 on error
922 */
923 int
_dbus_poll(DBusPollFD * fds,int n_fds,int timeout_milliseconds)924 _dbus_poll (DBusPollFD *fds,
925 int n_fds,
926 int timeout_milliseconds)
927 {
928 #define USE_CHRIS_IMPL 0
929
930 #if USE_CHRIS_IMPL
931
932 #define DBUS_POLL_CHAR_BUFFER_SIZE 2000
933 char msg[DBUS_POLL_CHAR_BUFFER_SIZE];
934 char *msgp;
935
936 int ret = 0;
937 int i;
938 struct timeval tv;
939 int ready;
940
941 #define DBUS_STACK_WSAEVENTS 256
942 WSAEVENT eventsOnStack[DBUS_STACK_WSAEVENTS];
943 WSAEVENT *pEvents = NULL;
944 if (n_fds > DBUS_STACK_WSAEVENTS)
945 pEvents = calloc(sizeof(WSAEVENT), n_fds);
946 else
947 pEvents = eventsOnStack;
948
949
950 #ifdef DBUS_ENABLE_VERBOSE_MODE
951 msgp = msg;
952 msgp += sprintf (msgp, "WSAEventSelect: to=%d\n\t", timeout_milliseconds);
953 for (i = 0; i < n_fds; i++)
954 {
955 static dbus_bool_t warned = FALSE;
956 DBusPollFD *fdp = &fds[i];
957
958
959 if (fdp->events & _DBUS_POLLIN)
960 msgp += sprintf (msgp, "R:%d ", fdp->fd);
961
962 if (fdp->events & _DBUS_POLLOUT)
963 msgp += sprintf (msgp, "W:%d ", fdp->fd);
964
965 msgp += sprintf (msgp, "E:%d\n\t", fdp->fd);
966
967 // FIXME: more robust code for long msg
968 // create on heap when msg[] becomes too small
969 if (msgp >= msg + DBUS_POLL_CHAR_BUFFER_SIZE)
970 {
971 _dbus_assert_not_reached ("buffer overflow in _dbus_poll");
972 }
973 }
974
975 msgp += sprintf (msgp, "\n");
976 _dbus_verbose ("%s",msg);
977 #endif
978 for (i = 0; i < n_fds; i++)
979 {
980 DBusPollFD *fdp = &fds[i];
981 WSAEVENT ev;
982 long lNetworkEvents = FD_OOB;
983
984 ev = WSACreateEvent();
985
986 if (fdp->events & _DBUS_POLLIN)
987 lNetworkEvents |= FD_READ | FD_ACCEPT | FD_CLOSE;
988
989 if (fdp->events & _DBUS_POLLOUT)
990 lNetworkEvents |= FD_WRITE | FD_CONNECT;
991
992 WSAEventSelect(fdp->fd, ev, lNetworkEvents);
993
994 pEvents[i] = ev;
995 }
996
997
998 ready = WSAWaitForMultipleEvents (n_fds, pEvents, FALSE, timeout_milliseconds, FALSE);
999
1000 if (DBUS_SOCKET_API_RETURNS_ERROR (ready))
1001 {
1002 DBUS_SOCKET_SET_ERRNO ();
1003 if (errno != WSAEWOULDBLOCK)
1004 _dbus_verbose ("WSAWaitForMultipleEvents: failed: %s\n", _dbus_strerror_from_errno ());
1005 ret = -1;
1006 }
1007 else if (ready == WSA_WAIT_TIMEOUT)
1008 {
1009 _dbus_verbose ("WSAWaitForMultipleEvents: WSA_WAIT_TIMEOUT\n");
1010 ret = 0;
1011 }
1012 else if (ready >= WSA_WAIT_EVENT_0 && ready < (int)(WSA_WAIT_EVENT_0 + n_fds))
1013 {
1014 msgp = msg;
1015 msgp += sprintf (msgp, "WSAWaitForMultipleEvents: =%d\n\t", ready);
1016
1017 for (i = 0; i < n_fds; i++)
1018 {
1019 DBusPollFD *fdp = &fds[i];
1020 WSANETWORKEVENTS ne;
1021
1022 fdp->revents = 0;
1023
1024 WSAEnumNetworkEvents(fdp->fd, pEvents[i], &ne);
1025
1026 if (ne.lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))
1027 fdp->revents |= _DBUS_POLLIN;
1028
1029 if (ne.lNetworkEvents & (FD_WRITE | FD_CONNECT))
1030 fdp->revents |= _DBUS_POLLOUT;
1031
1032 if (ne.lNetworkEvents & (FD_OOB))
1033 fdp->revents |= _DBUS_POLLERR;
1034
1035 if (ne.lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))
1036 msgp += sprintf (msgp, "R:%d ", fdp->fd);
1037
1038 if (ne.lNetworkEvents & (FD_WRITE | FD_CONNECT))
1039 msgp += sprintf (msgp, "W:%d ", fdp->fd);
1040
1041 if (ne.lNetworkEvents & (FD_OOB))
1042 msgp += sprintf (msgp, "E:%d ", fdp->fd);
1043
1044 msgp += sprintf (msgp, "lNetworkEvents:%d ", ne.lNetworkEvents);
1045
1046 if(ne.lNetworkEvents)
1047 ret++;
1048
1049 WSAEventSelect(fdp->fd, pEvents[i], 0);
1050 }
1051
1052 msgp += sprintf (msgp, "\n");
1053 _dbus_verbose ("%s",msg);
1054 }
1055 else
1056 {
1057 _dbus_verbose ("WSAWaitForMultipleEvents: failed for unknown reason!");
1058 ret = -1;
1059 }
1060
1061 for(i = 0; i < n_fds; i++)
1062 {
1063 WSACloseEvent(pEvents[i]);
1064 }
1065
1066 if (n_fds > DBUS_STACK_WSAEVENTS)
1067 free(pEvents);
1068
1069 return ret;
1070
1071 #else /* USE_CHRIS_IMPL */
1072
1073 #define DBUS_POLL_CHAR_BUFFER_SIZE 2000
1074 char msg[DBUS_POLL_CHAR_BUFFER_SIZE];
1075 char *msgp;
1076
1077 fd_set read_set, write_set, err_set;
1078 int max_fd = 0;
1079 int i;
1080 struct timeval tv;
1081 int ready;
1082
1083 FD_ZERO (&read_set);
1084 FD_ZERO (&write_set);
1085 FD_ZERO (&err_set);
1086
1087
1088 #ifdef DBUS_ENABLE_VERBOSE_MODE
1089 msgp = msg;
1090 msgp += sprintf (msgp, "select: to=%d\n\t", timeout_milliseconds);
1091 for (i = 0; i < n_fds; i++)
1092 {
1093 static dbus_bool_t warned = FALSE;
1094 DBusPollFD *fdp = &fds[i];
1095
1096
1097 if (fdp->events & _DBUS_POLLIN)
1098 msgp += sprintf (msgp, "R:%d ", fdp->fd);
1099
1100 if (fdp->events & _DBUS_POLLOUT)
1101 msgp += sprintf (msgp, "W:%d ", fdp->fd);
1102
1103 msgp += sprintf (msgp, "E:%d\n\t", fdp->fd);
1104
1105 // FIXME: more robust code for long msg
1106 // create on heap when msg[] becomes too small
1107 if (msgp >= msg + DBUS_POLL_CHAR_BUFFER_SIZE)
1108 {
1109 _dbus_assert_not_reached ("buffer overflow in _dbus_poll");
1110 }
1111 }
1112
1113 msgp += sprintf (msgp, "\n");
1114 _dbus_verbose ("%s",msg);
1115 #endif
1116 for (i = 0; i < n_fds; i++)
1117 {
1118 DBusPollFD *fdp = &fds[i];
1119
1120 if (fdp->events & _DBUS_POLLIN)
1121 FD_SET (fdp->fd, &read_set);
1122
1123 if (fdp->events & _DBUS_POLLOUT)
1124 FD_SET (fdp->fd, &write_set);
1125
1126 FD_SET (fdp->fd, &err_set);
1127
1128 max_fd = MAX (max_fd, fdp->fd);
1129 }
1130
1131
1132 tv.tv_sec = timeout_milliseconds / 1000;
1133 tv.tv_usec = (timeout_milliseconds % 1000) * 1000;
1134
1135 ready = select (max_fd + 1, &read_set, &write_set, &err_set,
1136 timeout_milliseconds < 0 ? NULL : &tv);
1137
1138 if (DBUS_SOCKET_API_RETURNS_ERROR (ready))
1139 {
1140 DBUS_SOCKET_SET_ERRNO ();
1141 if (errno != WSAEWOULDBLOCK)
1142 _dbus_verbose ("select: failed: %s\n", _dbus_strerror_from_errno ());
1143 }
1144 else if (ready == 0)
1145 _dbus_verbose ("select: = 0\n");
1146 else
1147 if (ready > 0)
1148 {
1149 #ifdef DBUS_ENABLE_VERBOSE_MODE
1150 msgp = msg;
1151 msgp += sprintf (msgp, "select: = %d:\n\t", ready);
1152
1153 for (i = 0; i < n_fds; i++)
1154 {
1155 DBusPollFD *fdp = &fds[i];
1156
1157 if (FD_ISSET (fdp->fd, &read_set))
1158 msgp += sprintf (msgp, "R:%d ", fdp->fd);
1159
1160 if (FD_ISSET (fdp->fd, &write_set))
1161 msgp += sprintf (msgp, "W:%d ", fdp->fd);
1162
1163 if (FD_ISSET (fdp->fd, &err_set))
1164 msgp += sprintf (msgp, "E:%d\n\t", fdp->fd);
1165 }
1166 msgp += sprintf (msgp, "\n");
1167 _dbus_verbose ("%s",msg);
1168 #endif
1169
1170 for (i = 0; i < n_fds; i++)
1171 {
1172 DBusPollFD *fdp = &fds[i];
1173
1174 fdp->revents = 0;
1175
1176 if (FD_ISSET (fdp->fd, &read_set))
1177 fdp->revents |= _DBUS_POLLIN;
1178
1179 if (FD_ISSET (fdp->fd, &write_set))
1180 fdp->revents |= _DBUS_POLLOUT;
1181
1182 if (FD_ISSET (fdp->fd, &err_set))
1183 fdp->revents |= _DBUS_POLLERR;
1184 }
1185 }
1186 return ready;
1187 #endif /* USE_CHRIS_IMPL */
1188 }
1189
1190
1191
1192
1193 /******************************************************************************
1194
1195 Original CVS version of dbus-sysdeps.c
1196
1197 ******************************************************************************/
1198 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
1199 /* dbus-sysdeps.c Wrappers around system/libc features (internal to D-Bus implementation)
1200 *
1201 * Copyright (C) 2002, 2003 Red Hat, Inc.
1202 * Copyright (C) 2003 CodeFactory AB
1203 * Copyright (C) 2005 Novell, Inc.
1204 *
1205 * Licensed under the Academic Free License version 2.1
1206 *
1207 * This program is free software; you can redistribute it and/or modify
1208 * it under the terms of the GNU General Public License as published by
1209 * the Free Software Foundation; either version 2 of the License, or
1210 * (at your option) any later version.
1211 *
1212 * This program is distributed in the hope that it will be useful,
1213 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1214 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1215 * GNU General Public License for more details.
1216 *
1217 * You should have received a copy of the GNU General Public License
1218 * along with this program; if not, write to the Free Software
1219 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1220 *
1221 */
1222
1223
1224 /**
1225 * Exit the process, returning the given value.
1226 *
1227 * @param code the exit code
1228 */
1229 void
_dbus_exit(int code)1230 _dbus_exit (int code)
1231 {
1232 _exit (code);
1233 }
1234
1235 /**
1236 * Creates a socket and connects to a socket at the given host
1237 * and port. The connection fd is returned, and is set up as
1238 * nonblocking.
1239 *
1240 * @param host the host name to connect to
1241 * @param port the port to connect to
1242 * @param family the address family to listen on, NULL for all
1243 * @param error return location for error code
1244 * @returns connection file descriptor or -1 on error
1245 */
1246 int
_dbus_connect_tcp_socket(const char * host,const char * port,const char * family,DBusError * error)1247 _dbus_connect_tcp_socket (const char *host,
1248 const char *port,
1249 const char *family,
1250 DBusError *error)
1251 {
1252 return _dbus_connect_tcp_socket_with_nonce (host, port, family, (const char*)NULL, error);
1253 }
1254
1255 int
_dbus_connect_tcp_socket_with_nonce(const char * host,const char * port,const char * family,const char * noncefile,DBusError * error)1256 _dbus_connect_tcp_socket_with_nonce (const char *host,
1257 const char *port,
1258 const char *family,
1259 const char *noncefile,
1260 DBusError *error)
1261 {
1262 int fd = -1, res;
1263 struct addrinfo hints;
1264 struct addrinfo *ai, *tmp;
1265
1266 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1267
1268 _dbus_win_startup_winsock ();
1269
1270 _DBUS_ZERO (hints);
1271
1272 if (!family)
1273 hints.ai_family = AF_UNSPEC;
1274 else if (!strcmp(family, "ipv4"))
1275 hints.ai_family = AF_INET;
1276 else if (!strcmp(family, "ipv6"))
1277 hints.ai_family = AF_INET6;
1278 else
1279 {
1280 dbus_set_error (error,
1281 DBUS_ERROR_INVALID_ARGS,
1282 "Unknown address family %s", family);
1283 return -1;
1284 }
1285 hints.ai_protocol = IPPROTO_TCP;
1286 hints.ai_socktype = SOCK_STREAM;
1287 #ifdef AI_ADDRCONFIG
1288 hints.ai_flags = AI_ADDRCONFIG;
1289 #else
1290 hints.ai_flags = 0;
1291 #endif
1292
1293 if ((res = getaddrinfo(host, port, &hints, &ai)) != 0 || !ai)
1294 {
1295 dbus_set_error (error,
1296 _dbus_error_from_errno (res),
1297 "Failed to lookup host/port: \"%s:%s\": %s (%d)",
1298 host, port, _dbus_strerror(res), res);
1299 return -1;
1300 }
1301
1302 tmp = ai;
1303 while (tmp)
1304 {
1305 if ((fd = socket (tmp->ai_family, SOCK_STREAM, 0)) == INVALID_SOCKET)
1306 {
1307 DBUS_SOCKET_SET_ERRNO ();
1308 dbus_set_error (error,
1309 _dbus_error_from_errno (errno),
1310 "Failed to open socket: %s",
1311 _dbus_strerror_from_errno ());
1312 freeaddrinfo(ai);
1313 return -1;
1314 }
1315 _DBUS_ASSERT_ERROR_IS_CLEAR(error);
1316
1317 if (connect (fd, (struct sockaddr*) tmp->ai_addr, tmp->ai_addrlen) == SOCKET_ERROR)
1318 {
1319 DBUS_SOCKET_SET_ERRNO ();
1320 closesocket(fd);
1321 fd = -1;
1322 tmp = tmp->ai_next;
1323 continue;
1324 }
1325
1326 break;
1327 }
1328 freeaddrinfo(ai);
1329
1330 if (fd == -1)
1331 {
1332 dbus_set_error (error,
1333 _dbus_error_from_errno (errno),
1334 "Failed to connect to socket \"%s:%s\" %s",
1335 host, port, _dbus_strerror_from_errno ());
1336 return -1;
1337 }
1338
1339 if (noncefile != NULL)
1340 {
1341 DBusString noncefileStr;
1342 dbus_bool_t ret;
1343 if (!_dbus_string_init (&noncefileStr) ||
1344 !_dbus_string_append(&noncefileStr, noncefile))
1345 {
1346 closesocket (fd);
1347 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
1348 return -1;
1349 }
1350
1351 ret = _dbus_send_nonce (fd, &noncefileStr, error);
1352
1353 _dbus_string_free (&noncefileStr);
1354
1355 if (!ret)
1356 {
1357 closesocket (fd);
1358 return -1;
1359 }
1360 }
1361
1362 if (!_dbus_set_fd_nonblocking (fd, error))
1363 {
1364 closesocket (fd);
1365 return -1;
1366 }
1367
1368 return fd;
1369 }
1370
1371 /**
1372 * Creates a socket and binds it to the given path, then listens on
1373 * the socket. The socket is set to be nonblocking. In case of port=0
1374 * a random free port is used and returned in the port parameter.
1375 * If inaddr_any is specified, the hostname is ignored.
1376 *
1377 * @param host the host name to listen on
1378 * @param port the port to listen on, if zero a free port will be used
1379 * @param family the address family to listen on, NULL for all
1380 * @param retport string to return the actual port listened on
1381 * @param fds_p location to store returned file descriptors
1382 * @param error return location for errors
1383 * @returns the number of listening file descriptors or -1 on error
1384 */
1385
1386 int
_dbus_listen_tcp_socket(const char * host,const char * port,const char * family,DBusString * retport,int ** fds_p,DBusError * error)1387 _dbus_listen_tcp_socket (const char *host,
1388 const char *port,
1389 const char *family,
1390 DBusString *retport,
1391 int **fds_p,
1392 DBusError *error)
1393 {
1394 int nlisten_fd = 0, *listen_fd = NULL, res, i, port_num = -1;
1395 struct addrinfo hints;
1396 struct addrinfo *ai, *tmp;
1397
1398 // On Vista, sockaddr_gen must be a sockaddr_in6, and not a sockaddr_in6_old
1399 //That's required for family == IPv6(which is the default on Vista if family is not given)
1400 //So we use our own union instead of sockaddr_gen:
1401
1402 typedef union {
1403 struct sockaddr Address;
1404 struct sockaddr_in AddressIn;
1405 struct sockaddr_in6 AddressIn6;
1406 } mysockaddr_gen;
1407
1408 *fds_p = NULL;
1409 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1410
1411 _dbus_win_startup_winsock ();
1412
1413 _DBUS_ZERO (hints);
1414
1415 if (!family)
1416 hints.ai_family = AF_UNSPEC;
1417 else if (!strcmp(family, "ipv4"))
1418 hints.ai_family = AF_INET;
1419 else if (!strcmp(family, "ipv6"))
1420 hints.ai_family = AF_INET6;
1421 else
1422 {
1423 dbus_set_error (error,
1424 DBUS_ERROR_INVALID_ARGS,
1425 "Unknown address family %s", family);
1426 return -1;
1427 }
1428
1429 hints.ai_protocol = IPPROTO_TCP;
1430 hints.ai_socktype = SOCK_STREAM;
1431 #ifdef AI_ADDRCONFIG
1432 hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
1433 #else
1434 hints.ai_flags = AI_PASSIVE;
1435 #endif
1436
1437 redo_lookup_with_port:
1438 if ((res = getaddrinfo(host, port, &hints, &ai)) != 0 || !ai)
1439 {
1440 dbus_set_error (error,
1441 _dbus_error_from_errno (res),
1442 "Failed to lookup host/port: \"%s:%s\": %s (%d)",
1443 host ? host : "*", port, _dbus_strerror(res), res);
1444 return -1;
1445 }
1446
1447 tmp = ai;
1448 while (tmp)
1449 {
1450 int fd = -1, *newlisten_fd;
1451 if ((fd = socket (tmp->ai_family, SOCK_STREAM, 0)) == INVALID_SOCKET)
1452 {
1453 DBUS_SOCKET_SET_ERRNO ();
1454 dbus_set_error (error,
1455 _dbus_error_from_errno (errno),
1456 "Failed to open socket: %s",
1457 _dbus_strerror_from_errno ());
1458 goto failed;
1459 }
1460 _DBUS_ASSERT_ERROR_IS_CLEAR(error);
1461
1462 if (bind (fd, (struct sockaddr*) tmp->ai_addr, tmp->ai_addrlen) == SOCKET_ERROR)
1463 {
1464 DBUS_SOCKET_SET_ERRNO ();
1465 dbus_set_error (error, _dbus_error_from_errno (errno),
1466 "Failed to bind socket \"%s:%s\": %s",
1467 host ? host : "*", port, _dbus_strerror_from_errno ());
1468 closesocket (fd);
1469 goto failed;
1470 }
1471
1472 if (listen (fd, 30 /* backlog */) == SOCKET_ERROR)
1473 {
1474 DBUS_SOCKET_SET_ERRNO ();
1475 dbus_set_error (error, _dbus_error_from_errno (errno),
1476 "Failed to listen on socket \"%s:%s\": %s",
1477 host ? host : "*", port, _dbus_strerror_from_errno ());
1478 closesocket (fd);
1479 goto failed;
1480 }
1481
1482 newlisten_fd = dbus_realloc(listen_fd, sizeof(int)*(nlisten_fd+1));
1483 if (!newlisten_fd)
1484 {
1485 closesocket (fd);
1486 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
1487 "Failed to allocate file handle array");
1488 goto failed;
1489 }
1490 listen_fd = newlisten_fd;
1491 listen_fd[nlisten_fd] = fd;
1492 nlisten_fd++;
1493
1494 if (!_dbus_string_get_length(retport))
1495 {
1496 /* If the user didn't specify a port, or used 0, then
1497 the kernel chooses a port. After the first address
1498 is bound to, we need to force all remaining addresses
1499 to use the same port */
1500 if (!port || !strcmp(port, "0"))
1501 {
1502 mysockaddr_gen addr;
1503 socklen_t addrlen = sizeof(addr);
1504 char portbuf[10];
1505
1506 if (getsockname(fd, &addr.Address, &addrlen) == SOCKET_ERROR)
1507 {
1508 DBUS_SOCKET_SET_ERRNO ();
1509 dbus_set_error (error, _dbus_error_from_errno (errno),
1510 "Failed to resolve port \"%s:%s\": %s",
1511 host ? host : "*", port, _dbus_strerror_from_errno());
1512 goto failed;
1513 }
1514 snprintf( portbuf, sizeof( portbuf ) - 1, "%d", addr.AddressIn.sin_port );
1515 if (!_dbus_string_append(retport, portbuf))
1516 {
1517 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
1518 goto failed;
1519 }
1520
1521 /* Release current address list & redo lookup */
1522 port = _dbus_string_get_const_data(retport);
1523 freeaddrinfo(ai);
1524 goto redo_lookup_with_port;
1525 }
1526 else
1527 {
1528 if (!_dbus_string_append(retport, port))
1529 {
1530 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
1531 goto failed;
1532 }
1533 }
1534 }
1535
1536 tmp = tmp->ai_next;
1537 }
1538 freeaddrinfo(ai);
1539 ai = NULL;
1540
1541 if (!nlisten_fd)
1542 {
1543 _dbus_win_set_errno (WSAEADDRINUSE);
1544 dbus_set_error (error, _dbus_error_from_errno (errno),
1545 "Failed to bind socket \"%s:%s\": %s",
1546 host ? host : "*", port, _dbus_strerror_from_errno ());
1547 return -1;
1548 }
1549
1550 sscanf(_dbus_string_get_const_data(retport), "%d", &port_num);
1551
1552 for (i = 0 ; i < nlisten_fd ; i++)
1553 {
1554 if (!_dbus_set_fd_nonblocking (listen_fd[i], error))
1555 {
1556 goto failed;
1557 }
1558 }
1559
1560 *fds_p = listen_fd;
1561
1562 return nlisten_fd;
1563
1564 failed:
1565 if (ai)
1566 freeaddrinfo(ai);
1567 for (i = 0 ; i < nlisten_fd ; i++)
1568 closesocket (listen_fd[i]);
1569 dbus_free(listen_fd);
1570 return -1;
1571 }
1572
1573
1574 /**
1575 * Accepts a connection on a listening socket.
1576 * Handles EINTR for you.
1577 *
1578 * @param listen_fd the listen file descriptor
1579 * @returns the connection fd of the client, or -1 on error
1580 */
1581 int
_dbus_accept(int listen_fd)1582 _dbus_accept (int listen_fd)
1583 {
1584 int client_fd;
1585
1586 retry:
1587 client_fd = accept (listen_fd, NULL, NULL);
1588
1589 if (DBUS_SOCKET_IS_INVALID (client_fd))
1590 {
1591 DBUS_SOCKET_SET_ERRNO ();
1592 if (errno == EINTR)
1593 goto retry;
1594 }
1595
1596 _dbus_verbose ("client fd %d accepted\n", client_fd);
1597
1598 return client_fd;
1599 }
1600
1601
1602
1603
1604 dbus_bool_t
_dbus_send_credentials_socket(int handle,DBusError * error)1605 _dbus_send_credentials_socket (int handle,
1606 DBusError *error)
1607 {
1608 /* FIXME: for the session bus credentials shouldn't matter (?), but
1609 * for the system bus they are presumably essential. A rough outline
1610 * of a way to implement the credential transfer would be this:
1611 *
1612 * client waits to *read* a byte.
1613 *
1614 * server creates a named pipe with a random name, sends a byte
1615 * contining its length, and its name.
1616 *
1617 * client reads the name, connects to it (using Win32 API).
1618 *
1619 * server waits for connection to the named pipe, then calls
1620 * ImpersonateNamedPipeClient(), notes its now-current credentials,
1621 * calls RevertToSelf(), closes its handles to the named pipe, and
1622 * is done. (Maybe there is some other way to get the SID of a named
1623 * pipe client without having to use impersonation?)
1624 *
1625 * client closes its handles and is done.
1626 *
1627 * Ralf: Why not sending credentials over the given this connection ?
1628 * Using named pipes makes it impossible to be connected from a unix client.
1629 *
1630 */
1631 int bytes_written;
1632 DBusString buf;
1633
1634 _dbus_string_init_const_len (&buf, "\0", 1);
1635 again:
1636 bytes_written = _dbus_write_socket (handle, &buf, 0, 1 );
1637
1638 if (bytes_written < 0 && errno == EINTR)
1639 goto again;
1640
1641 if (bytes_written < 0)
1642 {
1643 dbus_set_error (error, _dbus_error_from_errno (errno),
1644 "Failed to write credentials byte: %s",
1645 _dbus_strerror_from_errno ());
1646 return FALSE;
1647 }
1648 else if (bytes_written == 0)
1649 {
1650 dbus_set_error (error, DBUS_ERROR_IO_ERROR,
1651 "wrote zero bytes writing credentials byte");
1652 return FALSE;
1653 }
1654 else
1655 {
1656 _dbus_assert (bytes_written == 1);
1657 _dbus_verbose ("wrote 1 zero byte, credential sending isn't implemented yet\n");
1658 return TRUE;
1659 }
1660 return TRUE;
1661 }
1662
1663 /**
1664 * Reads a single byte which must be nul (an error occurs otherwise),
1665 * and reads unix credentials if available. Fills in pid/uid/gid with
1666 * -1 if no credentials are available. Return value indicates whether
1667 * a byte was read, not whether we got valid credentials. On some
1668 * systems, such as Linux, reading/writing the byte isn't actually
1669 * required, but we do it anyway just to avoid multiple codepaths.
1670 *
1671 * Fails if no byte is available, so you must select() first.
1672 *
1673 * The point of the byte is that on some systems we have to
1674 * use sendmsg()/recvmsg() to transmit credentials.
1675 *
1676 * @param client_fd the client file descriptor
1677 * @param credentials struct to fill with credentials of client
1678 * @param error location to store error code
1679 * @returns #TRUE on success
1680 */
1681 dbus_bool_t
_dbus_read_credentials_socket(int handle,DBusCredentials * credentials,DBusError * error)1682 _dbus_read_credentials_socket (int handle,
1683 DBusCredentials *credentials,
1684 DBusError *error)
1685 {
1686 int bytes_read = 0;
1687 DBusString buf;
1688
1689 // could fail due too OOM
1690 if (_dbus_string_init(&buf))
1691 {
1692 bytes_read = _dbus_read_socket(handle, &buf, 1 );
1693
1694 if (bytes_read > 0)
1695 _dbus_verbose("got one zero byte from server");
1696
1697 _dbus_string_free(&buf);
1698 }
1699
1700 _dbus_credentials_add_from_current_process (credentials);
1701 _dbus_verbose("FIXME: get faked credentials from current process");
1702
1703 return TRUE;
1704 }
1705
1706 /**
1707 * Checks to make sure the given directory is
1708 * private to the user
1709 *
1710 * @param dir the name of the directory
1711 * @param error error return
1712 * @returns #FALSE on failure
1713 **/
1714 dbus_bool_t
_dbus_check_dir_is_private_to_user(DBusString * dir,DBusError * error)1715 _dbus_check_dir_is_private_to_user (DBusString *dir, DBusError *error)
1716 {
1717 /* TODO */
1718 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1719 return TRUE;
1720 }
1721
1722
1723 /**
1724 * Appends the given filename to the given directory.
1725 *
1726 * @todo it might be cute to collapse multiple '/' such as "foo//"
1727 * concat "//bar"
1728 *
1729 * @param dir the directory name
1730 * @param next_component the filename
1731 * @returns #TRUE on success
1732 */
1733 dbus_bool_t
_dbus_concat_dir_and_file(DBusString * dir,const DBusString * next_component)1734 _dbus_concat_dir_and_file (DBusString *dir,
1735 const DBusString *next_component)
1736 {
1737 dbus_bool_t dir_ends_in_slash;
1738 dbus_bool_t file_starts_with_slash;
1739
1740 if (_dbus_string_get_length (dir) == 0 ||
1741 _dbus_string_get_length (next_component) == 0)
1742 return TRUE;
1743
1744 dir_ends_in_slash =
1745 ('/' == _dbus_string_get_byte (dir, _dbus_string_get_length (dir) - 1) ||
1746 '\\' == _dbus_string_get_byte (dir, _dbus_string_get_length (dir) - 1));
1747
1748 file_starts_with_slash =
1749 ('/' == _dbus_string_get_byte (next_component, 0) ||
1750 '\\' == _dbus_string_get_byte (next_component, 0));
1751
1752 if (dir_ends_in_slash && file_starts_with_slash)
1753 {
1754 _dbus_string_shorten (dir, 1);
1755 }
1756 else if (!(dir_ends_in_slash || file_starts_with_slash))
1757 {
1758 if (!_dbus_string_append_byte (dir, '\\'))
1759 return FALSE;
1760 }
1761
1762 return _dbus_string_copy (next_component, 0, dir,
1763 _dbus_string_get_length (dir));
1764 }
1765
1766 /*---------------- DBusCredentials ----------------------------------*/
1767
1768 /**
1769 * Adds the credentials corresponding to the given username.
1770 *
1771 * @param credentials credentials to fill in
1772 * @param username the username
1773 * @returns #TRUE if the username existed and we got some credentials
1774 */
1775 dbus_bool_t
_dbus_credentials_add_from_user(DBusCredentials * credentials,const DBusString * username)1776 _dbus_credentials_add_from_user (DBusCredentials *credentials,
1777 const DBusString *username)
1778 {
1779 return _dbus_credentials_add_windows_sid (credentials,
1780 _dbus_string_get_const_data(username));
1781 }
1782
1783 /**
1784 * Adds the credentials of the current process to the
1785 * passed-in credentials object.
1786 *
1787 * @param credentials credentials to add to
1788 * @returns #FALSE if no memory; does not properly roll back on failure, so only some credentials may have been added
1789 */
1790
1791 dbus_bool_t
_dbus_credentials_add_from_current_process(DBusCredentials * credentials)1792 _dbus_credentials_add_from_current_process (DBusCredentials *credentials)
1793 {
1794 dbus_bool_t retval = FALSE;
1795 char *sid = NULL;
1796
1797 if (!_dbus_getsid(&sid))
1798 goto failed;
1799
1800 if (!_dbus_credentials_add_unix_pid(credentials, _dbus_getpid()))
1801 goto failed;
1802
1803 if (!_dbus_credentials_add_windows_sid (credentials,sid))
1804 goto failed;
1805
1806 retval = TRUE;
1807 goto end;
1808 failed:
1809 retval = FALSE;
1810 end:
1811 if (sid)
1812 LocalFree(sid);
1813
1814 return retval;
1815 }
1816
1817 /**
1818 * Append to the string the identity we would like to have when we
1819 * authenticate, on UNIX this is the current process UID and on
1820 * Windows something else, probably a Windows SID string. No escaping
1821 * is required, that is done in dbus-auth.c. The username here
1822 * need not be anything human-readable, it can be the machine-readable
1823 * form i.e. a user id.
1824 *
1825 * @param str the string to append to
1826 * @returns #FALSE on no memory
1827 * @todo to which class belongs this
1828 */
1829 dbus_bool_t
_dbus_append_user_from_current_process(DBusString * str)1830 _dbus_append_user_from_current_process (DBusString *str)
1831 {
1832 dbus_bool_t retval = FALSE;
1833 char *sid = NULL;
1834
1835 if (!_dbus_getsid(&sid))
1836 return FALSE;
1837
1838 retval = _dbus_string_append (str,sid);
1839
1840 LocalFree(sid);
1841 return retval;
1842 }
1843
1844 /**
1845 * Gets our process ID
1846 * @returns process ID
1847 */
1848 dbus_pid_t
_dbus_getpid(void)1849 _dbus_getpid (void)
1850 {
1851 return GetCurrentProcessId ();
1852 }
1853
1854 /** nanoseconds in a second */
1855 #define NANOSECONDS_PER_SECOND 1000000000
1856 /** microseconds in a second */
1857 #define MICROSECONDS_PER_SECOND 1000000
1858 /** milliseconds in a second */
1859 #define MILLISECONDS_PER_SECOND 1000
1860 /** nanoseconds in a millisecond */
1861 #define NANOSECONDS_PER_MILLISECOND 1000000
1862 /** microseconds in a millisecond */
1863 #define MICROSECONDS_PER_MILLISECOND 1000
1864
1865 /**
1866 * Sleeps the given number of milliseconds.
1867 * @param milliseconds number of milliseconds
1868 */
1869 void
_dbus_sleep_milliseconds(int milliseconds)1870 _dbus_sleep_milliseconds (int milliseconds)
1871 {
1872 Sleep (milliseconds);
1873 }
1874
1875
1876 /**
1877 * Get current time, as in gettimeofday().
1878 *
1879 * @param tv_sec return location for number of seconds
1880 * @param tv_usec return location for number of microseconds
1881 */
1882 void
_dbus_get_current_time(long * tv_sec,long * tv_usec)1883 _dbus_get_current_time (long *tv_sec,
1884 long *tv_usec)
1885 {
1886 FILETIME ft;
1887 dbus_uint64_t time64;
1888
1889 GetSystemTimeAsFileTime (&ft);
1890
1891 memcpy (&time64, &ft, sizeof (time64));
1892
1893 /* Convert from 100s of nanoseconds since 1601-01-01
1894 * to Unix epoch. Yes, this is Y2038 unsafe.
1895 */
1896 time64 -= DBUS_INT64_CONSTANT (116444736000000000);
1897 time64 /= 10;
1898
1899 if (tv_sec)
1900 *tv_sec = time64 / 1000000;
1901
1902 if (tv_usec)
1903 *tv_usec = time64 % 1000000;
1904 }
1905
1906
1907 /**
1908 * signal (SIGPIPE, SIG_IGN);
1909 */
1910 void
_dbus_disable_sigpipe(void)1911 _dbus_disable_sigpipe (void)
1912 {
1913 }
1914
1915 /**
1916 * Creates a directory; succeeds if the directory
1917 * is created or already existed.
1918 *
1919 * @param filename directory filename
1920 * @param error initialized error object
1921 * @returns #TRUE on success
1922 */
1923 dbus_bool_t
_dbus_create_directory(const DBusString * filename,DBusError * error)1924 _dbus_create_directory (const DBusString *filename,
1925 DBusError *error)
1926 {
1927 const char *filename_c;
1928
1929 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1930
1931 filename_c = _dbus_string_get_const_data (filename);
1932
1933 if (!CreateDirectoryA (filename_c, NULL))
1934 {
1935 if (GetLastError () == ERROR_ALREADY_EXISTS)
1936 return TRUE;
1937
1938 dbus_set_error (error, DBUS_ERROR_FAILED,
1939 "Failed to create directory %s: %s\n",
1940 filename_c, _dbus_strerror_from_errno ());
1941 return FALSE;
1942 }
1943 else
1944 return TRUE;
1945 }
1946
1947
1948 /**
1949 * Generates the given number of random bytes,
1950 * using the best mechanism we can come up with.
1951 *
1952 * @param str the string
1953 * @param n_bytes the number of random bytes to append to string
1954 * @returns #TRUE on success, #FALSE if no memory
1955 */
1956 dbus_bool_t
_dbus_generate_random_bytes(DBusString * str,int n_bytes)1957 _dbus_generate_random_bytes (DBusString *str,
1958 int n_bytes)
1959 {
1960 int old_len;
1961 char *p;
1962 HCRYPTPROV hprov;
1963
1964 old_len = _dbus_string_get_length (str);
1965
1966 if (!_dbus_string_lengthen (str, n_bytes))
1967 return FALSE;
1968
1969 p = _dbus_string_get_data_len (str, old_len, n_bytes);
1970
1971 if (!CryptAcquireContext (&hprov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
1972 return FALSE;
1973
1974 if (!CryptGenRandom (hprov, n_bytes, p))
1975 {
1976 CryptReleaseContext (hprov, 0);
1977 return FALSE;
1978 }
1979
1980 CryptReleaseContext (hprov, 0);
1981
1982 return TRUE;
1983 }
1984
1985 /**
1986 * Gets the temporary files directory by inspecting the environment variables
1987 * TMPDIR, TMP, and TEMP in that order. If none of those are set "/tmp" is returned
1988 *
1989 * @returns location of temp directory
1990 */
1991 const char*
_dbus_get_tmpdir(void)1992 _dbus_get_tmpdir(void)
1993 {
1994 static const char* tmpdir = NULL;
1995 static char buf[1000];
1996
1997 if (tmpdir == NULL)
1998 {
1999 char *last_slash;
2000
2001 if (!GetTempPathA (sizeof (buf), buf))
2002 {
2003 _dbus_warn ("GetTempPath failed\n");
2004 _dbus_abort ();
2005 }
2006
2007 /* Drop terminating backslash or slash */
2008 last_slash = _mbsrchr (buf, '\\');
2009 if (last_slash > buf && last_slash[1] == '\0')
2010 last_slash[0] = '\0';
2011 last_slash = _mbsrchr (buf, '/');
2012 if (last_slash > buf && last_slash[1] == '\0')
2013 last_slash[0] = '\0';
2014
2015 tmpdir = buf;
2016 }
2017
2018 _dbus_assert(tmpdir != NULL);
2019
2020 return tmpdir;
2021 }
2022
2023
2024 /**
2025 * Deletes the given file.
2026 *
2027 * @param filename the filename
2028 * @param error error location
2029 *
2030 * @returns #TRUE if unlink() succeeded
2031 */
2032 dbus_bool_t
_dbus_delete_file(const DBusString * filename,DBusError * error)2033 _dbus_delete_file (const DBusString *filename,
2034 DBusError *error)
2035 {
2036 const char *filename_c;
2037
2038 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
2039
2040 filename_c = _dbus_string_get_const_data (filename);
2041
2042 if (DeleteFileA (filename_c) == 0)
2043 {
2044 dbus_set_error (error, DBUS_ERROR_FAILED,
2045 "Failed to delete file %s: %s\n",
2046 filename_c, _dbus_strerror_from_errno ());
2047 return FALSE;
2048 }
2049 else
2050 return TRUE;
2051 }
2052
2053 /* Forward declaration of prototype used in next function */
2054 static dbus_bool_t
2055 _dbus_get_install_root(char *prefix, int len);
2056
2057 /*
2058 * replaces the term DBUS_PREFIX in configure_time_path by the
2059 * current dbus installation directory. On unix this function is a noop
2060 *
2061 * @param configure_time_path
2062 * @return real path
2063 */
2064 const char *
_dbus_replace_install_prefix(const char * configure_time_path)2065 _dbus_replace_install_prefix (const char *configure_time_path)
2066 {
2067 #ifndef DBUS_PREFIX
2068 return configure_time_path;
2069 #else
2070 static char retval[1000];
2071 static char runtime_prefix[1000];
2072 int len = 1000;
2073 int i;
2074
2075 if (!configure_time_path)
2076 return NULL;
2077
2078 if ((!_dbus_get_install_root(runtime_prefix, len) ||
2079 strncmp (configure_time_path, DBUS_PREFIX "/",
2080 strlen (DBUS_PREFIX) + 1))) {
2081 strcat (retval, configure_time_path);
2082 return retval;
2083 }
2084
2085 strcpy (retval, runtime_prefix);
2086 strcat (retval, configure_time_path + strlen (DBUS_PREFIX) + 1);
2087
2088 /* Somehow, in some situations, backslashes get collapsed in the string.
2089 * Since windows C library accepts both forward and backslashes as
2090 * path separators, convert all backslashes to forward slashes.
2091 */
2092
2093 for(i = 0; retval[i] != '\0'; i++) {
2094 if(retval[i] == '\\')
2095 retval[i] = '/';
2096 }
2097 return retval;
2098 #endif
2099 }
2100
2101 #if !defined (DBUS_DISABLE_ASSERTS) || defined(DBUS_BUILD_TESTS)
2102
2103 #if defined(_MSC_VER) || defined(DBUS_WINCE)
2104 # ifdef BACKTRACES
2105 # undef BACKTRACES
2106 # endif
2107 #else
2108 # define BACKTRACES
2109 #endif
2110
2111 #ifdef BACKTRACES
2112 /*
2113 * Backtrace Generator
2114 *
2115 * Copyright 2004 Eric Poech
2116 * Copyright 2004 Robert Shearman
2117 *
2118 * This library is free software; you can redistribute it and/or
2119 * modify it under the terms of the GNU Lesser General Public
2120 * License as published by the Free Software Foundation; either
2121 * version 2.1 of the License, or (at your option) any later version.
2122 *
2123 * This library is distributed in the hope that it will be useful,
2124 * but WITHOUT ANY WARRANTY; without even the implied warranty of
2125 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2126 * Lesser General Public License for more details.
2127 *
2128 * You should have received a copy of the GNU Lesser General Public
2129 * License along with this library; if not, write to the Free Software
2130 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2131 */
2132
2133 #include <winver.h>
2134 #include <imagehlp.h>
2135 #include <stdio.h>
2136
2137 #define DPRINTF _dbus_warn
2138
2139 #ifdef _MSC_VER
2140 #define BOOL int
2141
2142 #define __i386__
2143 #endif
2144
2145 //#define MAKE_FUNCPTR(f) static typeof(f) * p##f
2146
2147 //MAKE_FUNCPTR(StackWalk);
2148 //MAKE_FUNCPTR(SymGetModuleBase);
2149 //MAKE_FUNCPTR(SymFunctionTableAccess);
2150 //MAKE_FUNCPTR(SymInitialize);
2151 //MAKE_FUNCPTR(SymGetSymFromAddr);
2152 //MAKE_FUNCPTR(SymGetModuleInfo);
2153 static BOOL (WINAPI *pStackWalk)(
2154 DWORD MachineType,
2155 HANDLE hProcess,
2156 HANDLE hThread,
2157 LPSTACKFRAME StackFrame,
2158 PVOID ContextRecord,
2159 PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine,
2160 PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine,
2161 PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine,
2162 PTRANSLATE_ADDRESS_ROUTINE TranslateAddress
2163 );
2164 #ifdef _WIN64
2165 static DWORD64 (WINAPI *pSymGetModuleBase)(
2166 HANDLE hProcess,
2167 DWORD64 dwAddr
2168 );
2169 static PVOID (WINAPI *pSymFunctionTableAccess)(
2170 HANDLE hProcess,
2171 DWORD64 AddrBase
2172 );
2173 #else
2174 static DWORD (WINAPI *pSymGetModuleBase)(
2175 HANDLE hProcess,
2176 DWORD dwAddr
2177 );
2178 static PVOID (WINAPI *pSymFunctionTableAccess)(
2179 HANDLE hProcess,
2180 DWORD AddrBase
2181 );
2182 #endif
2183 static BOOL (WINAPI *pSymInitialize)(
2184 HANDLE hProcess,
2185 PSTR UserSearchPath,
2186 BOOL fInvadeProcess
2187 );
2188 static BOOL (WINAPI *pSymGetSymFromAddr)(
2189 HANDLE hProcess,
2190 DWORD Address,
2191 PDWORD Displacement,
2192 PIMAGEHLP_SYMBOL Symbol
2193 );
2194 static BOOL (WINAPI *pSymGetModuleInfo)(
2195 HANDLE hProcess,
2196 DWORD dwAddr,
2197 PIMAGEHLP_MODULE ModuleInfo
2198 );
2199 static DWORD (WINAPI *pSymSetOptions)(
2200 DWORD SymOptions
2201 );
2202
2203
init_backtrace()2204 static BOOL init_backtrace()
2205 {
2206 HMODULE hmodDbgHelp = LoadLibraryA("dbghelp");
2207 /*
2208 #define GETFUNC(x) \
2209 p##x = (typeof(x)*)GetProcAddress(hmodDbgHelp, #x); \
2210 if (!p##x) \
2211 { \
2212 return FALSE; \
2213 }
2214 */
2215
2216
2217 // GETFUNC(StackWalk);
2218 // GETFUNC(SymGetModuleBase);
2219 // GETFUNC(SymFunctionTableAccess);
2220 // GETFUNC(SymInitialize);
2221 // GETFUNC(SymGetSymFromAddr);
2222 // GETFUNC(SymGetModuleInfo);
2223
2224 #define FUNC(x) #x
2225
2226 pStackWalk = (BOOL (WINAPI *)(
2227 DWORD MachineType,
2228 HANDLE hProcess,
2229 HANDLE hThread,
2230 LPSTACKFRAME StackFrame,
2231 PVOID ContextRecord,
2232 PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine,
2233 PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine,
2234 PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine,
2235 PTRANSLATE_ADDRESS_ROUTINE TranslateAddress
2236 ))GetProcAddress (hmodDbgHelp, FUNC(StackWalk));
2237 #ifdef _WIN64
2238 pSymGetModuleBase=(DWORD64 (WINAPI *)(
2239 HANDLE hProcess,
2240 DWORD64 dwAddr
2241 ))GetProcAddress (hmodDbgHelp, FUNC(SymGetModuleBase));
2242 pSymFunctionTableAccess=(PVOID (WINAPI *)(
2243 HANDLE hProcess,
2244 DWORD64 AddrBase
2245 ))GetProcAddress (hmodDbgHelp, FUNC(SymFunctionTableAccess));
2246 #else
2247 pSymGetModuleBase=(DWORD (WINAPI *)(
2248 HANDLE hProcess,
2249 DWORD dwAddr
2250 ))GetProcAddress (hmodDbgHelp, FUNC(SymGetModuleBase));
2251 pSymFunctionTableAccess=(PVOID (WINAPI *)(
2252 HANDLE hProcess,
2253 DWORD AddrBase
2254 ))GetProcAddress (hmodDbgHelp, FUNC(SymFunctionTableAccess));
2255 #endif
2256 pSymInitialize = (BOOL (WINAPI *)(
2257 HANDLE hProcess,
2258 PSTR UserSearchPath,
2259 BOOL fInvadeProcess
2260 ))GetProcAddress (hmodDbgHelp, FUNC(SymInitialize));
2261 pSymGetSymFromAddr = (BOOL (WINAPI *)(
2262 HANDLE hProcess,
2263 DWORD Address,
2264 PDWORD Displacement,
2265 PIMAGEHLP_SYMBOL Symbol
2266 ))GetProcAddress (hmodDbgHelp, FUNC(SymGetSymFromAddr));
2267 pSymGetModuleInfo = (BOOL (WINAPI *)(
2268 HANDLE hProcess,
2269 DWORD dwAddr,
2270 PIMAGEHLP_MODULE ModuleInfo
2271 ))GetProcAddress (hmodDbgHelp, FUNC(SymGetModuleInfo));
2272 pSymSetOptions = (DWORD (WINAPI *)(
2273 DWORD SymOptions
2274 ))GetProcAddress (hmodDbgHelp, FUNC(SymSetOptions));
2275
2276
2277 pSymSetOptions(SYMOPT_UNDNAME);
2278
2279 pSymInitialize(GetCurrentProcess(), NULL, TRUE);
2280
2281 return TRUE;
2282 }
2283
dump_backtrace_for_thread(HANDLE hThread)2284 static void dump_backtrace_for_thread(HANDLE hThread)
2285 {
2286 STACKFRAME sf;
2287 CONTEXT context;
2288 DWORD dwImageType;
2289
2290 if (!pStackWalk)
2291 if (!init_backtrace())
2292 return;
2293
2294 /* can't use this function for current thread as GetThreadContext
2295 * doesn't support getting context from current thread */
2296 if (hThread == GetCurrentThread())
2297 return;
2298
2299 DPRINTF("Backtrace:\n");
2300
2301 _DBUS_ZERO(context);
2302 context.ContextFlags = CONTEXT_FULL;
2303
2304 SuspendThread(hThread);
2305
2306 if (!GetThreadContext(hThread, &context))
2307 {
2308 DPRINTF("Couldn't get thread context (error %ld)\n", GetLastError());
2309 ResumeThread(hThread);
2310 return;
2311 }
2312
2313 _DBUS_ZERO(sf);
2314
2315 #ifdef __i386__
2316 sf.AddrFrame.Offset = context.Ebp;
2317 sf.AddrFrame.Mode = AddrModeFlat;
2318 sf.AddrPC.Offset = context.Eip;
2319 sf.AddrPC.Mode = AddrModeFlat;
2320 dwImageType = IMAGE_FILE_MACHINE_I386;
2321 #elif _M_X64
2322 dwImageType = IMAGE_FILE_MACHINE_AMD64;
2323 sf.AddrPC.Offset = context.Rip;
2324 sf.AddrPC.Mode = AddrModeFlat;
2325 sf.AddrFrame.Offset = context.Rsp;
2326 sf.AddrFrame.Mode = AddrModeFlat;
2327 sf.AddrStack.Offset = context.Rsp;
2328 sf.AddrStack.Mode = AddrModeFlat;
2329 #elif _M_IA64
2330 dwImageType = IMAGE_FILE_MACHINE_IA64;
2331 sf.AddrPC.Offset = context.StIIP;
2332 sf.AddrPC.Mode = AddrModeFlat;
2333 sf.AddrFrame.Offset = context.IntSp;
2334 sf.AddrFrame.Mode = AddrModeFlat;
2335 sf.AddrBStore.Offset= context.RsBSP;
2336 sf.AddrBStore.Mode = AddrModeFlat;
2337 sf.AddrStack.Offset = context.IntSp;
2338 sf.AddrStack.Mode = AddrModeFlat;
2339 #else
2340 # error You need to fill in the STACKFRAME structure for your architecture
2341 #endif
2342
2343 while (pStackWalk(dwImageType, GetCurrentProcess(),
2344 hThread, &sf, &context, NULL, pSymFunctionTableAccess,
2345 pSymGetModuleBase, NULL))
2346 {
2347 BYTE buffer[256];
2348 IMAGEHLP_SYMBOL * pSymbol = (IMAGEHLP_SYMBOL *)buffer;
2349 DWORD dwDisplacement;
2350
2351 pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
2352 pSymbol->MaxNameLength = sizeof(buffer) - sizeof(IMAGEHLP_SYMBOL) + 1;
2353
2354 if (!pSymGetSymFromAddr(GetCurrentProcess(), sf.AddrPC.Offset,
2355 &dwDisplacement, pSymbol))
2356 {
2357 IMAGEHLP_MODULE ModuleInfo;
2358 ModuleInfo.SizeOfStruct = sizeof(ModuleInfo);
2359
2360 if (!pSymGetModuleInfo(GetCurrentProcess(), sf.AddrPC.Offset,
2361 &ModuleInfo))
2362 DPRINTF("1\t%p\n", (void*)sf.AddrPC.Offset);
2363 else
2364 DPRINTF("2\t%s+0x%lx\n", ModuleInfo.ImageName,
2365 sf.AddrPC.Offset - ModuleInfo.BaseOfImage);
2366 }
2367 else if (dwDisplacement)
2368 DPRINTF("3\t%s+0x%lx\n", pSymbol->Name, dwDisplacement);
2369 else
2370 DPRINTF("4\t%s\n", pSymbol->Name);
2371 }
2372
2373 ResumeThread(hThread);
2374 }
2375
dump_thread_proc(LPVOID lpParameter)2376 static DWORD WINAPI dump_thread_proc(LPVOID lpParameter)
2377 {
2378 dump_backtrace_for_thread((HANDLE)lpParameter);
2379 return 0;
2380 }
2381
2382 /* cannot get valid context from current thread, so we have to execute
2383 * backtrace from another thread */
dump_backtrace()2384 static void dump_backtrace()
2385 {
2386 HANDLE hCurrentThread;
2387 HANDLE hThread;
2388 DWORD dwThreadId;
2389 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
2390 GetCurrentProcess(), &hCurrentThread, 0, FALSE, DUPLICATE_SAME_ACCESS);
2391 hThread = CreateThread(NULL, 0, dump_thread_proc, (LPVOID)hCurrentThread,
2392 0, &dwThreadId);
2393 WaitForSingleObject(hThread, INFINITE);
2394 CloseHandle(hThread);
2395 CloseHandle(hCurrentThread);
2396 }
2397 #endif
2398 #endif /* asserts or tests enabled */
2399
2400 #ifdef BACKTRACES
_dbus_print_backtrace(void)2401 void _dbus_print_backtrace(void)
2402 {
2403 init_backtrace();
2404 dump_backtrace();
2405 }
2406 #else
_dbus_print_backtrace(void)2407 void _dbus_print_backtrace(void)
2408 {
2409 _dbus_verbose (" D-Bus not compiled with backtrace support\n");
2410 }
2411 #endif
2412
fromAscii(char ascii)2413 static dbus_uint32_t fromAscii(char ascii)
2414 {
2415 if(ascii >= '0' && ascii <= '9')
2416 return ascii - '0';
2417 if(ascii >= 'A' && ascii <= 'F')
2418 return ascii - 'A' + 10;
2419 if(ascii >= 'a' && ascii <= 'f')
2420 return ascii - 'a' + 10;
2421 return 0;
2422 }
2423
_dbus_read_local_machine_uuid(DBusGUID * machine_id,dbus_bool_t create_if_not_found,DBusError * error)2424 dbus_bool_t _dbus_read_local_machine_uuid (DBusGUID *machine_id,
2425 dbus_bool_t create_if_not_found,
2426 DBusError *error)
2427 {
2428 #ifdef DBUS_WINCE
2429 return TRUE;
2430 // TODO
2431 #else
2432 HW_PROFILE_INFOA info;
2433 char *lpc = &info.szHwProfileGuid[0];
2434 dbus_uint32_t u;
2435
2436 // the hw-profile guid lives long enough
2437 if(!GetCurrentHwProfileA(&info))
2438 {
2439 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); // FIXME
2440 return FALSE;
2441 }
2442
2443 // Form: {12340001-4980-1920-6788-123456789012}
2444 lpc++;
2445 // 12340001
2446 u = ((fromAscii(lpc[0]) << 0) |
2447 (fromAscii(lpc[1]) << 4) |
2448 (fromAscii(lpc[2]) << 8) |
2449 (fromAscii(lpc[3]) << 12) |
2450 (fromAscii(lpc[4]) << 16) |
2451 (fromAscii(lpc[5]) << 20) |
2452 (fromAscii(lpc[6]) << 24) |
2453 (fromAscii(lpc[7]) << 28));
2454 machine_id->as_uint32s[0] = u;
2455
2456 lpc += 9;
2457 // 4980-1920
2458 u = ((fromAscii(lpc[0]) << 0) |
2459 (fromAscii(lpc[1]) << 4) |
2460 (fromAscii(lpc[2]) << 8) |
2461 (fromAscii(lpc[3]) << 12) |
2462 (fromAscii(lpc[5]) << 16) |
2463 (fromAscii(lpc[6]) << 20) |
2464 (fromAscii(lpc[7]) << 24) |
2465 (fromAscii(lpc[8]) << 28));
2466 machine_id->as_uint32s[1] = u;
2467
2468 lpc += 10;
2469 // 6788-1234
2470 u = ((fromAscii(lpc[0]) << 0) |
2471 (fromAscii(lpc[1]) << 4) |
2472 (fromAscii(lpc[2]) << 8) |
2473 (fromAscii(lpc[3]) << 12) |
2474 (fromAscii(lpc[5]) << 16) |
2475 (fromAscii(lpc[6]) << 20) |
2476 (fromAscii(lpc[7]) << 24) |
2477 (fromAscii(lpc[8]) << 28));
2478 machine_id->as_uint32s[2] = u;
2479
2480 lpc += 9;
2481 // 56789012
2482 u = ((fromAscii(lpc[0]) << 0) |
2483 (fromAscii(lpc[1]) << 4) |
2484 (fromAscii(lpc[2]) << 8) |
2485 (fromAscii(lpc[3]) << 12) |
2486 (fromAscii(lpc[4]) << 16) |
2487 (fromAscii(lpc[5]) << 20) |
2488 (fromAscii(lpc[6]) << 24) |
2489 (fromAscii(lpc[7]) << 28));
2490 machine_id->as_uint32s[3] = u;
2491 #endif
2492 return TRUE;
2493 }
2494
2495 static
_dbus_global_lock(const char * mutexname)2496 HANDLE _dbus_global_lock (const char *mutexname)
2497 {
2498 HANDLE mutex;
2499 DWORD gotMutex;
2500
2501 mutex = CreateMutexA( NULL, FALSE, mutexname );
2502 if( !mutex )
2503 {
2504 return FALSE;
2505 }
2506
2507 gotMutex = WaitForSingleObject( mutex, INFINITE );
2508 switch( gotMutex )
2509 {
2510 case WAIT_ABANDONED:
2511 ReleaseMutex (mutex);
2512 CloseHandle (mutex);
2513 return 0;
2514 case WAIT_FAILED:
2515 case WAIT_TIMEOUT:
2516 return 0;
2517 }
2518
2519 return mutex;
2520 }
2521
2522 static
_dbus_global_unlock(HANDLE mutex)2523 void _dbus_global_unlock (HANDLE mutex)
2524 {
2525 ReleaseMutex (mutex);
2526 CloseHandle (mutex);
2527 }
2528
2529 // for proper cleanup in dbus-daemon
2530 static HANDLE hDBusDaemonMutex = NULL;
2531 static HANDLE hDBusSharedMem = NULL;
2532 // sync _dbus_daemon_publish_session_bus_address, _dbus_daemon_unpublish_session_bus_address and _dbus_daemon_already_runs
2533 static const char *cUniqueDBusInitMutex = "UniqueDBusInitMutex";
2534 // sync _dbus_get_autolaunch_address
2535 static const char *cDBusAutolaunchMutex = "DBusAutolaunchMutex";
2536 // mutex to determine if dbus-daemon is already started (per user)
2537 static const char *cDBusDaemonMutex = "DBusDaemonMutex";
2538 // named shm for dbus adress info (per user)
2539 #ifdef _DEBUG
2540 static const char *cDBusDaemonAddressInfo = "DBusDaemonAddressInfoDebug";
2541 #else
2542 static const char *cDBusDaemonAddressInfo = "DBusDaemonAddressInfo";
2543 #endif
2544
2545
2546 void
_dbus_daemon_publish_session_bus_address(const char * address)2547 _dbus_daemon_publish_session_bus_address (const char* address)
2548 {
2549 HANDLE lock;
2550 char *shared_addr = NULL;
2551 DWORD ret;
2552
2553 _dbus_assert (address);
2554 // before _dbus_global_lock to keep correct lock/release order
2555 hDBusDaemonMutex = CreateMutexA( NULL, FALSE, cDBusDaemonMutex );
2556 ret = WaitForSingleObject( hDBusDaemonMutex, 1000 );
2557 if ( ret != WAIT_OBJECT_0 ) {
2558 _dbus_warn("Could not lock mutex %s (return code %ld). daemon already running? Bus address not published.\n", cDBusDaemonMutex, ret );
2559 return;
2560 }
2561
2562 // sync _dbus_daemon_publish_session_bus_address, _dbus_daemon_unpublish_session_bus_address and _dbus_daemon_already_runs
2563 lock = _dbus_global_lock( cUniqueDBusInitMutex );
2564
2565 // create shm
2566 hDBusSharedMem = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
2567 0, strlen( address ) + 1, cDBusDaemonAddressInfo );
2568 _dbus_assert( hDBusSharedMem );
2569
2570 shared_addr = MapViewOfFile( hDBusSharedMem, FILE_MAP_WRITE, 0, 0, 0 );
2571
2572 _dbus_assert (shared_addr);
2573
2574 strcpy( shared_addr, address);
2575
2576 // cleanup
2577 UnmapViewOfFile( shared_addr );
2578
2579 _dbus_global_unlock( lock );
2580 }
2581
2582 void
_dbus_daemon_unpublish_session_bus_address(void)2583 _dbus_daemon_unpublish_session_bus_address (void)
2584 {
2585 HANDLE lock;
2586
2587 // sync _dbus_daemon_publish_session_bus_address, _dbus_daemon_unpublish_session_bus_address and _dbus_daemon_already_runs
2588 lock = _dbus_global_lock( cUniqueDBusInitMutex );
2589
2590 CloseHandle( hDBusSharedMem );
2591
2592 hDBusSharedMem = NULL;
2593
2594 ReleaseMutex( hDBusDaemonMutex );
2595
2596 CloseHandle( hDBusDaemonMutex );
2597
2598 hDBusDaemonMutex = NULL;
2599
2600 _dbus_global_unlock( lock );
2601 }
2602
2603 static dbus_bool_t
_dbus_get_autolaunch_shm(DBusString * address)2604 _dbus_get_autolaunch_shm (DBusString *address)
2605 {
2606 HANDLE sharedMem;
2607 char *shared_addr;
2608 int i;
2609
2610 // read shm
2611 for(i=0;i<20;++i) {
2612 // we know that dbus-daemon is available, so we wait until shm is available
2613 sharedMem = OpenFileMappingA( FILE_MAP_READ, FALSE, cDBusDaemonAddressInfo );
2614 if( sharedMem == 0 )
2615 Sleep( 100 );
2616 if ( sharedMem != 0)
2617 break;
2618 }
2619
2620 if( sharedMem == 0 )
2621 return FALSE;
2622
2623 shared_addr = MapViewOfFile( sharedMem, FILE_MAP_READ, 0, 0, 0 );
2624
2625 if( !shared_addr )
2626 return FALSE;
2627
2628 _dbus_string_init( address );
2629
2630 _dbus_string_append( address, shared_addr );
2631
2632 // cleanup
2633 UnmapViewOfFile( shared_addr );
2634
2635 CloseHandle( sharedMem );
2636
2637 return TRUE;
2638 }
2639
2640 static dbus_bool_t
_dbus_daemon_already_runs(DBusString * address)2641 _dbus_daemon_already_runs (DBusString *address)
2642 {
2643 HANDLE lock;
2644 HANDLE daemon;
2645 dbus_bool_t bRet = TRUE;
2646
2647 // sync _dbus_daemon_publish_session_bus_address, _dbus_daemon_unpublish_session_bus_address and _dbus_daemon_already_runs
2648 lock = _dbus_global_lock( cUniqueDBusInitMutex );
2649
2650 // do checks
2651 daemon = CreateMutexA( NULL, FALSE, cDBusDaemonMutex );
2652 if(WaitForSingleObject( daemon, 10 ) != WAIT_TIMEOUT)
2653 {
2654 ReleaseMutex (daemon);
2655 CloseHandle (daemon);
2656
2657 _dbus_global_unlock( lock );
2658 return FALSE;
2659 }
2660
2661 // read shm
2662 bRet = _dbus_get_autolaunch_shm( address );
2663
2664 // cleanup
2665 CloseHandle ( daemon );
2666
2667 _dbus_global_unlock( lock );
2668
2669 return bRet;
2670 }
2671
2672 dbus_bool_t
_dbus_get_autolaunch_address(DBusString * address,DBusError * error)2673 _dbus_get_autolaunch_address (DBusString *address,
2674 DBusError *error)
2675 {
2676 HANDLE mutex;
2677 STARTUPINFOA si;
2678 PROCESS_INFORMATION pi;
2679 dbus_bool_t retval = FALSE;
2680 LPSTR lpFile;
2681 char dbus_exe_path[MAX_PATH];
2682 char dbus_args[MAX_PATH * 2];
2683 const char * daemon_name = DBUS_DAEMON_NAME ".exe";
2684
2685 mutex = _dbus_global_lock ( cDBusAutolaunchMutex );
2686
2687 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
2688
2689 if (_dbus_daemon_already_runs(address))
2690 {
2691 _dbus_verbose("found already running dbus daemon\n");
2692 retval = TRUE;
2693 goto out;
2694 }
2695
2696 if (!SearchPathA(NULL, daemon_name, NULL, sizeof(dbus_exe_path), dbus_exe_path, &lpFile))
2697 {
2698 printf ("please add the path to %s to your PATH environment variable\n", daemon_name);
2699 printf ("or start the daemon manually\n\n");
2700 goto out;
2701 }
2702
2703 // Create process
2704 ZeroMemory( &si, sizeof(si) );
2705 si.cb = sizeof(si);
2706 ZeroMemory( &pi, sizeof(pi) );
2707
2708 _snprintf(dbus_args, sizeof(dbus_args) - 1, "\"%s\" %s", dbus_exe_path, " --session");
2709
2710 // argv[i] = "--config-file=bus\\session.conf";
2711 // printf("create process \"%s\" %s\n", dbus_exe_path, dbus_args);
2712 if(CreateProcessA(dbus_exe_path, dbus_args, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi))
2713 {
2714 CloseHandle (pi.hThread);
2715 CloseHandle (pi.hProcess);
2716 retval = _dbus_get_autolaunch_shm( address );
2717 }
2718
2719 if (retval == FALSE)
2720 dbus_set_error_const (error, DBUS_ERROR_FAILED, "Failed to launch dbus-daemon");
2721
2722 out:
2723 if (retval)
2724 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
2725 else
2726 _DBUS_ASSERT_ERROR_IS_SET (error);
2727
2728 _dbus_global_unlock (mutex);
2729
2730 return retval;
2731 }
2732
2733
2734 /** Makes the file readable by every user in the system.
2735 *
2736 * @param filename the filename
2737 * @param error error location
2738 * @returns #TRUE if the file's permissions could be changed.
2739 */
2740 dbus_bool_t
_dbus_make_file_world_readable(const DBusString * filename,DBusError * error)2741 _dbus_make_file_world_readable(const DBusString *filename,
2742 DBusError *error)
2743 {
2744 // TODO
2745 return TRUE;
2746 }
2747
2748 /**
2749 * return the relocated DATADIR
2750 *
2751 * @returns relocated DATADIR static string
2752 */
2753
2754 static const char *
_dbus_windows_get_datadir(void)2755 _dbus_windows_get_datadir (void)
2756 {
2757 return _dbus_replace_install_prefix(DBUS_DATADIR);
2758 }
2759
2760 #undef DBUS_DATADIR
2761 #define DBUS_DATADIR _dbus_windows_get_datadir ()
2762
2763
2764 #define DBUS_STANDARD_SESSION_SERVICEDIR "/dbus-1/services"
2765 #define DBUS_STANDARD_SYSTEM_SERVICEDIR "/dbus-1/system-services"
2766
2767 /**
2768 * Returns the standard directories for a session bus to look for service
2769 * activation files
2770 *
2771 * On Windows this should be data directories:
2772 *
2773 * %CommonProgramFiles%/dbus
2774 *
2775 * and
2776 *
2777 * relocated DBUS_DATADIR
2778 *
2779 * @param dirs the directory list we are returning
2780 * @returns #FALSE on OOM
2781 */
2782
2783 dbus_bool_t
_dbus_get_standard_session_servicedirs(DBusList ** dirs)2784 _dbus_get_standard_session_servicedirs (DBusList **dirs)
2785 {
2786 const char *common_progs;
2787 DBusString servicedir_path;
2788
2789 if (!_dbus_string_init (&servicedir_path))
2790 return FALSE;
2791
2792 #ifdef DBUS_WINCE
2793 {
2794 /* On Windows CE, we adjust datadir dynamically to installation location. */
2795 const char *data_dir = _dbus_getenv ("DBUS_DATADIR");
2796
2797 if (data_dir != NULL)
2798 {
2799 if (!_dbus_string_append (&servicedir_path, data_dir))
2800 goto oom;
2801
2802 if (!_dbus_string_append (&servicedir_path, _DBUS_PATH_SEPARATOR))
2803 goto oom;
2804 }
2805 }
2806 #else
2807 if (!_dbus_string_append (&servicedir_path, DBUS_DATADIR))
2808 goto oom;
2809
2810 if (!_dbus_string_append (&servicedir_path, _DBUS_PATH_SEPARATOR))
2811 goto oom;
2812 #endif
2813
2814 common_progs = _dbus_getenv ("CommonProgramFiles");
2815
2816 if (common_progs != NULL)
2817 {
2818 if (!_dbus_string_append (&servicedir_path, common_progs))
2819 goto oom;
2820
2821 if (!_dbus_string_append (&servicedir_path, _DBUS_PATH_SEPARATOR))
2822 goto oom;
2823 }
2824
2825 if (!_dbus_split_paths_and_append (&servicedir_path,
2826 DBUS_STANDARD_SESSION_SERVICEDIR,
2827 dirs))
2828 goto oom;
2829
2830 _dbus_string_free (&servicedir_path);
2831 return TRUE;
2832
2833 oom:
2834 _dbus_string_free (&servicedir_path);
2835 return FALSE;
2836 }
2837
2838 /**
2839 * Returns the standard directories for a system bus to look for service
2840 * activation files
2841 *
2842 * On UNIX this should be the standard xdg freedesktop.org data directories:
2843 *
2844 * XDG_DATA_DIRS=${XDG_DATA_DIRS-/usr/local/share:/usr/share}
2845 *
2846 * and
2847 *
2848 * DBUS_DATADIR
2849 *
2850 * On Windows there is no system bus and this function can return nothing.
2851 *
2852 * @param dirs the directory list we are returning
2853 * @returns #FALSE on OOM
2854 */
2855
2856 dbus_bool_t
_dbus_get_standard_system_servicedirs(DBusList ** dirs)2857 _dbus_get_standard_system_servicedirs (DBusList **dirs)
2858 {
2859 *dirs = NULL;
2860 return TRUE;
2861 }
2862
2863 _DBUS_DEFINE_GLOBAL_LOCK (atomic);
2864
2865 /**
2866 * Atomically increments an integer
2867 *
2868 * @param atomic pointer to the integer to increment
2869 * @returns the value before incrementing
2870 *
2871 */
2872 dbus_int32_t
_dbus_atomic_inc(DBusAtomic * atomic)2873 _dbus_atomic_inc (DBusAtomic *atomic)
2874 {
2875 // +/- 1 is needed here!
2876 // no volatile argument with mingw
2877 return InterlockedIncrement (&atomic->value) - 1;
2878 }
2879
2880 /**
2881 * Atomically decrement an integer
2882 *
2883 * @param atomic pointer to the integer to decrement
2884 * @returns the value before decrementing
2885 *
2886 */
2887 dbus_int32_t
_dbus_atomic_dec(DBusAtomic * atomic)2888 _dbus_atomic_dec (DBusAtomic *atomic)
2889 {
2890 // +/- 1 is needed here!
2891 // no volatile argument with mingw
2892 return InterlockedDecrement (&atomic->value) + 1;
2893 }
2894
2895 /**
2896 * Called when the bus daemon is signaled to reload its configuration; any
2897 * caches should be nuked. Of course any caches that need explicit reload
2898 * are probably broken, but c'est la vie.
2899 *
2900 *
2901 */
2902 void
_dbus_flush_caches(void)2903 _dbus_flush_caches (void)
2904 {
2905 }
2906
2907 /**
2908 * See if errno is EAGAIN or EWOULDBLOCK (this has to be done differently
2909 * for Winsock so is abstracted)
2910 *
2911 * @returns #TRUE if errno == EAGAIN or errno == EWOULDBLOCK
2912 */
2913 dbus_bool_t
_dbus_get_is_errno_eagain_or_ewouldblock(void)2914 _dbus_get_is_errno_eagain_or_ewouldblock (void)
2915 {
2916 return errno == WSAEWOULDBLOCK;
2917 }
2918
2919 /**
2920 * return the absolute path of the dbus installation
2921 *
2922 * @param s buffer for installation path
2923 * @param len length of buffer
2924 * @returns #FALSE on failure
2925 */
2926 static dbus_bool_t
_dbus_get_install_root(char * prefix,int len)2927 _dbus_get_install_root(char *prefix, int len)
2928 {
2929 //To find the prefix, we cut the filename and also \bin\ if present
2930 char* p = 0;
2931 int i;
2932 DWORD pathLength;
2933 char *lastSlash;
2934 SetLastError( 0 );
2935 pathLength = GetModuleFileNameA(_dbus_win_get_dll_hmodule(), prefix, len);
2936 if ( pathLength == 0 || GetLastError() != 0 ) {
2937 *prefix = '\0';
2938 return FALSE;
2939 }
2940 lastSlash = _mbsrchr(prefix, '\\');
2941 if (lastSlash == NULL) {
2942 *prefix = '\0';
2943 return FALSE;
2944 }
2945 //cut off binary name
2946 lastSlash[1] = 0;
2947
2948 //cut possible "\\bin"
2949
2950 //this fails if we are in a double-byte system codepage and the
2951 //folder's name happens to end with the *bytes*
2952 //"\\bin"... (I.e. the second byte of some Han character and then
2953 //the Latin "bin", but that is not likely I think...
2954 if (lastSlash - prefix >= 4 && strnicmp(lastSlash - 4, "\\bin", 4) == 0)
2955 lastSlash[-3] = 0;
2956 else if (lastSlash - prefix >= 10 && strnicmp(lastSlash - 10, "\\bin\\debug", 10) == 0)
2957 lastSlash[-9] = 0;
2958 else if (lastSlash - prefix >= 12 && strnicmp(lastSlash - 12, "\\bin\\release", 12) == 0)
2959 lastSlash[-11] = 0;
2960
2961 return TRUE;
2962 }
2963
2964 /**
2965 find config file either from installation or build root according to
2966 the following path layout
2967 install-root/
2968 bin/dbus-daemon[d].exe
2969 etc/<config-file>.conf *or* etc/dbus-1/<config-file>.conf
2970 (the former above is what dbus4win uses, the latter above is
2971 what a "normal" Unix-style "make install" uses)
2972
2973 build-root/
2974 bin/dbus-daemon[d].exe
2975 bus/<config-file>.conf
2976 */
2977 dbus_bool_t
_dbus_get_config_file_name(DBusString * config_file,char * s)2978 _dbus_get_config_file_name(DBusString *config_file, char *s)
2979 {
2980 char path[MAX_PATH*2];
2981 int path_size = sizeof(path);
2982
2983 if (!_dbus_get_install_root(path,path_size))
2984 return FALSE;
2985
2986 if(strlen(s) + 4 + strlen(path) > sizeof(path)-2)
2987 return FALSE;
2988 strcat(path,"etc\\");
2989 strcat(path,s);
2990 if (_dbus_file_exists(path))
2991 {
2992 // find path from executable
2993 if (!_dbus_string_append (config_file, path))
2994 return FALSE;
2995 }
2996 else
2997 {
2998 if (!_dbus_get_install_root(path,path_size))
2999 return FALSE;
3000 if(strlen(s) + 11 + strlen(path) > sizeof(path)-2)
3001 return FALSE;
3002 strcat(path,"etc\\dbus-1\\");
3003 strcat(path,s);
3004
3005 if (_dbus_file_exists(path))
3006 {
3007 if (!_dbus_string_append (config_file, path))
3008 return FALSE;
3009 }
3010 else
3011 {
3012 if (!_dbus_get_install_root(path,path_size))
3013 return FALSE;
3014 if(strlen(s) + 4 + strlen(path) > sizeof(path)-2)
3015 return FALSE;
3016 strcat(path,"bus\\");
3017 strcat(path,s);
3018
3019 if (_dbus_file_exists(path))
3020 {
3021 if (!_dbus_string_append (config_file, path))
3022 return FALSE;
3023 }
3024 }
3025 }
3026 return TRUE;
3027 }
3028
3029 /**
3030 * Append the absolute path of the system.conf file
3031 * (there is no system bus on Windows so this can just
3032 * return FALSE and print a warning or something)
3033 *
3034 * @param str the string to append to
3035 * @returns #FALSE if no memory
3036 */
3037 dbus_bool_t
_dbus_append_system_config_file(DBusString * str)3038 _dbus_append_system_config_file (DBusString *str)
3039 {
3040 return _dbus_get_config_file_name(str, "system.conf");
3041 }
3042
3043 /**
3044 * Append the absolute path of the session.conf file.
3045 *
3046 * @param str the string to append to
3047 * @returns #FALSE if no memory
3048 */
3049 dbus_bool_t
_dbus_append_session_config_file(DBusString * str)3050 _dbus_append_session_config_file (DBusString *str)
3051 {
3052 return _dbus_get_config_file_name(str, "session.conf");
3053 }
3054
3055 /* See comment in dbus-sysdeps-unix.c */
3056 dbus_bool_t
_dbus_lookup_session_address(dbus_bool_t * supported,DBusString * address,DBusError * error)3057 _dbus_lookup_session_address (dbus_bool_t *supported,
3058 DBusString *address,
3059 DBusError *error)
3060 {
3061 /* Probably fill this in with something based on COM? */
3062 *supported = FALSE;
3063 return TRUE;
3064 }
3065
3066 /**
3067 * Appends the directory in which a keyring for the given credentials
3068 * should be stored. The credentials should have either a Windows or
3069 * UNIX user in them. The directory should be an absolute path.
3070 *
3071 * On UNIX the directory is ~/.dbus-keyrings while on Windows it should probably
3072 * be something else, since the dotfile convention is not normal on Windows.
3073 *
3074 * @param directory string to append directory to
3075 * @param credentials credentials the directory should be for
3076 *
3077 * @returns #FALSE on no memory
3078 */
3079 dbus_bool_t
_dbus_append_keyring_directory_for_credentials(DBusString * directory,DBusCredentials * credentials)3080 _dbus_append_keyring_directory_for_credentials (DBusString *directory,
3081 DBusCredentials *credentials)
3082 {
3083 DBusString homedir;
3084 DBusString dotdir;
3085 dbus_uid_t uid;
3086 const char *homepath;
3087 const char *homedrive;
3088
3089 _dbus_assert (credentials != NULL);
3090 _dbus_assert (!_dbus_credentials_are_anonymous (credentials));
3091
3092 if (!_dbus_string_init (&homedir))
3093 return FALSE;
3094
3095 homedrive = _dbus_getenv("HOMEDRIVE");
3096 if (homedrive != NULL && *homedrive != '\0')
3097 {
3098 _dbus_string_append(&homedir,homedrive);
3099 }
3100
3101 homepath = _dbus_getenv("HOMEPATH");
3102 if (homepath != NULL && *homepath != '\0')
3103 {
3104 _dbus_string_append(&homedir,homepath);
3105 }
3106
3107 #ifdef DBUS_BUILD_TESTS
3108 {
3109 const char *override;
3110
3111 override = _dbus_getenv ("DBUS_TEST_HOMEDIR");
3112 if (override != NULL && *override != '\0')
3113 {
3114 _dbus_string_set_length (&homedir, 0);
3115 if (!_dbus_string_append (&homedir, override))
3116 goto failed;
3117
3118 _dbus_verbose ("Using fake homedir for testing: %s\n",
3119 _dbus_string_get_const_data (&homedir));
3120 }
3121 else
3122 {
3123 static dbus_bool_t already_warned = FALSE;
3124 if (!already_warned)
3125 {
3126 _dbus_warn ("Using your real home directory for testing, set DBUS_TEST_HOMEDIR to avoid\n");
3127 already_warned = TRUE;
3128 }
3129 }
3130 }
3131 #endif
3132
3133 #ifdef DBUS_WINCE
3134 /* It's not possible to create a .something directory in Windows CE
3135 using the file explorer. */
3136 #define KEYRING_DIR "dbus-keyrings"
3137 #else
3138 #define KEYRING_DIR ".dbus-keyrings"
3139 #endif
3140
3141 _dbus_string_init_const (&dotdir, KEYRING_DIR);
3142 if (!_dbus_concat_dir_and_file (&homedir,
3143 &dotdir))
3144 goto failed;
3145
3146 if (!_dbus_string_copy (&homedir, 0,
3147 directory, _dbus_string_get_length (directory))) {
3148 goto failed;
3149 }
3150
3151 _dbus_string_free (&homedir);
3152 return TRUE;
3153
3154 failed:
3155 _dbus_string_free (&homedir);
3156 return FALSE;
3157 }
3158
3159 /** Checks if a file exists
3160 *
3161 * @param file full path to the file
3162 * @returns #TRUE if file exists
3163 */
3164 dbus_bool_t
_dbus_file_exists(const char * file)3165 _dbus_file_exists (const char *file)
3166 {
3167 DWORD attributes = GetFileAttributesA (file);
3168
3169 if (attributes != INVALID_FILE_ATTRIBUTES && GetLastError() != ERROR_PATH_NOT_FOUND)
3170 return TRUE;
3171 else
3172 return FALSE;
3173 }
3174
3175 /**
3176 * A wrapper around strerror() because some platforms
3177 * may be lame and not have strerror().
3178 *
3179 * @param error_number errno.
3180 * @returns error description.
3181 */
3182 const char*
_dbus_strerror(int error_number)3183 _dbus_strerror (int error_number)
3184 {
3185 #ifdef DBUS_WINCE
3186 // TODO
3187 return "unknown";
3188 #else
3189 const char *msg;
3190
3191 switch (error_number)
3192 {
3193 case WSAEINTR:
3194 return "Interrupted function call";
3195 case WSAEACCES:
3196 return "Permission denied";
3197 case WSAEFAULT:
3198 return "Bad address";
3199 case WSAEINVAL:
3200 return "Invalid argument";
3201 case WSAEMFILE:
3202 return "Too many open files";
3203 case WSAEWOULDBLOCK:
3204 return "Resource temporarily unavailable";
3205 case WSAEINPROGRESS:
3206 return "Operation now in progress";
3207 case WSAEALREADY:
3208 return "Operation already in progress";
3209 case WSAENOTSOCK:
3210 return "Socket operation on nonsocket";
3211 case WSAEDESTADDRREQ:
3212 return "Destination address required";
3213 case WSAEMSGSIZE:
3214 return "Message too long";
3215 case WSAEPROTOTYPE:
3216 return "Protocol wrong type for socket";
3217 case WSAENOPROTOOPT:
3218 return "Bad protocol option";
3219 case WSAEPROTONOSUPPORT:
3220 return "Protocol not supported";
3221 case WSAESOCKTNOSUPPORT:
3222 return "Socket type not supported";
3223 case WSAEOPNOTSUPP:
3224 return "Operation not supported";
3225 case WSAEPFNOSUPPORT:
3226 return "Protocol family not supported";
3227 case WSAEAFNOSUPPORT:
3228 return "Address family not supported by protocol family";
3229 case WSAEADDRINUSE:
3230 return "Address already in use";
3231 case WSAEADDRNOTAVAIL:
3232 return "Cannot assign requested address";
3233 case WSAENETDOWN:
3234 return "Network is down";
3235 case WSAENETUNREACH:
3236 return "Network is unreachable";
3237 case WSAENETRESET:
3238 return "Network dropped connection on reset";
3239 case WSAECONNABORTED:
3240 return "Software caused connection abort";
3241 case WSAECONNRESET:
3242 return "Connection reset by peer";
3243 case WSAENOBUFS:
3244 return "No buffer space available";
3245 case WSAEISCONN:
3246 return "Socket is already connected";
3247 case WSAENOTCONN:
3248 return "Socket is not connected";
3249 case WSAESHUTDOWN:
3250 return "Cannot send after socket shutdown";
3251 case WSAETIMEDOUT:
3252 return "Connection timed out";
3253 case WSAECONNREFUSED:
3254 return "Connection refused";
3255 case WSAEHOSTDOWN:
3256 return "Host is down";
3257 case WSAEHOSTUNREACH:
3258 return "No route to host";
3259 case WSAEPROCLIM:
3260 return "Too many processes";
3261 case WSAEDISCON:
3262 return "Graceful shutdown in progress";
3263 case WSATYPE_NOT_FOUND:
3264 return "Class type not found";
3265 case WSAHOST_NOT_FOUND:
3266 return "Host not found";
3267 case WSATRY_AGAIN:
3268 return "Nonauthoritative host not found";
3269 case WSANO_RECOVERY:
3270 return "This is a nonrecoverable error";
3271 case WSANO_DATA:
3272 return "Valid name, no data record of requested type";
3273 case WSA_INVALID_HANDLE:
3274 return "Specified event object handle is invalid";
3275 case WSA_INVALID_PARAMETER:
3276 return "One or more parameters are invalid";
3277 case WSA_IO_INCOMPLETE:
3278 return "Overlapped I/O event object not in signaled state";
3279 case WSA_IO_PENDING:
3280 return "Overlapped operations will complete later";
3281 case WSA_NOT_ENOUGH_MEMORY:
3282 return "Insufficient memory available";
3283 case WSA_OPERATION_ABORTED:
3284 return "Overlapped operation aborted";
3285 #ifdef WSAINVALIDPROCTABLE
3286
3287 case WSAINVALIDPROCTABLE:
3288 return "Invalid procedure table from service provider";
3289 #endif
3290 #ifdef WSAINVALIDPROVIDER
3291
3292 case WSAINVALIDPROVIDER:
3293 return "Invalid service provider version number";
3294 #endif
3295 #ifdef WSAPROVIDERFAILEDINIT
3296
3297 case WSAPROVIDERFAILEDINIT:
3298 return "Unable to initialize a service provider";
3299 #endif
3300
3301 case WSASYSCALLFAILURE:
3302 return "System call failure";
3303 }
3304 msg = strerror (error_number);
3305 if (msg == NULL)
3306 msg = "unknown";
3307
3308 return msg;
3309 #endif //DBUS_WINCE
3310 }
3311
3312 /**
3313 * Assigns an error name and message corresponding to a Win32 error
3314 * code to a DBusError. Does nothing if error is #NULL.
3315 *
3316 * @param error the error.
3317 * @param code the Win32 error code
3318 */
3319 void
_dbus_win_set_error_from_win_error(DBusError * error,int code)3320 _dbus_win_set_error_from_win_error (DBusError *error,
3321 int code)
3322 {
3323 char *msg;
3324
3325 /* As we want the English message, use the A API */
3326 FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER |
3327 FORMAT_MESSAGE_IGNORE_INSERTS |
3328 FORMAT_MESSAGE_FROM_SYSTEM,
3329 NULL, code, MAKELANGID (LANG_ENGLISH, SUBLANG_ENGLISH_US),
3330 (LPSTR) &msg, 0, NULL);
3331 if (msg)
3332 {
3333 char *msg_copy;
3334
3335 msg_copy = dbus_malloc (strlen (msg));
3336 strcpy (msg_copy, msg);
3337 LocalFree (msg);
3338
3339 dbus_set_error (error, "win32.error", "%s", msg_copy);
3340 }
3341 else
3342 dbus_set_error (error, "win32.error", "Unknown error code %d or FormatMessage failed", code);
3343 }
3344
3345 void
_dbus_win_warn_win_error(const char * message,int code)3346 _dbus_win_warn_win_error (const char *message,
3347 int code)
3348 {
3349 DBusError error;
3350
3351 dbus_error_init (&error);
3352 _dbus_win_set_error_from_win_error (&error, code);
3353 _dbus_warn ("%s: %s\n", message, error.message);
3354 dbus_error_free (&error);
3355 }
3356
3357 /**
3358 * Removes a directory; Directory must be empty
3359 *
3360 * @param filename directory filename
3361 * @param error initialized error object
3362 * @returns #TRUE on success
3363 */
3364 dbus_bool_t
_dbus_delete_directory(const DBusString * filename,DBusError * error)3365 _dbus_delete_directory (const DBusString *filename,
3366 DBusError *error)
3367 {
3368 const char *filename_c;
3369
3370 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
3371
3372 filename_c = _dbus_string_get_const_data (filename);
3373
3374 if (RemoveDirectoryA (filename_c) == 0)
3375 {
3376 char *emsg = _dbus_win_error_string (GetLastError ());
3377 dbus_set_error (error, _dbus_win_error_from_last_error (),
3378 "Failed to remove directory %s: %s",
3379 filename_c, emsg);
3380 _dbus_win_free_error_string (emsg);
3381 return FALSE;
3382 }
3383
3384 return TRUE;
3385 }
3386
3387 /** @} end of sysdeps-win */
3388 /* tests in dbus-sysdeps-util.c */
3389
3390