From 70bfc74e54ac8a9a93885710cd8350d1a58b3406 Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Sat, 3 Mar 2007 17:25:54 +0000 Subject: * dbus/*-win.*,bus/*-win.*: added win32 platform related files. These files are only added to the cmake build system. The missing dbus-win32.patch file will be added later. --- dbus/dbus-sysdeps-win.c | 5178 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 5178 insertions(+) create mode 100644 dbus/dbus-sysdeps-win.c (limited to 'dbus/dbus-sysdeps-win.c') diff --git a/dbus/dbus-sysdeps-win.c b/dbus/dbus-sysdeps-win.c new file mode 100644 index 00000000..20c2400c --- /dev/null +++ b/dbus/dbus-sysdeps-win.c @@ -0,0 +1,5178 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-sysdeps.c Wrappers around system/libc features (internal to D-BUS implementation) + * + * Copyright (C) 2002, 2003 Red Hat, Inc. + * Copyright (C) 2003 CodeFactory AB + * Copyright (C) 2005 Novell, Inc. + * Copyright (C) 2006 Ralf Habacker + * Copyright (C) 2006 Peter Kümmel + * Copyright (C) 2006 Christian Ehrlicher + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#undef open + +#define STRSAFE_NO_DEPRECATE + +#ifndef DBUS_WINCE +#define _WIN32_WINNT 0x0500 +#endif + +#include "dbus-internals.h" +#include "dbus-sysdeps.h" +#include "dbus-threads.h" +#include "dbus-protocol.h" +#include "dbus-string.h" +#include "dbus-sysdeps-win.h" +#include "dbus-protocol.h" +#include "dbus-hash.h" +#include "dbus-sockets-win.h" +#include "dbus-userdb.h" +#include "dbus-list.h" + +#include +#include + +#include +#include +#include + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#ifndef HAVE_SOCKLEN_T +#define socklen_t int +#endif + +_DBUS_DEFINE_GLOBAL_LOCK (win_fds); +_DBUS_DEFINE_GLOBAL_LOCK (sid_atom_cache); + + +static +void +_dbus_lock_sockets() +{ + _dbus_assert (win_fds!=0); + _DBUS_LOCK (win_fds); +} + +static +void +_dbus_unlock_sockets() +{ + _dbus_assert (win_fds!=0); + _DBUS_UNLOCK (win_fds); +} + +#ifdef _DBUS_WIN_USE_RANDOMIZER +static int win_encap_randomizer; +#endif +static DBusHashTable *sid_atom_cache = NULL; + + +static DBusString dbusdir; +static int working_dir_init = 0; + +int _dbus_init_working_dir(char *s) +{ + /* change working directory to one level above + of dbus-daemon executable path. + This allows the usage of relative path in + config files or command line parameters */ + DBusString daemon_path,bin_path; + + if (!_dbus_string_init (&daemon_path)) + return FALSE; + + if (!_dbus_string_init (&bin_path)) + return FALSE; + + if (!_dbus_string_init (&dbusdir)) + return FALSE; + + _dbus_string_append(&daemon_path,s); + _dbus_string_get_dirname(&daemon_path,&bin_path); + _dbus_string_get_dirname(&bin_path,&dbusdir); + chdir(_dbus_string_get_const_data(&dbusdir)); + _dbus_verbose ("Change working path to %s\n",_dbus_string_get_const_data (&dbusdir)); + working_dir_init = 1; + return TRUE; +} + +DBusString *_dbus_get_working_dir(void) +{ + if (!working_dir_init) + return NULL; + + _dbus_verbose ("retrieving working path %s\n",_dbus_string_get_const_data (&dbusdir)); + return &dbusdir; +} + +/** + * File interface + * + */ +dbus_bool_t +_dbus_open_file (DBusFile *file, + const char *filename, + int oflag, + int pmode) +{ + if (pmode!=-1) + file->FDATA = _open (filename, oflag, pmode); + else + file->FDATA = _open (filename, oflag); + if (file->FDATA >= 0) + return TRUE; + else + { + file->FDATA = -1; + return FALSE; + } +} + +dbus_bool_t +_dbus_close_file (DBusFile *file, + DBusError *error) +{ + const int fd = file->FDATA; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + _dbus_assert (fd >= 0); + + if (_close (fd) == -1) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Could not close fd %d: %s", fd, + _dbus_strerror (errno)); + return FALSE; + } + + file->FDATA = -1; + _dbus_verbose ("closed C file descriptor %d:\n",fd); + + return TRUE; +} + +int +_dbus_read_file(DBusFile *file, + DBusString *buffer, + int count) +{ + const int fd = file->FDATA; + int bytes_read; + int start; + char *data; + _dbus_assert (count >= 0); + + start = _dbus_string_get_length (buffer); + + if (!_dbus_string_lengthen (buffer, count)) + { + errno = ENOMEM; + return -1; + } + + data = _dbus_string_get_data_len (buffer, start, count); + + _dbus_assert (fd >= 0); + + _dbus_verbose ("read: count=%d fd=%d\n", count, fd); + bytes_read = read (fd, data, count); + + if (bytes_read == -1) + _dbus_verbose ("read: failed: %s\n", _dbus_strerror (errno)); + else + _dbus_verbose ("read: = %d\n", bytes_read); + + if (bytes_read < 0) + { + /* put length back (note that this doesn't actually realloc anything) */ + _dbus_string_set_length (buffer, start); + return -1; + } + else + { + /* put length back (doesn't actually realloc) */ + _dbus_string_set_length (buffer, start + bytes_read); + +#if 0 + + if (bytes_read > 0) + _dbus_verbose_bytes_of_string (buffer, start, bytes_read); +#endif + + return bytes_read; + } +} + +int +_dbus_write_file (DBusFile *file, + const DBusString *buffer, + int start, + int len) +{ + const int fd = file->FDATA; + const char *data; + int bytes_written; + + data = _dbus_string_get_const_data_len (buffer, start, len); + + _dbus_assert (fd >= 0); + + _dbus_verbose ("write: len=%d fd=%d\n", len, fd); + bytes_written = write (fd, data, len); + + if (bytes_written == -1) + _dbus_verbose ("write: failed: %s\n", _dbus_strerror (errno)); + else + _dbus_verbose ("write: = %d\n", bytes_written); + +#if 0 + + if (bytes_written > 0) + _dbus_verbose_bytes_of_string (buffer, start, bytes_written); +#endif + + return bytes_written; +} + +dbus_bool_t +_dbus_is_valid_file (DBusFile* file) +{ + return file->FDATA >= 0; +} + +dbus_bool_t _dbus_fstat (DBusFile *file, + struct stat *sb) +{ + return fstat(file->FDATA, sb) >= 0; +} + +int +_dbus_write_pipe (DBusPipe pipe, + const DBusString *buffer, + int start, + int len) +{ + DBusFile file; + file.FDATA = pipe; + return _dbus_write_file(&file, buffer, start, len); +} + +int +_dbus_read_pipe(DBusPipe pipe, + DBusString *buffer, + int count) +{ + DBusFile file; + file.FDATA = pipe; + return _dbus_read_file(&file, buffer, count); +} + +#undef FDATA + +/** + * Socket interface + * + */ + +static DBusSocket *win_fds = NULL; +static int win_n_fds = 0; // is this the size? rename to win_fds_size? # + +#if 0 +#define TO_HANDLE(n) ((n)^win32_encap_randomizer) +#define FROM_HANDLE(n) ((n)^win32_encap_randomizer) +#else +#define TO_HANDLE(n) ((n)+0x10000000) +#define FROM_HANDLE(n) ((n)-0x10000000) +#define IS_HANDLE(n) ((n)&0x10000000) +#endif + + +static +void +_dbus_win_deallocate_fd (int fd) +{ + _DBUS_LOCK (win_fds); + win_fds[FROM_HANDLE (fd)].is_used = 0; + _DBUS_UNLOCK (win_fds); +} + +static +int +_dbus_win_allocate_fd (void) +{ + int i; + + _DBUS_LOCK (win_fds); + + if (win_fds == NULL) + { +#ifdef _DBUS_WIN_USE_RANDOMIZER + DBusString random; +#endif + + win_n_fds = 16; + /* Use malloc to avoid memory leak failure in dbus-test */ + win_fds = malloc (win_n_fds * sizeof (*win_fds)); + + _dbus_assert (win_fds != NULL); + + for (i = 0; i < win_n_fds; i++) + win_fds[i].is_used = 0; + +#ifdef _DBUS_WIN_USE_RANDOMIZER + + _dbus_string_init (&random); + _dbus_generate_random_bytes (&random, sizeof (int)); + memmove (&win_encap_randomizer, _dbus_string_get_const_data (&random), sizeof (int)); + win_encap_randomizer &= 0xFF; + _dbus_string_free (&random); +#endif + + } + + for (i = 0; i < win_n_fds && win_fds[i].is_used != 0; i++) + ; + + if (i == win_n_fds) + { + int oldn = win_n_fds; + int j; + + win_n_fds += 16; + win_fds = realloc (win_fds, win_n_fds * sizeof (*win_fds)); + + _dbus_assert (win_fds != NULL); + + for (j = oldn; j < win_n_fds; j++) + win_fds[i].is_used = 0; + } + + memset(&win_fds[i], 0, sizeof(win_fds[i])); + + win_fds[i].is_used = 1; + win_fds[i].fd = -1; + win_fds[i].port_file_fd = -1; + win_fds[i].close_on_exec = FALSE; + win_fds[i].non_blocking = FALSE; + + _DBUS_UNLOCK (win_fds); + + return i; +} + +static +int +_dbus_create_handle_from_socket (int s) +{ + int i; + int handle = -1; + + // check: parameter must be a valid value + _dbus_assert(s != -1); + _dbus_assert(!IS_HANDLE(s)); + + // get index of a new position in the map + i = _dbus_win_allocate_fd (); + + // fill new posiiton in the map: value->index + win_fds[i].fd = s; + win_fds[i].is_used = 1; + + // create handle from the index: index->handle + handle = TO_HANDLE (i); + + _dbus_verbose ("_dbus_create_handle_from_value, value: %d, handle: %d\n", s, handle); + + return handle; +} + +int +_dbus_socket_to_handle (DBusSocket *s) +{ + int i; + int handle = -1; + + // check: parameter must be a valid socket + _dbus_assert(s != NULL); + _dbus_assert(s->fd != -1); + _dbus_assert(!IS_HANDLE(s->fd)); + + _DBUS_LOCK (win_fds); + + // at the first call there is no win_fds + // will be constructed _dbus_create_handle_from_socket + // because handle = -1 + if (win_fds != NULL) + { + // search for the value in the map + // find the index of the value: value->index + for (i = 0; i < win_n_fds; i++) + if (win_fds[i].is_used == 1 && win_fds[i].fd == s->fd) + { + // create handle from the index: index->handle + handle = TO_HANDLE (i); + break; + } + } + _DBUS_UNLOCK (win_fds); + + + if (handle == -1) + { + handle = _dbus_create_handle_from_socket(s->fd); + } + + _dbus_assert(handle != -1); + + return handle; +} + +static +void +_dbus_handle_to_socket_unlocked (int handle, + DBusSocket **ptr) +{ + int i; + + // check: parameter must be a valid handle + _dbus_assert(handle != -1); + _dbus_assert(IS_HANDLE(handle)); + _dbus_assert(ptr != NULL); + + // map from handle to index: handle->index + i = FROM_HANDLE (handle); + + _dbus_assert (win_fds != NULL); + _dbus_assert (i >= 0 && i < win_n_fds); + + // check for if fd is valid + _dbus_assert (win_fds[i].is_used == 1); + + // get socket from index: index->socket + *ptr = &win_fds[i]; + + _dbus_verbose ("_dbus_socket_to_handle_unlocked: socket=%d, handle=%d, index=%d\n", (*ptr)->fd, handle, i); +} + +void +_dbus_handle_to_socket (int handle, + DBusSocket **ptr) +{ + _dbus_lock_sockets(); + _dbus_handle_to_socket_unlocked (handle, ptr); + _dbus_unlock_sockets(); +} + +#undef TO_HANDLE +#undef IS_HANDLE +#undef FROM_HANDLE +#define FROM_HANDLE(n) 1==DBUS_WIN_DONT_USE__FROM_HANDLE__DIRECTLY +#define win_fds 1==DBUS_WIN_DONT_USE_win_fds_DIRECTLY + + + + +/** + * Thin wrapper around the read() system call that appends + * the data it reads to the DBusString buffer. It appends + * up to the given count, and returns the same value + * and same errno as read(). The only exception is that + * _dbus_read() handles EINTR for you. _dbus_read() can + * return ENOMEM, even though regular UNIX read doesn't. + * + * @param fd the file descriptor to read from + * @param buffer the buffer to append data to + * @param count the amount of data to read + * @returns the number of bytes read or -1 + */ +int +_dbus_read_socket (int handle, + DBusString *buffer, + int count) +{ + DBusSocket *s; + int bytes_read; + int start; + char *data; + + _dbus_assert (count >= 0); + + start = _dbus_string_get_length (buffer); + + if (!_dbus_string_lengthen (buffer, count)) + { + errno = ENOMEM; + return -1; + } + + data = _dbus_string_get_data_len (buffer, start, count); + + _dbus_handle_to_socket(handle, &s); + + if(s->is_used) + { + _dbus_verbose ("recv: count=%d socket=%d\n", count, s->fd); + bytes_read = recv (s->fd, data, count, 0); + if (bytes_read == SOCKET_ERROR) + { + DBUS_SOCKET_SET_ERRNO(); + _dbus_verbose ("recv: failed: %s\n", _dbus_strerror (errno)); + bytes_read = -1; + } + else + _dbus_verbose ("recv: = %d\n", bytes_read); + } + else + { + _dbus_assert_not_reached ("no valid socket"); + } + + if (bytes_read < 0) + { + /* put length back (note that this doesn't actually realloc anything) */ + _dbus_string_set_length (buffer, start); + return -1; + } + else + { + /* put length back (doesn't actually realloc) */ + _dbus_string_set_length (buffer, start + bytes_read); + +#if 0 + + if (bytes_read > 0) + _dbus_verbose_bytes_of_string (buffer, start, bytes_read); +#endif + + return bytes_read; + } +} + +/** + * Thin wrapper around the write() system call that writes a part of a + * DBusString and handles EINTR for you. + * + * @param fd the file descriptor to write + * @param buffer the buffer to write data from + * @param start the first byte in the buffer to write + * @param len the number of bytes to try to write + * @returns the number of bytes written or -1 on error + */ +int +_dbus_write_socket (int handle, + const DBusString *buffer, + int start, + int len) +{ + DBusSocket *s; + int is_used; + const char *data; + int bytes_written; + + data = _dbus_string_get_const_data_len (buffer, start, len); + + _dbus_handle_to_socket(handle, &s); + + if (s->is_used) + { + _dbus_verbose ("send: len=%d socket=%d\n", len, s->fd); + bytes_written = send (s->fd, data, len, 0); + if (bytes_written == SOCKET_ERROR) + { + DBUS_SOCKET_SET_ERRNO(); + _dbus_verbose ("send: failed: %s\n", _dbus_strerror (errno)); + bytes_written = -1; + } + else + _dbus_verbose ("send: = %d\n", bytes_written); + } + else + { + _dbus_assert_not_reached ("unhandled fd type"); + } + +#if 0 + if (bytes_written > 0) + _dbus_verbose_bytes_of_string (buffer, start, bytes_written); +#endif + + return bytes_written; +} + + +/** + * Closes a file descriptor. + * + * @param fd the file descriptor + * @param error error object + * @returns #FALSE if error set + */ +dbus_bool_t +_dbus_close_socket (int handle, + DBusError *error) +{ + DBusSocket *s; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + _dbus_lock_sockets(); + + _dbus_handle_to_socket_unlocked (handle, &s); + + + if (s->is_used) + { + if (s->port_file_fd >= 0) + { + _chsize (s->port_file_fd, 0); + close (s->port_file_fd); + s->port_file_fd = -1; + unlink (_dbus_string_get_const_data (&s->port_file)); + free ((char *) _dbus_string_get_const_data (&s->port_file)); + } + + if (closesocket (s->fd) == SOCKET_ERROR) + { + DBUS_SOCKET_SET_ERRNO (); + dbus_set_error (error, _dbus_error_from_errno (errno), + "Could not close socket: socket=%d, handle=%d, %s", + s->fd, handle, _dbus_strerror (errno)); + _dbus_unlock_sockets(); + return FALSE; + } + _dbus_verbose ("_dbus_close_socket: socket=%d, handle=%d\n", + s->fd, handle); + } + else + { + _dbus_assert_not_reached ("unhandled fd type"); + } + + _dbus_unlock_sockets(); + + _dbus_win_deallocate_fd (handle); + + return TRUE; + +} + +/** + * Sets the file descriptor to be close + * on exec. Should be called for all file + * descriptors in D-Bus code. + * + * @param fd the file descriptor + */ +void +_dbus_fd_set_close_on_exec (int handle) +{ + DBusSocket *s; + if (handle < 0) + return; + + _dbus_lock_sockets(); + + _dbus_handle_to_socket_unlocked (handle, &s); + s->close_on_exec = TRUE; + + _dbus_unlock_sockets(); +} + +/** + * Sets a file descriptor to be nonblocking. + * + * @param fd the file descriptor. + * @param error address of error location. + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_set_fd_nonblocking (int handle, + DBusError *error) +{ + DBusSocket *s; + u_long one = 1; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + _dbus_lock_sockets(); + + _dbus_handle_to_socket_unlocked(handle, &s); + + if (s->is_used) + { + if (ioctlsocket (s->fd, FIONBIO, &one) == SOCKET_ERROR) + { + dbus_set_error (error, _dbus_error_from_errno (WSAGetLastError ()), + "Failed to set socket %d:%d to nonblocking: %s", s->fd, + _dbus_strerror (WSAGetLastError ())); + _dbus_unlock_sockets(); + return FALSE; + } + } + else + { + _dbus_assert_not_reached ("unhandled fd type"); + } + + _dbus_unlock_sockets(); + + return TRUE; +} + + +/** + * Like _dbus_write() but will use writev() if possible + * to write both buffers in sequence. The return value + * is the number of bytes written in the first buffer, + * plus the number written in the second. If the first + * buffer is written successfully and an error occurs + * writing the second, the number of bytes in the first + * is returned (i.e. the error is ignored), on systems that + * don't have writev. Handles EINTR for you. + * The second buffer may be #NULL. + * + * @param fd the file descriptor + * @param buffer1 first buffer + * @param start1 first byte to write in first buffer + * @param len1 number of bytes to write from first buffer + * @param buffer2 second buffer, or #NULL + * @param start2 first byte to write in second buffer + * @param len2 number of bytes to write in second buffer + * @returns total bytes written from both buffers, or -1 on error + */ +int +_dbus_write_socket_two (int handle, + const DBusString *buffer1, + int start1, + int len1, + const DBusString *buffer2, + int start2, + int len2) +{ + DBusSocket *s; + WSABUF vectors[2]; + const char *data1; + const char *data2; + int rc; + DWORD bytes_written; + int ret1; + + _dbus_assert (buffer1 != NULL); + _dbus_assert (start1 >= 0); + _dbus_assert (start2 >= 0); + _dbus_assert (len1 >= 0); + _dbus_assert (len2 >= 0); + + _dbus_handle_to_socket(handle, &s); + + data1 = _dbus_string_get_const_data_len (buffer1, start1, len1); + + if (buffer2 != NULL) + data2 = _dbus_string_get_const_data_len (buffer2, start2, len2); + else + { + data2 = NULL; + start2 = 0; + len2 = 0; + } + + if (s->is_used) + { + vectors[0].buf = (char*) data1; + vectors[0].len = len1; + vectors[1].buf = (char*) data2; + vectors[1].len = len2; + + _dbus_verbose ("WSASend: len1+2=%d+%d socket=%d\n", len1, len2, s->fd); + rc = WSASend (s->fd, vectors, data2 ? 2 : 1, &bytes_written, + 0, NULL, NULL); + if (rc < 0) + { + DBUS_SOCKET_SET_ERRNO (); + _dbus_verbose ("WSASend: failed: %s\n", _dbus_strerror (errno)); + bytes_written = -1; + } + else + _dbus_verbose ("WSASend: = %ld\n", bytes_written); + return bytes_written; + } + else + { + _dbus_assert_not_reached ("unhandled fd type"); + } + return 0; +} + +/** + * @def _DBUS_MAX_SUN_PATH_LENGTH + * + * Maximum length of the path to a UNIX domain socket, + * sockaddr_un::sun_path member. POSIX requires that all systems + * support at least 100 bytes here, including the nul termination. + * We use 99 for the max value to allow for the nul. + * + * We could probably also do sizeof (addr.sun_path) + * but this way we are the same on all platforms + * which is probably a good idea. + */ + +/** + * Creates a socket and connects it to the UNIX domain socket at the + * given path. The connection fd is returned, and is set up as + * nonblocking. + * + * On Windows there are no UNIX domain sockets. Instead, connects to a + * localhost-bound TCP socket, whose port number is stored in a file + * at the given path. + * + * Uses abstract sockets instead of filesystem-linked sockets if + * requested (it's possible only on Linux; see "man 7 unix" on Linux). + * On non-Linux abstract socket usage always fails. + * + * @param path the path to UNIX domain socket + * @param abstract #TRUE to use abstract namespace + * @param error return location for error code + * @returns connection file descriptor or -1 on error + */ +int +_dbus_connect_unix_socket (const char *path, + dbus_bool_t abstract, + DBusError *error) +{ +#ifdef DBUS_WINCE + return -1; +#else + int fd, n, port; + char buf[7]; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + _dbus_verbose ("connecting to pseudo-unix socket at %s\n", + path); + + if (abstract) + { + dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, + "Implementation does not support abstract socket namespace\n"); + return -1; + } + + fd = _sopen (path, O_RDONLY, SH_DENYNO); + + if (fd == -1) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to open file %s: %s", + path, _dbus_strerror (errno)); + return -1; + } + + n = read (fd, buf, sizeof (buf) - 1); + close (fd); + + if (n == 0) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Failed to read port number from file %s", + path); + return -1; + } + + buf[n] = '\0'; + port = atoi (buf); + + if (port <= 0 || port > 0xFFFF) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Invalid port numer in file %s", + path); + return -1; + } + + return _dbus_connect_tcp_socket (NULL, port, error); +#endif //DBUS_WINCE + +} + +/** + * Creates a socket and binds it to the given path, + * then listens on the socket. The socket is + * set to be nonblocking. + * + * Uses abstract sockets instead of filesystem-linked + * sockets if requested (it's possible only on Linux; + * see "man 7 unix" on Linux). + * On non-Linux abstract socket usage always fails. + * + * @param path the socket name + * @param abstract #TRUE to use abstract namespace + * @param error return location for errors + * @returns the listening file descriptor or -1 on error + */ +int +_dbus_listen_unix_socket (const char *path, + dbus_bool_t abstract, + DBusError *error) +{ +#ifdef DBUS_WINCE + return -1; +#else + DBusSocket *s; + int listen_handle; + struct sockaddr sa; + int addr_len; + int filefd; + int n, l; + DBusString portstr; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + _dbus_verbose ("listening on pseudo-unix socket at %s\n", + path); + + if (abstract) + { + dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, + "Implementation does not support abstract socket namespace\n"); + return -1; + } + + listen_handle = _dbus_listen_tcp_socket (NULL, 0, error); + + if (listen_handle == -1) + return -1; + + _dbus_handle_to_socket(listen_handle, &s); + + addr_len = sizeof (sa); + if (getsockname (s->fd, &sa, &addr_len) == SOCKET_ERROR) + { + DBUS_SOCKET_SET_ERRNO (); + dbus_set_error (error, _dbus_error_from_errno (errno), + "getsockname failed: %s", + _dbus_strerror (errno)); + _dbus_close_socket (listen_handle, NULL); + return -1; + } + + _dbus_assert (((struct sockaddr_in*) &sa)->sin_family == AF_INET); + + filefd = _sopen (path, O_CREAT|O_WRONLY|_O_SHORT_LIVED, SH_DENYWR, 0666); + + if (filefd == -1) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to create pseudo-unix socket port number file %s: %s", + path, _dbus_strerror (errno)); + _dbus_close_socket (listen_handle, NULL); + return -1; + } + + _dbus_lock_sockets(); + _dbus_handle_to_socket_unlocked(listen_handle, &s); + s->port_file_fd = filefd; + _dbus_unlock_sockets(); + + /* Use strdup() to avoid memory leak in dbus-test */ + path = strdup (path); + if (!path) + { + _DBUS_SET_OOM (error); + _dbus_close_socket (listen_handle, NULL); + return -1; + } + + _dbus_string_init_const (&s->port_file, path); + + if (!_dbus_string_init (&portstr)) + { + _DBUS_SET_OOM (error); + _dbus_close_socket (listen_handle, NULL); + return -1; + } + + if (!_dbus_string_append_int (&portstr, ntohs (((struct sockaddr_in*) &sa)->sin_port))) + { + _DBUS_SET_OOM (error); + _dbus_close_socket (listen_handle, NULL); + return -1; + } + + l = _dbus_string_get_length (&portstr); + n = write (filefd, _dbus_string_get_const_data (&portstr), l); + _dbus_string_free (&portstr); + + if (n == -1) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to write port number to file %s: %s", + path, _dbus_strerror (errno)); + _dbus_close_socket (listen_handle, NULL); + return -1; + } + else if (n < l) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to write port number to file %s", + path); + _dbus_close_socket (listen_handle, NULL); + return -1; + } + + return listen_handle; +#endif //DBUS_WINCE +} + +#if 0 + +/** + * Opens the client side of a Windows named pipe. The connection D-BUS + * file descriptor index is returned. It is set up as nonblocking. + * + * @param path the path to named pipe socket + * @param error return location for error code + * @returns connection D-BUS file descriptor or -1 on error + */ +int +_dbus_connect_named_pipe (const char *path, + DBusError *error) +{ + _dbus_assert_not_reached ("not implemented"); +} + +#endif + + +dbus_bool_t +_dbus_account_to_win_sid (const wchar_t *waccount, + void **ppsid, + DBusError *error) +{ + dbus_bool_t retval = FALSE; + DWORD sid_length, wdomain_length; + SID_NAME_USE use; + wchar_t *wdomain; + + *ppsid = NULL; + + sid_length = 0; + wdomain_length = 0; + if (!LookupAccountNameW (NULL, waccount, NULL, &sid_length, + NULL, &wdomain_length, &use) + && GetLastError () != ERROR_INSUFFICIENT_BUFFER) + { + _dbus_win_set_error_from_win_error (error, GetLastError ()); + return FALSE; + } + + *ppsid = dbus_malloc (sid_length); + if (!*ppsid) + { + _DBUS_SET_OOM (error); + return FALSE; + } + + wdomain = dbus_new (wchar_t, wdomain_length); + if (!wdomain) + { + _DBUS_SET_OOM (error); + goto out1; + } + + if (!LookupAccountNameW (NULL, waccount, (PSID) *ppsid, &sid_length, + wdomain, &wdomain_length, &use)) + { + _dbus_win_set_error_from_win_error (error, GetLastError ()); + goto out2; + } + + if (!IsValidSid ((PSID) *ppsid)) + { + dbus_set_error_const (error, DBUS_ERROR_FAILED, "Invalid SID"); + goto out2; + } + + retval = TRUE; + +out2: + dbus_free (wdomain); +out1: + if (!retval) + { + dbus_free (*ppsid); + *ppsid = NULL; + } + + return retval; +} + + +dbus_bool_t +fill_win_user_info_name_and_groups (wchar_t *wname, + wchar_t *wdomain, + DBusUserInfo *info, + DBusError *error) +{ +#ifdef DBUS_WINCE + return TRUE; +#else + dbus_bool_t retval = FALSE; + char *name, *domain; + LPLOCALGROUP_USERS_INFO_0 local_groups = NULL; + LPGROUP_USERS_INFO_0 global_groups = NULL; + DWORD nread, ntotal; + + name = _dbus_win_utf16_to_utf8 (wname, error); + if (!name) + return FALSE; + + domain = _dbus_win_utf16_to_utf8 (wdomain, error); + if (!domain) + goto out0; + + info->username = dbus_malloc (strlen (domain) + 1 + strlen (name) + 1); + if (!info->username) + { + _DBUS_SET_OOM (error); + goto out1; + } + + strcpy (info->username, domain); + strcat (info->username, "\\"); + strcat (info->username, name); + + info->n_group_ids = 0; + if (NetUserGetLocalGroups (NULL, wname, 0, LG_INCLUDE_INDIRECT, + (LPBYTE *) &local_groups, MAX_PREFERRED_LENGTH, + &nread, &ntotal) == NERR_Success) + { + DWORD i; + int n; + + info->group_ids = dbus_new (dbus_gid_t, nread); + if (!info->group_ids) + { + _DBUS_SET_OOM (error); + goto out3; + } + + for (i = n = 0; i < nread; i++) + { + PSID group_sid; + if (_dbus_account_to_win_sid (local_groups[i].lgrui0_name, + &group_sid, error)) + { + info->group_ids[n++] = _dbus_win_sid_to_uid_t (group_sid); + dbus_free (group_sid); + } + } + info->n_group_ids = n; + } + + if (NetUserGetGroups (NULL, wname, 0, + (LPBYTE *) &global_groups, MAX_PREFERRED_LENGTH, + &nread, &ntotal) == NERR_Success) + { + DWORD i; + int n = info->n_group_ids; + + info->group_ids = dbus_realloc (info->group_ids, (n + nread) * sizeof (dbus_gid_t)); + if (!info->group_ids) + { + _DBUS_SET_OOM (error); + goto out4; + } + + for (i = 0; i < nread; i++) + { + PSID group_sid; + if (_dbus_account_to_win_sid (global_groups[i].grui0_name, + &group_sid, error)) + { + info->group_ids[n++] = _dbus_win_sid_to_uid_t (group_sid); + dbus_free (group_sid); + } + } + info->n_group_ids = n; + } + + if (info->n_group_ids > 0) + { + /* FIXME: find out actual primary group */ + info->primary_gid = info->group_ids[0]; + } + else + { + info->group_ids = dbus_new (dbus_gid_t, 1); + info->n_group_ids = 1; + info->group_ids[0] = DBUS_GID_UNSET; + info->primary_gid = DBUS_GID_UNSET; + } + + retval = TRUE; + +out4: + if (global_groups != NULL) + NetApiBufferFree (global_groups); +out3: + if (local_groups != NULL) + NetApiBufferFree (local_groups); +out1: + dbus_free (domain); +out0: + dbus_free (name); + + return retval; +#endif //DBUS_WINCE +} + +dbus_bool_t +fill_win_user_info_homedir (wchar_t *wname, + wchar_t *wdomain, + DBusUserInfo *info, + DBusError *error) +{ +#ifdef DBUS_WINCE + //TODO + return TRUE; +#else + dbus_bool_t retval = FALSE; + USER_INFO_1 *user_info = NULL; + wchar_t wcomputername[MAX_COMPUTERNAME_LENGTH + 1]; + DWORD wcomputername_length = MAX_COMPUTERNAME_LENGTH + 1; + dbus_bool_t local_computer; + wchar_t *dc = NULL; + NET_API_STATUS ret = 0; + + /* If the domain is this computer's name, assume it's a local user. + * Otherwise look up a DC for the domain, and ask it. + */ + + GetComputerNameW (wcomputername, &wcomputername_length); + local_computer = (wcsicmp (wcomputername, wdomain) == 0); + + if (!local_computer) + { + ret = NetGetAnyDCName (NULL, wdomain, (LPBYTE *) &dc); + if (ret != NERR_Success) + { + info->homedir = _dbus_strdup ("\\"); + _dbus_warn("NetGetAnyDCName() failed with errorcode %d '%s'\n",ret,_dbus_lm_strerror(ret)); + return TRUE; + } + } + + /* No way to find out the profile of another user, let's try the + * "home directory" from NetUserGetInfo's USER_INFO_1. + */ + ret = NetUserGetInfo (dc, wname, 1, (LPBYTE *) &user_info); + if (ret == NERR_Success ) + if(user_info->usri1_home_dir != NULL && + user_info->usri1_home_dir != (LPWSTR)0xfeeefeee && /* freed memory http://www.gamedev.net/community/forums/topic.asp?topic_id=158402 */ + user_info->usri1_home_dir[0] != '\0') + { + info->homedir = _dbus_win_utf16_to_utf8 (user_info->usri1_home_dir, error); + if (!info->homedir) + goto out1; + } + else + { + _dbus_verbose("NetUserGetInfo() returned no home dir entry\n"); + /* Not set, so use something random. */ + info->homedir = _dbus_strdup ("\\"); + } + else + { + char *dc_string = _dbus_win_utf16_to_utf8(dc,error); + _dbus_warn("NetUserGetInfo() failed with errorcode %d '%s', %s\n",ret,_dbus_lm_strerror(ret),dc_string); + dbus_free(dc_string); + /* Not set, so use something random. */ + info->homedir = _dbus_strdup ("\\"); + } + + retval = TRUE; + +out1: + if (dc != NULL) + NetApiBufferFree (dc); + if (user_info != NULL) + NetApiBufferFree (user_info); + + return retval; +#endif //DBUS_WINCE +} + +dbus_bool_t +fill_win_user_info_from_name (wchar_t *wname, + DBusUserInfo *info, + DBusError *error) +{ +#ifdef DBUS_WINCE + return TRUE; + //TODO +#else + dbus_bool_t retval = FALSE; + PSID sid; + wchar_t *wdomain; + DWORD sid_length, wdomain_length; + SID_NAME_USE use; + + sid_length = 0; + wdomain_length = 0; + if (!LookupAccountNameW (NULL, wname, NULL, &sid_length, + NULL, &wdomain_length, &use) && + GetLastError () != ERROR_INSUFFICIENT_BUFFER) + { + _dbus_win_set_error_from_win_error (error, GetLastError ()); + return FALSE; + } + + sid = dbus_malloc (sid_length); + if (!sid) + { + _DBUS_SET_OOM (error); + return FALSE; + } + + wdomain = dbus_new (wchar_t, wdomain_length); + if (!wdomain) + { + _DBUS_SET_OOM (error); + goto out0; + } + + if (!LookupAccountNameW (NULL, wname, sid, &sid_length, + wdomain, &wdomain_length, &use)) + { + _dbus_win_set_error_from_win_error (error, GetLastError ()); + goto out1; + } + + if (!IsValidSid (sid)) + { + dbus_set_error_const (error, DBUS_ERROR_FAILED, "Invalid SID"); + goto out1; + } + + info->uid = _dbus_win_sid_to_uid_t (sid); + + if (!fill_win_user_info_name_and_groups (wname, wdomain, info, error)) + goto out1; + + if (!fill_win_user_info_homedir (wname, wdomain, info, error)) + goto out1; + + retval = TRUE; + +out1: + dbus_free (wdomain); +out0: + dbus_free (sid); + + return retval; +#endif //DBUS_WINCE +} + +dbus_bool_t +_dbus_win_sid_to_name_and_domain (dbus_uid_t uid, + wchar_t **wname, + wchar_t **wdomain, + DBusError *error) +{ +#ifdef DBUS_WINCE + return TRUE; + //TODO +#else + PSID sid; + DWORD wname_length, wdomain_length; + SID_NAME_USE use; + + if (!_dbus_uid_t_to_win_sid (uid, &sid)) + { + _dbus_win_set_error_from_win_error (error, GetLastError ()); + return FALSE; + } + + wname_length = 0; + wdomain_length = 0; + if (!LookupAccountSidW (NULL, sid, NULL, &wname_length, + NULL, &wdomain_length, &use) && + GetLastError () != ERROR_INSUFFICIENT_BUFFER) + { + _dbus_win_set_error_from_win_error (error, GetLastError ()); + goto out0; + } + + *wname = dbus_new (wchar_t, wname_length); + if (!*wname) + { + _DBUS_SET_OOM (error); + goto out0; + } + + *wdomain = dbus_new (wchar_t, wdomain_length); + if (!*wdomain) + { + _DBUS_SET_OOM (error); + goto out1; + } + + if (!LookupAccountSidW (NULL, sid, *wname, &wname_length, + *wdomain, &wdomain_length, &use)) + { + _dbus_win_set_error_from_win_error (error, GetLastError ()); + goto out2; + } + + return TRUE; + +out2: + dbus_free (*wdomain); + *wdomain = NULL; +out1: + dbus_free (*wname); + *wname = NULL; +out0: + LocalFree (sid); + + return FALSE; +#endif //DBUS_WINCE +} + +dbus_bool_t +fill_win_user_info_from_uid (dbus_uid_t uid, + DBusUserInfo *info, + DBusError *error) +{ +#ifdef DBUS_WINCE + return TRUE; + //TODO +#else + PSID sid; + dbus_bool_t retval = FALSE; + wchar_t *wname, *wdomain; + + info->uid = uid; + + if (!_dbus_win_sid_to_name_and_domain (uid, &wname, &wdomain, error)) + { + _dbus_verbose("%s after _dbus_win_sid_to_name_and_domain\n",__FUNCTION__); + return FALSE; + } + + if (!fill_win_user_info_name_and_groups (wname, wdomain, info, error)) + { + _dbus_verbose("%s after fill_win_user_info_name_and_groups\n",__FUNCTION__); + goto out0; + } + + + if (!fill_win_user_info_homedir (wname, wdomain, info, error)) + { + _dbus_verbose("%s after fill_win_user_info_homedir\n",__FUNCTION__); + goto out0; + } + + retval = TRUE; + +out0: + dbus_free (wdomain); + dbus_free (wname); + + return retval; +#endif //DBUS_WINCE +} + + + + +void +_dbus_win_startup_winsock (void) +{ + /* Straight from MSDN, deuglified */ + + static dbus_bool_t beenhere = FALSE; + + WORD wVersionRequested; + WSADATA wsaData; + int err; + + if (beenhere) + return; + + wVersionRequested = MAKEWORD (2, 0); + + err = WSAStartup (wVersionRequested, &wsaData); + if (err != 0) + { + _dbus_assert_not_reached ("Could not initialize WinSock"); + _dbus_abort (); + } + + /* Confirm that the WinSock DLL supports 2.0. Note that if the DLL + * supports versions greater than 2.0 in addition to 2.0, it will + * still return 2.0 in wVersion since that is the version we + * requested. + */ + if (LOBYTE (wsaData.wVersion) != 2 || + HIBYTE (wsaData.wVersion) != 0) + { + _dbus_assert_not_reached ("No usable WinSock found"); + _dbus_abort (); + } + + beenhere = TRUE; +} + + + + + + + + + +/************************************************************************ + + UTF / string code + + ************************************************************************/ + +/** + * Measure the message length without terminating nul + */ +int _dbus_printf_string_upper_bound (const char *format, + va_list args) +{ + /* MSVCRT's vsnprintf semantics are a bit different */ + /* The C library source in the Platform SDK indicates that this + * would work, but alas, it doesn't. At least not on Windows + * 2000. Presumably those sources correspond to the C library on + * some newer or even future Windows version. + * + len = _vsnprintf (NULL, _DBUS_INT_MAX, format, args); + */ + char p[1024]; + int len; + len = vsnprintf (p, sizeof(p)-1, format, args); + if (len == -1) // try again + { + char *p; + p = malloc (strlen(format)*3); + len = vsnprintf (p, sizeof(p)-1, format, args); + free(p); + } + return len; +} + + +/** + * Returns the UTF-16 form of a UTF-8 string. The result should be + * freed with dbus_free() when no longer needed. + * + * @param str the UTF-8 string + * @param error return location for error code + */ +wchar_t * +_dbus_win_utf8_to_utf16 (const char *str, + DBusError *error) +{ + DBusString s; + int n; + wchar_t *retval; + + _dbus_string_init_const (&s, str); + + if (!_dbus_string_validate_utf8 (&s, 0, _dbus_string_get_length (&s))) + { + dbus_set_error_const (error, DBUS_ERROR_FAILED, "Invalid UTF-8"); + return NULL; + } + + n = MultiByteToWideChar (CP_UTF8, 0, str, -1, NULL, 0); + + if (n == 0) + { + _dbus_win_set_error_from_win_error (error, GetLastError ()); + return NULL; + } + + retval = dbus_new (wchar_t, n); + + if (!retval) + { + _DBUS_SET_OOM (error); + return NULL; + } + + if (MultiByteToWideChar (CP_UTF8, 0, str, -1, retval, n) != n) + { + dbus_free (retval); + dbus_set_error_const (error, DBUS_ERROR_FAILED, "MultiByteToWideChar inconsistency"); + return NULL; + } + + return retval; +} + +/** + * Returns the UTF-8 form of a UTF-16 string. The result should be + * freed with dbus_free() when no longer needed. + * + * @param str the UTF-16 string + * @param error return location for error code + */ +char * +_dbus_win_utf16_to_utf8 (const wchar_t *str, + DBusError *error) +{ + int n; + char *retval; + + n = WideCharToMultiByte (CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL); + + if (n == 0) + { + _dbus_win_set_error_from_win_error (error, GetLastError ()); + return NULL; + } + + retval = dbus_malloc (n); + + if (!retval) + { + _DBUS_SET_OOM (error); + return NULL; + } + + if (WideCharToMultiByte (CP_UTF8, 0, str, -1, retval, n, NULL, NULL) != n) + { + dbus_free (retval); + dbus_set_error_const (error, DBUS_ERROR_FAILED, "WideCharToMultiByte inconsistency"); + return NULL; + } + + return retval; +} + + + + + + +/************************************************************************ + + uid ... <-> win sid functions + + ************************************************************************/ + +dbus_bool_t +_dbus_win_account_to_sid (const wchar_t *waccount, + void **ppsid, + DBusError *error) +{ + dbus_bool_t retval = FALSE; + DWORD sid_length, wdomain_length; + SID_NAME_USE use; + wchar_t *wdomain; + + *ppsid = NULL; + + sid_length = 0; + wdomain_length = 0; + if (!LookupAccountNameW (NULL, waccount, NULL, &sid_length, + NULL, &wdomain_length, &use) && + GetLastError () != ERROR_INSUFFICIENT_BUFFER) + { + _dbus_win_set_error_from_win_error (error, GetLastError ()); + return FALSE; + } + + *ppsid = dbus_malloc (sid_length); + if (!*ppsid) + { + _DBUS_SET_OOM (error); + return FALSE; + } + + wdomain = dbus_new (wchar_t, wdomain_length); + if (!wdomain) + { + _DBUS_SET_OOM (error); + goto out1; + } + + if (!LookupAccountNameW (NULL, waccount, (PSID) *ppsid, &sid_length, + wdomain, &wdomain_length, &use)) + { + _dbus_win_set_error_from_win_error (error, GetLastError ()); + goto out2; + } + + if (!IsValidSid ((PSID) *ppsid)) + { + dbus_set_error_const (error, DBUS_ERROR_FAILED, "Invalid SID"); + goto out2; + } + + retval = TRUE; + +out2: + dbus_free (wdomain); +out1: + if (!retval) + { + dbus_free (*ppsid); + *ppsid = NULL; + } + + return retval; +} + +static void +_sid_atom_cache_shutdown (void *unused) +{ + DBusHashIter iter; + _DBUS_LOCK (sid_atom_cache); + _dbus_hash_iter_init (sid_atom_cache, &iter); + while (_dbus_hash_iter_next (&iter)) + { + ATOM atom; + atom = (ATOM) _dbus_hash_iter_get_value (&iter); + GlobalDeleteAtom(atom); + _dbus_hash_iter_remove_entry(&iter); + } + _DBUS_UNLOCK (sid_atom_cache); + _dbus_hash_table_unref (sid_atom_cache); + sid_atom_cache = NULL; +} + +/** + * Returns the 2-way associated dbus_uid_t form a SID. + * + * @param psid pointer to the SID + */ +dbus_uid_t +_dbus_win_sid_to_uid_t (PSID psid) +{ + dbus_uid_t uid; + dbus_uid_t olduid; + char *string; + ATOM atom; + + if (!IsValidSid (psid)) + { + _dbus_verbose("%s invalid sid\n",__FUNCTION__); + return DBUS_UID_UNSET; + } + if (!ConvertSidToStringSidA (psid, &string)) + { + _dbus_verbose("%s invalid sid\n",__FUNCTION__); + return DBUS_UID_UNSET; + } + + atom = GlobalAddAtom(string); + + if (atom == 0) + { + _dbus_verbose("%s GlobalAddAtom failed\n",__FUNCTION__); + LocalFree (string); + return DBUS_UID_UNSET; + } + + _DBUS_LOCK (sid_atom_cache); + + if (sid_atom_cache == NULL) + { + sid_atom_cache = _dbus_hash_table_new (DBUS_HASH_ULONG, NULL, NULL); + _dbus_register_shutdown_func (_sid_atom_cache_shutdown, NULL); + } + + uid = atom; + olduid = (dbus_uid_t) _dbus_hash_table_lookup_ulong (sid_atom_cache, uid); + + if (olduid) + { + _dbus_verbose("%s sid with id %i found in cache\n",__FUNCTION__, olduid); + uid = olduid; + } + else + { + _dbus_hash_table_insert_ulong (sid_atom_cache, uid, (void*) uid); + _dbus_verbose("%s sid %s added with uid %i to cache\n",__FUNCTION__, string, uid); + } + + _DBUS_UNLOCK (sid_atom_cache); + + return uid; +} + +dbus_bool_t _dbus_uid_t_to_win_sid (dbus_uid_t uid, PSID *ppsid) +{ + void* atom; + char string[255]; + + atom = _dbus_hash_table_lookup_ulong (sid_atom_cache, uid); + if (atom == NULL) + { + _dbus_verbose("%s uid %i not found in cache\n",__FUNCTION__,uid); + return FALSE; + } + memset( string, '.', sizeof(string) ); + if (!GlobalGetAtomNameA( (ATOM) atom, string, 255 )) + { + _dbus_verbose("%s uid %i not found in cache\n",__FUNCTION__, uid); + return FALSE; + } + if (!ConvertStringSidToSidA(string, ppsid)) + { + _dbus_verbose("%s could not convert %s into sid \n",__FUNCTION__, string); + return FALSE; + } + _dbus_verbose("%s converted %s into sid \n",__FUNCTION__, string); + return TRUE; +} + + +/** @} end of sysdeps-win */ + + +/** Gets our UID + * @returns process UID + */ +dbus_uid_t +_dbus_getuid(void) +{ + dbus_uid_t retval = DBUS_UID_UNSET; + HANDLE process_token = NULL; + TOKEN_USER *token_user = NULL; + DWORD n; + + if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &process_token)) + _dbus_win_warn_win_error ("OpenProcessToken failed", GetLastError ()); + else if ((!GetTokenInformation (process_token, TokenUser, NULL, 0, &n) + && GetLastError () != ERROR_INSUFFICIENT_BUFFER) + || (token_user = alloca (n)) == NULL + || !GetTokenInformation (process_token, TokenUser, token_user, n, &n)) + _dbus_win_warn_win_error ("GetTokenInformation failed", GetLastError ()); + else + retval = _dbus_win_sid_to_uid_t (token_user->User.Sid); + + if (process_token != NULL) + CloseHandle (process_token); + + _dbus_verbose("_dbus_getuid() returns %d\n",retval); + return retval; +} + +#ifdef DBUS_BUILD_TESTS +/** Gets our GID + * @returns process GID + */ +dbus_gid_t +_dbus_getgid (void) +{ + dbus_gid_t retval = DBUS_GID_UNSET; + HANDLE process_token = NULL; + TOKEN_PRIMARY_GROUP *token_primary_group = NULL; + DWORD n; + + if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &process_token)) + _dbus_win_warn_win_error ("OpenProcessToken failed", GetLastError ()); + else if ((!GetTokenInformation (process_token, TokenPrimaryGroup, + NULL, 0, &n) && + GetLastError () != ERROR_INSUFFICIENT_BUFFER) || + (token_primary_group = alloca (n)) == NULL || + !GetTokenInformation (process_token, TokenPrimaryGroup, + token_primary_group, n, &n)) + _dbus_win_warn_win_error ("GetTokenInformation failed", GetLastError ()); + else + retval = _dbus_win_sid_to_uid_t (token_primary_group->PrimaryGroup); + + if (process_token != NULL) + CloseHandle (process_token); + + return retval; +} + +#if 0 +dbus_bool_t +_dbus_domain_test (const char *test_data_dir) +{ + if (!_dbus_test_oom_handling ("spawn_nonexistent", + check_spawn_nonexistent, + NULL)) + return FALSE; +} + +#endif + +#endif //DBUS_BUILD_TESTS + +/************************************************************************ + + pipes + + ************************************************************************/ + +/** + * Creates a full-duplex pipe (as in socketpair()). + * Sets both ends of the pipe nonblocking. + * + * @todo libdbus only uses this for the debug-pipe server, so in + * principle it could be in dbus-sysdeps-util.c, except that + * dbus-sysdeps-util.c isn't in libdbus when tests are enabled and the + * debug-pipe server is used. + * + * @param fd1 return location for one end + * @param fd2 return location for the other end + * @param blocking #TRUE if pipe should be blocking + * @param error error return + * @returns #FALSE on failure (if error is set) + */ +dbus_bool_t +_dbus_full_duplex_pipe (int *fd1, + int *fd2, + dbus_bool_t blocking, + DBusError *error) +{ + SOCKET temp, socket1 = -1, socket2 = -1; + struct sockaddr_in saddr; + int len; + u_long arg; + fd_set read_set, write_set; + struct timeval tv; + DBusSocket sock; + + + _dbus_win_startup_winsock (); + + temp = socket (AF_INET, SOCK_STREAM, 0); + if (temp == INVALID_SOCKET) + { + DBUS_SOCKET_SET_ERRNO (); + goto out0; + } + + arg = 1; + if (ioctlsocket (temp, FIONBIO, &arg) == SOCKET_ERROR) + { + DBUS_SOCKET_SET_ERRNO (); + goto out0; + } + + _DBUS_ZERO (saddr); + saddr.sin_family = AF_INET; + saddr.sin_port = 0; + saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + + if (bind (temp, (struct sockaddr *)&saddr, sizeof (saddr))) + { + DBUS_SOCKET_SET_ERRNO (); + goto out0; + } + + if (listen (temp, 1) == SOCKET_ERROR) + { + DBUS_SOCKET_SET_ERRNO (); + goto out0; + } + + len = sizeof (saddr); + if (getsockname (temp, (struct sockaddr *)&saddr, &len)) + { + DBUS_SOCKET_SET_ERRNO (); + goto out0; + } + + socket1 = socket (AF_INET, SOCK_STREAM, 0); + if (socket1 == INVALID_SOCKET) + { + DBUS_SOCKET_SET_ERRNO (); + goto out0; + } + + arg = 1; + if (ioctlsocket (socket1, FIONBIO, &arg) == SOCKET_ERROR) + { + DBUS_SOCKET_SET_ERRNO (); + goto out1; + } + + if (connect (socket1, (struct sockaddr *)&saddr, len) != SOCKET_ERROR || + WSAGetLastError () != WSAEWOULDBLOCK) + { + dbus_set_error_const (error, DBUS_ERROR_FAILED, + "_dbus_full_duplex_pipe socketpair() emulation failed"); + goto out1; + } + + FD_ZERO (&read_set); + FD_SET (temp, &read_set); + + tv.tv_sec = 0; + tv.tv_usec = 0; + + if (select (0, &read_set, NULL, NULL, NULL) == SOCKET_ERROR) + { + DBUS_SOCKET_SET_ERRNO (); + goto out1; + } + + _dbus_assert (FD_ISSET (temp, &read_set)); + + socket2 = accept (temp, (struct sockaddr *) &saddr, &len); + if (socket2 == INVALID_SOCKET) + { + DBUS_SOCKET_SET_ERRNO (); + goto out1; + } + + FD_ZERO (&write_set); + FD_SET (socket1, &write_set); + + tv.tv_sec = 0; + tv.tv_usec = 0; + + if (select (0, NULL, &write_set, NULL, NULL) == SOCKET_ERROR) + { + DBUS_SOCKET_SET_ERRNO (); + goto out2; + } + + _dbus_assert (FD_ISSET (socket1, &write_set)); + + if (blocking) + { + arg = 0; + if (ioctlsocket (socket1, FIONBIO, &arg) == SOCKET_ERROR) + { + DBUS_SOCKET_SET_ERRNO (); + goto out2; + } + + arg = 0; + if (ioctlsocket (socket2, FIONBIO, &arg) == SOCKET_ERROR) + { + DBUS_SOCKET_SET_ERRNO (); + goto out2; + } + } + else + { + arg = 1; + if (ioctlsocket (socket2, FIONBIO, &arg) == SOCKET_ERROR) + { + DBUS_SOCKET_SET_ERRNO (); + goto out2; + } + } + + sock.fd = socket1; + *fd1 = _dbus_socket_to_handle (&sock); + sock.fd = socket2; + *fd2 = _dbus_socket_to_handle (&sock); + + _dbus_verbose ("full-duplex pipe %d:%d <-> %d:%d\n", + *fd1, socket1, *fd2, socket2); + + closesocket (temp); + + return TRUE; + +out2: + closesocket (socket2); +out1: + closesocket (socket1); +out0: + closesocket (temp); + + dbus_set_error (error, _dbus_error_from_errno (errno), + "Could not setup socket pair: %s", + _dbus_strerror (errno)); + + return FALSE; +} + +/** + * Wrapper for poll(). + * + * @param fds the file descriptors to poll + * @param n_fds number of descriptors in the array + * @param timeout_milliseconds timeout or -1 for infinite + * @returns numbers of fds with revents, or <0 on error + */ +#define USE_CHRIS_IMPL 0 +#if USE_CHRIS_IMPL +int +_dbus_poll (DBusPollFD *fds, + int n_fds, + int timeout_milliseconds) +{ +#define DBUS_POLL_CHAR_BUFFER_SIZE 2000 + char msg[DBUS_POLL_CHAR_BUFFER_SIZE]; + char *msgp; + + int ret = 0; + int i; + struct timeval tv; + int ready; + +#define DBUS_STACK_WSAEVENTS 256 + WSAEVENT eventsOnStack[DBUS_STACK_WSAEVENTS]; + WSAEVENT *pEvents = NULL; + if (n_fds > DBUS_STACK_WSAEVENTS) + pEvents = calloc(sizeof(WSAEVENT), n_fds); + else + pEvents = eventsOnStack; + + _dbus_lock_sockets(); + +#ifdef DBUS_ENABLE_VERBOSE_MODE + msgp = msg; + msgp += sprintf (msgp, "WSAEventSelect: to=%d\n\t", timeout_milliseconds); + for (i = 0; i < n_fds; i++) + { + static dbus_bool_t warned = FALSE; + DBusSocket *s; + DBusPollFD *fdp = &fds[i]; + + _dbus_handle_to_socket_unlocked(fdp->fd, &s); + + if (s->is_used == 0) + { + _dbus_warn ("no valid socket"); + warned = TRUE; + } + + if (fdp->events & _DBUS_POLLIN) + msgp += sprintf (msgp, "R:%d ", s->fd); + + if (fdp->events & _DBUS_POLLOUT) + msgp += sprintf (msgp, "W:%d ", s->fd); + + msgp += sprintf (msgp, "E:%d\n\t", s->fd); + + // FIXME: more robust code for long msg + // create on heap when msg[] becomes too small + if (msgp >= msg + DBUS_POLL_CHAR_BUFFER_SIZE) + { + _dbus_assert_not_reached ("buffer overflow in _dbus_poll"); + } + } + + msgp += sprintf (msgp, "\n"); + _dbus_verbose ("%s",msg); +#endif + for (i = 0; i < n_fds; i++) + { + DBusSocket *s; + DBusPollFD *fdp = &fds[i]; + WSAEVENT ev; + long lNetworkEvents = FD_OOB; + + _dbus_handle_to_socket_unlocked(fdp->fd, &s); + + if (s->is_used == 0) + continue; + + ev = WSACreateEvent(); + + if (fdp->events & _DBUS_POLLIN) + lNetworkEvents |= FD_READ | FD_ACCEPT | FD_CLOSE; + + if (fdp->events & _DBUS_POLLOUT) + lNetworkEvents |= FD_WRITE | FD_CONNECT; + + WSAEventSelect(s->fd, ev, lNetworkEvents); + + pEvents[i] = ev; + } + + _dbus_unlock_sockets(); + + ready = WSAWaitForMultipleEvents (n_fds, pEvents, FALSE, timeout_milliseconds, FALSE); + + if (DBUS_SOCKET_API_RETURNS_ERROR (ready)) + { + DBUS_SOCKET_SET_ERRNO (); + if (errno != EWOULDBLOCK) + _dbus_verbose ("WSAWaitForMultipleEvents: failed: %s\n", _dbus_strerror (errno)); + ret = -1; + } + else if (ready == WSA_WAIT_TIMEOUT) + { + _dbus_verbose ("WSAWaitForMultipleEvents: WSA_WAIT_TIMEOUT\n"); + ret = 0; + } + else if (ready >= WSA_WAIT_EVENT_0 && ready < (int)(WSA_WAIT_EVENT_0 + n_fds)) + { + msgp = msg; + msgp += sprintf (msgp, "WSAWaitForMultipleEvents: =%d\n\t", ready); + + _dbus_lock_sockets(); + for (i = 0; i < n_fds; i++) + { + DBusSocket *s; + DBusPollFD *fdp = &fds[i]; + WSANETWORKEVENTS ne; + + _dbus_handle_to_socket_unlocked(fdp->fd, &s); + + fdp->revents = 0; + + WSAEnumNetworkEvents(s->fd, pEvents[i], &ne); + + if (ne.lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) + fdp->revents |= _DBUS_POLLIN; + + if (ne.lNetworkEvents & (FD_WRITE | FD_CONNECT)) + fdp->revents |= _DBUS_POLLOUT; + + if (ne.lNetworkEvents & (FD_OOB)) + fdp->revents |= _DBUS_POLLERR; + + if (ne.lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) + msgp += sprintf (msgp, "R:%d ", s->fd); + + if (ne.lNetworkEvents & (FD_WRITE | FD_CONNECT)) + msgp += sprintf (msgp, "W:%d ", s->fd); + + if (ne.lNetworkEvents & (FD_OOB)) + msgp += sprintf (msgp, "E:%d ", s->fd); + + msgp += sprintf (msgp, "lNetworkEvents:%d ", ne.lNetworkEvents); + + if(ne.lNetworkEvents) + ret++; + + WSAEventSelect(s->fd, pEvents[i], 0); + } + _dbus_unlock_sockets(); + + msgp += sprintf (msgp, "\n"); + _dbus_verbose ("%s",msg); + } + else + { + _dbus_verbose ("WSAWaitForMultipleEvents: failed for unknown reason!"); + ret = -1; + } + + for(i = 0; i < n_fds; i++) + { + WSACloseEvent(pEvents[i]); + } + + if (n_fds > DBUS_STACK_WSAEVENTS) + free(pEvents); + + return ret; +} + +#else // USE_CHRIS_IMPL + +int +_dbus_poll (DBusPollFD *fds, + int n_fds, + int timeout_milliseconds) +{ +#define DBUS_POLL_CHAR_BUFFER_SIZE 2000 + char msg[DBUS_POLL_CHAR_BUFFER_SIZE]; + char *msgp; + + fd_set read_set, write_set, err_set; + int max_fd = 0; + int i; + struct timeval tv; + int ready; + + FD_ZERO (&read_set); + FD_ZERO (&write_set); + FD_ZERO (&err_set); + + _dbus_lock_sockets(); + +#ifdef DBUS_ENABLE_VERBOSE_MODE + msgp = msg; + msgp += sprintf (msgp, "select: to=%d\n\t", timeout_milliseconds); + for (i = 0; i < n_fds; i++) + { + static dbus_bool_t warned = FALSE; + DBusSocket *s; + DBusPollFD *fdp = &fds[i]; + + _dbus_handle_to_socket_unlocked(fdp->fd, &s); + + if (s->is_used == 0) + { + _dbus_warn ("no valid socket"); + warned = TRUE; + } + + if (fdp->events & _DBUS_POLLIN) + msgp += sprintf (msgp, "R:%d ", s->fd); + + if (fdp->events & _DBUS_POLLOUT) + msgp += sprintf (msgp, "W:%d ", s->fd); + + msgp += sprintf (msgp, "E:%d\n\t", s->fd); + + // FIXME: more robust code for long msg + // create on heap when msg[] becomes too small + if (msgp >= msg + DBUS_POLL_CHAR_BUFFER_SIZE) + { + _dbus_assert_not_reached ("buffer overflow in _dbus_poll"); + } + } + + msgp += sprintf (msgp, "\n"); + _dbus_verbose ("%s",msg); +#endif + for (i = 0; i < n_fds; i++) + { + DBusSocket *s; + DBusPollFD *fdp = &fds[i]; + + _dbus_handle_to_socket_unlocked(fdp->fd, &s); + + if (s->is_used != 1) + continue; + + if (fdp->events & _DBUS_POLLIN) + FD_SET (s->fd, &read_set); + + if (fdp->events & _DBUS_POLLOUT) + FD_SET (s->fd, &write_set); + + FD_SET (s->fd, &err_set); + + max_fd = MAX (max_fd, s->fd); + } + + _dbus_unlock_sockets(); + + tv.tv_sec = timeout_milliseconds / 1000; + tv.tv_usec = (timeout_milliseconds % 1000) * 1000; + + ready = select (max_fd + 1, &read_set, &write_set, &err_set, + timeout_milliseconds < 0 ? NULL : &tv); + + if (DBUS_SOCKET_API_RETURNS_ERROR (ready)) + { + DBUS_SOCKET_SET_ERRNO (); + if (errno != EWOULDBLOCK) + _dbus_verbose ("select: failed: %s\n", _dbus_strerror (errno)); + } + else if (ready == 0) + _dbus_verbose ("select: = 0\n"); + else + if (ready > 0) + { +#ifdef DBUS_ENABLE_VERBOSE_MODE + msgp = msg; + msgp += sprintf (msgp, "select: = %d:\n\t", ready); + _dbus_lock_sockets(); + for (i = 0; i < n_fds; i++) + { + DBusSocket *s; + DBusPollFD *fdp = &fds[i]; + + _dbus_handle_to_socket_unlocked(fdp->fd, &s); + + if (FD_ISSET (s->fd, &read_set)) + msgp += sprintf (msgp, "R:%d ", s->fd); + + if (FD_ISSET (s->fd, &write_set)) + msgp += sprintf (msgp, "W:%d ", s->fd); + + if (FD_ISSET (s->fd, &err_set)) + msgp += sprintf (msgp, "E:%d\n\t", s->fd); + } + msgp += sprintf (msgp, "\n"); + _dbus_verbose ("%s",msg); +#endif + + for (i = 0; i < n_fds; i++) + { + DBusSocket *s; + DBusPollFD *fdp = &fds[i]; + + _dbus_handle_to_socket_unlocked(fdp->fd, &s); + + fdp->revents = 0; + + if (FD_ISSET (s->fd, &read_set)) + fdp->revents |= _DBUS_POLLIN; + + if (FD_ISSET (s->fd, &write_set)) + fdp->revents |= _DBUS_POLLOUT; + + if (FD_ISSET (s->fd, &err_set)) + fdp->revents |= _DBUS_POLLERR; + } + _dbus_unlock_sockets(); + } + return ready; +} +#endif // USE_CHRIS_IMPL + + +/************************************************************************ + + error handling + + ************************************************************************/ + + +/** + * Assigns an error name and message corresponding to a Win32 error + * code to a DBusError. Does nothing if error is #NULL. + * + * @param error the error. + * @param code the Win32 error code + */ +void +_dbus_win_set_error_from_win_error (DBusError *error, + int code) +{ + char *msg; + + /* As we want the English message, use the A API */ + FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_IGNORE_INSERTS | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, code, MAKELANGID (LANG_ENGLISH, SUBLANG_ENGLISH_US), + (LPTSTR) &msg, 0, NULL); + if (msg) + { + char *msg_copy; + + msg_copy = dbus_malloc (strlen (msg)); + strcpy (msg_copy, msg); + LocalFree (msg); + + dbus_set_error (error, "Win32 error", "%s", msg_copy); + } + else + dbus_set_error_const (error, "Win32 error", "Unknown error code or FormatMessage failed"); +} + +void +_dbus_win_warn_win_error (const char *message, + int code) +{ + DBusError error; + + dbus_error_init (&error); + _dbus_win_set_error_from_win_error (&error, code); + _dbus_warn ("%s: %s\n", message, error.message); + dbus_error_free (&error); +} + +/** + * A wrapper around strerror() because some platforms + * may be lame and not have strerror(). + * + * @param error_number errno. + * @returns error description. + */ +const char* +_dbus_strerror (int error_number) +{ +#ifdef DBUS_WINCE + // TODO + return "unknown"; +#else + const char *msg; + + switch (error_number) + { + case WSAEINTR: + return "Interrupted function call"; + case WSAEACCES: + return "Permission denied"; + case WSAEFAULT: + return "Bad address"; + case WSAEINVAL: + return "Invalid argument"; + case WSAEMFILE: + return "Too many open files"; + case WSAEWOULDBLOCK: + return "Resource temporarily unavailable"; + case WSAEINPROGRESS: + return "Operation now in progress"; + case WSAEALREADY: + return "Operation already in progress"; + case WSAENOTSOCK: + return "Socket operation on nonsocket"; + case WSAEDESTADDRREQ: + return "Destination address required"; + case WSAEMSGSIZE: + return "Message too long"; + case WSAEPROTOTYPE: + return "Protocol wrong type for socket"; + case WSAENOPROTOOPT: + return "Bad protocol option"; + case WSAEPROTONOSUPPORT: + return "Protocol not supported"; + case WSAESOCKTNOSUPPORT: + return "Socket type not supported"; + case WSAEOPNOTSUPP: + return "Operation not supported"; + case WSAEPFNOSUPPORT: + return "Protocol family not supported"; + case WSAEAFNOSUPPORT: + return "Address family not supported by protocol family"; + case WSAEADDRINUSE: + return "Address already in use"; + case WSAEADDRNOTAVAIL: + return "Cannot assign requested address"; + case WSAENETDOWN: + return "Network is down"; + case WSAENETUNREACH: + return "Network is unreachable"; + case WSAENETRESET: + return "Network dropped connection on reset"; + case WSAECONNABORTED: + return "Software caused connection abort"; + case WSAECONNRESET: + return "Connection reset by peer"; + case WSAENOBUFS: + return "No buffer space available"; + case WSAEISCONN: + return "Socket is already connected"; + case WSAENOTCONN: + return "Socket is not connected"; + case WSAESHUTDOWN: + return "Cannot send after socket shutdown"; + case WSAETIMEDOUT: + return "Connection timed out"; + case WSAECONNREFUSED: + return "Connection refused"; + case WSAEHOSTDOWN: + return "Host is down"; + case WSAEHOSTUNREACH: + return "No route to host"; + case WSAEPROCLIM: + return "Too many processes"; + case WSAEDISCON: + return "Graceful shutdown in progress"; + case WSATYPE_NOT_FOUND: + return "Class type not found"; + case WSAHOST_NOT_FOUND: + return "Host not found"; + case WSATRY_AGAIN: + return "Nonauthoritative host not found"; + case WSANO_RECOVERY: + return "This is a nonrecoverable error"; + case WSANO_DATA: + return "Valid name, no data record of requested type"; + case WSA_INVALID_HANDLE: + return "Specified event object handle is invalid"; + case WSA_INVALID_PARAMETER: + return "One or more parameters are invalid"; + case WSA_IO_INCOMPLETE: + return "Overlapped I/O event object not in signaled state"; + case WSA_IO_PENDING: + return "Overlapped operations will complete later"; + case WSA_NOT_ENOUGH_MEMORY: + return "Insufficient memory available"; + case WSA_OPERATION_ABORTED: + return "Overlapped operation aborted"; +#ifdef WSAINVALIDPROCTABLE + + case WSAINVALIDPROCTABLE: + return "Invalid procedure table from service provider"; +#endif +#ifdef WSAINVALIDPROVIDER + + case WSAINVALIDPROVIDER: + return "Invalid service provider version number"; +#endif +#ifdef WSAPROVIDERFAILEDINIT + + case WSAPROVIDERFAILEDINIT: + return "Unable to initialize a service provider"; +#endif + + case WSASYSCALLFAILURE: + return "System call failure"; + } + msg = strerror (error_number); + if (msg == NULL) + msg = "unknown"; + + return msg; +#endif //DBUS_WINCE +} + + + +/* lan manager error codes */ +const char* +_dbus_lm_strerror(int error_number) +{ +#ifdef DBUS_WINCE + // TODO + return "unknown"; +#else + const char *msg; + switch (error_number) + { + case NERR_NetNotStarted: + return "The workstation driver is not installed."; + case NERR_UnknownServer: + return "The server could not be located."; + case NERR_ShareMem: + return "An internal error occurred. The network cannot access a shared memory segment."; + case NERR_NoNetworkResource: + return "A network resource shortage occurred."; + case NERR_RemoteOnly: + return "This operation is not supported on workstations."; + case NERR_DevNotRedirected: + return "The device is not connected."; + case NERR_ServerNotStarted: + return "The Server service is not started."; + case NERR_ItemNotFound: + return "The queue is empty."; + case NERR_UnknownDevDir: + return "The device or directory does not exist."; + case NERR_RedirectedPath: + return "The operation is invalid on a redirected resource."; + case NERR_DuplicateShare: + return "The name has already been shared."; + case NERR_NoRoom: + return "The server is currently out of the requested resource."; + case NERR_TooManyItems: + return "Requested addition of items exceeds the maximum allowed."; + case NERR_InvalidMaxUsers: + return "The Peer service supports only two simultaneous users."; + case NERR_BufTooSmall: + return "The API return buffer is too small."; + case NERR_RemoteErr: + return "A remote API error occurred."; + case NERR_LanmanIniError: + return "An error occurred when opening or reading the configuration file."; + case NERR_NetworkError: + return "A general network error occurred."; + case NERR_WkstaInconsistentState: + return "The Workstation service is in an inconsistent state. Restart the computer before restarting the Workstation service."; + case NERR_WkstaNotStarted: + return "The Workstation service has not been started."; + case NERR_BrowserNotStarted: + return "The requested information is not available."; + case NERR_InternalError: + return "An internal error occurred."; + case NERR_BadTransactConfig: + return "The server is not configured for transactions."; + case NERR_InvalidAPI: + return "The requested API is not supported on the remote server."; + case NERR_BadEventName: + return "The event name is invalid."; + case NERR_DupNameReboot: + return "The computer name already exists on the network. Change it and restart the computer."; + case NERR_CfgCompNotFound: + return "The specified component could not be found in the configuration information."; + case NERR_CfgParamNotFound: + return "The specified parameter could not be found in the configuration information."; + case NERR_LineTooLong: + return "A line in the configuration file is too long."; + case NERR_QNotFound: + return "The printer does not exist."; + case NERR_JobNotFound: + return "The print job does not exist."; + case NERR_DestNotFound: + return "The printer destination cannot be found."; + case NERR_DestExists: + return "The printer destination already exists."; + case NERR_QExists: + return "The printer queue already exists."; + case NERR_QNoRoom: + return "No more printers can be added."; + case NERR_JobNoRoom: + return "No more print jobs can be added."; + case NERR_DestNoRoom: + return "No more printer destinations can be added."; + case NERR_DestIdle: + return "This printer destination is idle and cannot accept control operations."; + case NERR_DestInvalidOp: + return "This printer destination request contains an invalid control function."; + case NERR_ProcNoRespond: + return "The print processor is not responding."; + case NERR_SpoolerNotLoaded: + return "The spooler is not running."; + case NERR_DestInvalidState: + return "This operation cannot be performed on the print destination in its current state."; + case NERR_QInvalidState: + return "This operation cannot be performed on the printer queue in its current state."; + case NERR_JobInvalidState: + return "This operation cannot be performed on the print job in its current state."; + case NERR_SpoolNoMemory: + return "A spooler memory allocation failure occurred."; + case NERR_DriverNotFound: + return "The device driver does not exist."; + case NERR_DataTypeInvalid: + return "The data type is not supported by the print processor."; + case NERR_ProcNotFound: + return "The print processor is not installed."; + case NERR_ServiceTableLocked: + return "The service database is locked."; + case NERR_ServiceTableFull: + return "The service table is full."; + case NERR_ServiceInstalled: + return "The requested service has already been started."; + case NERR_ServiceEntryLocked: + return "The service does not respond to control actions."; + case NERR_ServiceNotInstalled: + return "The service has not been started."; + case NERR_BadServiceName: + return "The service name is invalid."; + case NERR_ServiceCtlTimeout: + return "The service is not responding to the control function."; + case NERR_ServiceCtlBusy: + return "The service control is busy."; + case NERR_BadServiceProgName: + return "The configuration file contains an invalid service program name."; + case NERR_ServiceNotCtrl: + return "The service could not be controlled in its present state."; + case NERR_ServiceKillProc: + return "The service ended abnormally."; + case NERR_ServiceCtlNotValid: + return "The requested pause or stop is not valid for this service."; + case NERR_NotInDispatchTbl: + return "The service control dispatcher could not find the service name in the dispatch table."; + case NERR_BadControlRecv: + return "The service control dispatcher pipe read failed."; + case NERR_ServiceNotStarting: + return "A thread for the new service could not be created."; + case NERR_AlreadyLoggedOn: + return "This workstation is already logged on to the local-area network."; + case NERR_NotLoggedOn: + return "The workstation is not logged on to the local-area network."; + case NERR_BadUsername: + return "The user name or group name parameter is invalid."; + case NERR_BadPassword: + return "The password parameter is invalid."; + case NERR_UnableToAddName_W: + return "@W The logon processor did not add the message alias."; + case NERR_UnableToAddName_F: + return "The logon processor did not add the message alias."; + case NERR_UnableToDelName_W: + return "@W The logoff processor did not delete the message alias."; + case NERR_UnableToDelName_F: + return "The logoff processor did not delete the message alias."; + case NERR_LogonsPaused: + return "Network logons are paused."; + case NERR_LogonServerConflict: + return "A centralized logon-server conflict occurred."; + case NERR_LogonNoUserPath: + return "The server is configured without a valid user path."; + case NERR_LogonScriptError: + return "An error occurred while loading or running the logon script."; + case NERR_StandaloneLogon: + return "The logon server was not specified. Your computer will be logged on as STANDALONE."; + case NERR_LogonServerNotFound: + return "The logon server could not be found."; + case NERR_LogonDomainExists: + return "There is already a logon domain for this computer."; + case NERR_NonValidatedLogon: + return "The logon server could not validate the logon."; + case NERR_ACFNotFound: + return "The security database could not be found."; + case NERR_GroupNotFound: + return "The group name could not be found."; + case NERR_UserNotFound: + return "The user name could not be found."; + case NERR_ResourceNotFound: + return "The resource name could not be found."; + case NERR_GroupExists: + return "The group already exists."; + case NERR_UserExists: + return "The user account already exists."; + case NERR_ResourceExists: + return "The resource permission list already exists."; + case NERR_NotPrimary: + return "This operation is only allowed on the primary domain controller of the domain."; + case NERR_ACFNotLoaded: + return "The security database has not been started."; + case NERR_ACFNoRoom: + return "There are too many names in the user accounts database."; + case NERR_ACFFileIOFail: + return "A disk I/O failure occurred."; + case NERR_ACFTooManyLists: + return "The limit of 64 entries per resource was exceeded."; + case NERR_UserLogon: + return "Deleting a user with a session is not allowed."; + case NERR_ACFNoParent: + return "The parent directory could not be located."; + case NERR_CanNotGrowSegment: + return "Unable to add to the security database session cache segment."; + case NERR_SpeGroupOp: + return "This operation is not allowed on this special group."; + case NERR_NotInCache: + return "This user is not cached in user accounts database session cache."; + case NERR_UserInGroup: + return "The user already belongs to this group."; + case NERR_UserNotInGroup: + return "The user does not belong to this group."; + case NERR_AccountUndefined: + return "This user account is undefined."; + case NERR_AccountExpired: + return "This user account has expired."; + case NERR_InvalidWorkstation: + return "The user is not allowed to log on from this workstation."; + case NERR_InvalidLogonHours: + return "The user is not allowed to log on at this time."; + case NERR_PasswordExpired: + return "The password of this user has expired."; + case NERR_PasswordCantChange: + return "The password of this user cannot change."; + case NERR_PasswordHistConflict: + return "This password cannot be used now."; + case NERR_PasswordTooShort: + return "The password does not meet the password policy requirements. Check the minimum password length, password complexity and password history requirements."; + case NERR_PasswordTooRecent: + return "The password of this user is too recent to change."; + case NERR_InvalidDatabase: + return "The security database is corrupted."; + case NERR_DatabaseUpToDate: + return "No updates are necessary to this replicant network/local security database."; + case NERR_SyncRequired: + return "This replicant database is outdated; synchronization is required."; + case NERR_UseNotFound: + return "The network connection could not be found."; + case NERR_BadAsgType: + return "This asg_type is invalid."; + case NERR_DeviceIsShared: + return "This device is currently being shared."; + case NERR_NoComputerName: + return "The computer name could not be added as a message alias. The name may already exist on the network."; + case NERR_MsgAlreadyStarted: + return "The Messenger service is already started."; + case NERR_MsgInitFailed: + return "The Messenger service failed to start."; + case NERR_NameNotFound: + return "The message alias could not be found on the network."; + case NERR_AlreadyForwarded: + return "This message alias has already been forwarded."; + case NERR_AddForwarded: + return "This message alias has been added but is still forwarded."; + case NERR_AlreadyExists: + return "This message alias already exists locally."; + case NERR_TooManyNames: + return "The maximum number of added message aliases has been exceeded."; + case NERR_DelComputerName: + return "The computer name could not be deleted."; + case NERR_LocalForward: + return "Messages cannot be forwarded back to the same workstation."; + case NERR_GrpMsgProcessor: + return "An error occurred in the domain message processor."; + case NERR_PausedRemote: + return "The message was sent, but the recipient has paused the Messenger service."; + case NERR_BadReceive: + return "The message was sent but not received."; + case NERR_NameInUse: + return "The message alias is currently in use. Try again later."; + case NERR_MsgNotStarted: + return "The Messenger service has not been started."; + case NERR_NotLocalName: + return "The name is not on the local computer."; + case NERR_NoForwardName: + return "The forwarded message alias could not be found on the network."; + case NERR_RemoteFull: + return "The message alias table on the remote station is full."; + case NERR_NameNotForwarded: + return "Messages for this alias are not currently being forwarded."; + case NERR_TruncatedBroadcast: + return "The broadcast message was truncated."; + case NERR_InvalidDevice: + return "This is an invalid device name."; + case NERR_WriteFault: + return "A write fault occurred."; + case NERR_DuplicateName: + return "A duplicate message alias exists on the network."; + case NERR_DeleteLater: + return "@W This message alias will be deleted later."; + case NERR_IncompleteDel: + return "The message alias was not successfully deleted from all networks."; + case NERR_MultipleNets: + return "This operation is not supported on computers with multiple networks."; + case NERR_NetNameNotFound: + return "This shared resource does not exist."; + case NERR_DeviceNotShared: + return "This device is not shared."; + case NERR_ClientNameNotFound: + return "A session does not exist with that computer name."; + case NERR_FileIdNotFound: + return "There is not an open file with that identification number."; + case NERR_ExecFailure: + return "A failure occurred when executing a remote administration command."; + case NERR_TmpFile: + return "A failure occurred when opening a remote temporary file."; + case NERR_TooMuchData: + return "The data returned from a remote administration command has been truncated to 64K."; + case NERR_DeviceShareConflict: + return "This device cannot be shared as both a spooled and a non-spooled resource."; + case NERR_BrowserTableIncomplete: + return "The information in the list of servers may be incorrect."; + case NERR_NotLocalDomain: + return "The computer is not active in this domain."; +#ifdef NERR_IsDfsShare + + case NERR_IsDfsShare: + return "The share must be removed from the Distributed File System before it can be deleted."; +#endif + + case NERR_DevInvalidOpCode: + return "The operation is invalid for this device."; + case NERR_DevNotFound: + return "This device cannot be shared."; + case NERR_DevNotOpen: + return "This device was not open."; + case NERR_BadQueueDevString: + return "This device name list is invalid."; + case NERR_BadQueuePriority: + return "The queue priority is invalid."; + case NERR_NoCommDevs: + return "There are no shared communication devices."; + case NERR_QueueNotFound: + return "The queue you specified does not exist."; + case NERR_BadDevString: + return "This list of devices is invalid."; + case NERR_BadDev: + return "The requested device is invalid."; + case NERR_InUseBySpooler: + return "This device is already in use by the spooler."; + case NERR_CommDevInUse: + return "This device is already in use as a communication device."; + case NERR_InvalidComputer: + return "This computer name is invalid."; + case NERR_MaxLenExceeded: + return "The string and prefix specified are too long."; + case NERR_BadComponent: + return "This path component is invalid."; + case NERR_CantType: + return "Could not determine the type of input."; + case NERR_TooManyEntries: + return "The buffer for types is not big enough."; + case NERR_ProfileFileTooBig: + return "Profile files cannot exceed 64K."; + case NERR_ProfileOffset: + return "The start offset is out of range."; + case NERR_ProfileCleanup: + return "The system cannot delete current connections to network resources."; + case NERR_ProfileUnknownCmd: + return "The system was unable to parse the command line in this file."; + case NERR_ProfileLoadErr: + return "An error occurred while loading the profile file."; + case NERR_ProfileSaveErr: + return "@W Errors occurred while saving the profile file. The profile was partially saved."; + case NERR_LogOverflow: + return "Log file %1 is full."; + case NERR_LogFileChanged: + return "This log file has changed between reads."; + case NERR_LogFileCorrupt: + return "Log file %1 is corrupt."; + case NERR_SourceIsDir: + return "The source path cannot be a directory."; + case NERR_BadSource: + return "The source path is illegal."; + case NERR_BadDest: + return "The destination path is illegal."; + case NERR_DifferentServers: + return "The source and destination paths are on different servers."; + case NERR_RunSrvPaused: + return "The Run server you requested is paused."; + case NERR_ErrCommRunSrv: + return "An error occurred when communicating with a Run server."; + case NERR_ErrorExecingGhost: + return "An error occurred when starting a background process."; + case NERR_ShareNotFound: + return "The shared resource you are connected to could not be found."; + case NERR_InvalidLana: + return "The LAN adapter number is invalid."; + case NERR_OpenFiles: + return "There are open files on the connection."; + case NERR_ActiveConns: + return "Active connections still exist."; + case NERR_BadPasswordCore: + return "This share name or password is invalid."; + case NERR_DevInUse: + return "The device is being accessed by an active process."; + case NERR_LocalDrive: + return "The drive letter is in use locally."; + case NERR_AlertExists: + return "The specified client is already registered for the specified event."; + case NERR_TooManyAlerts: + return "The alert table is full."; + case NERR_NoSuchAlert: + return "An invalid or nonexistent alert name was raised."; + case NERR_BadRecipient: + return "The alert recipient is invalid."; + case NERR_AcctLimitExceeded: + return "A user's session with this server has been deleted."; + case NERR_InvalidLogSeek: + return "The log file does not contain the requested record number."; + case NERR_BadUasConfig: + return "The user accounts database is not configured correctly."; + case NERR_InvalidUASOp: + return "This operation is not permitted when the Netlogon service is running."; + case NERR_LastAdmin: + return "This operation is not allowed on the last administrative account."; + case NERR_DCNotFound: + return "Could not find domain controller for this domain."; + case NERR_LogonTrackingError: + return "Could not set logon information for this user."; + case NERR_NetlogonNotStarted: + return "The Netlogon service has not been started."; + case NERR_CanNotGrowUASFile: + return "Unable to add to the user accounts database."; + case NERR_TimeDiffAtDC: + return "This server's clock is not synchronized with the primary domain controller's clock."; + case NERR_PasswordMismatch: + return "A password mismatch has been detected."; + case NERR_NoSuchServer: + return "The server identification does not specify a valid server."; + case NERR_NoSuchSession: + return "The session identification does not specify a valid session."; + case NERR_NoSuchConnection: + return "The connection identification does not specify a valid connection."; + case NERR_TooManyServers: + return "There is no space for another entry in the table of available servers."; + case NERR_TooManySessions: + return "The server has reached the maximum number of sessions it supports."; + case NERR_TooManyConnections: + return "The server has reached the maximum number of connections it supports."; + case NERR_TooManyFiles: + return "The server cannot open more files because it has reached its maximum number."; + case NERR_NoAlternateServers: + return "There are no alternate servers registered on this server."; + case NERR_TryDownLevel: + return "Try down-level (remote admin protocol) version of API instead."; + case NERR_UPSDriverNotStarted: + return "The UPS driver could not be accessed by the UPS service."; + case NERR_UPSInvalidConfig: + return "The UPS service is not configured correctly."; + case NERR_UPSInvalidCommPort: + return "The UPS service could not access the specified Comm Port."; + case NERR_UPSSignalAsserted: + return "The UPS indicated a line fail or low battery situation. Service not started."; + case NERR_UPSShutdownFailed: + return "The UPS service failed to perform a system shut down."; + case NERR_BadDosRetCode: + return "The program below returned an MS-DOS error code:"; + case NERR_ProgNeedsExtraMem: + return "The program below needs more memory:"; + case NERR_BadDosFunction: + return "The program below called an unsupported MS-DOS function:"; + case NERR_RemoteBootFailed: + return "The workstation failed to boot."; + case NERR_BadFileCheckSum: + return "The file below is corrupt."; + case NERR_NoRplBootSystem: + return "No loader is specified in the boot-block definition file."; + case NERR_RplLoadrNetBiosErr: + return "NetBIOS returned an error: The NCB and SMB are dumped above."; + case NERR_RplLoadrDiskErr: + return "A disk I/O error occurred."; + case NERR_ImageParamErr: + return "Image parameter substitution failed."; + case NERR_TooManyImageParams: + return "Too many image parameters cross disk sector boundaries."; + case NERR_NonDosFloppyUsed: + return "The image was not generated from an MS-DOS diskette formatted with /S."; + case NERR_RplBootRestart: + return "Remote boot will be restarted later."; + case NERR_RplSrvrCallFailed: + return "The call to the Remoteboot server failed."; + case NERR_CantConnectRplSrvr: + return "Cannot connect to the Remoteboot server."; + case NERR_CantOpenImageFile: + return "Cannot open image file on the Remoteboot server."; + case NERR_CallingRplSrvr: + return "Connecting to the Remoteboot server..."; + case NERR_StartingRplBoot: + return "Connecting to the Remoteboot server..."; + case NERR_RplBootServiceTerm: + return "Remote boot service was stopped; check the error log for the cause of the problem."; + case NERR_RplBootStartFailed: + return "Remote boot startup failed; check the error log for the cause of the problem."; + case NERR_RPL_CONNECTED: + return "A second connection to a Remoteboot resource is not allowed."; + case NERR_BrowserConfiguredToNotRun: + return "The browser service was configured with MaintainServerList=No."; + case NERR_RplNoAdaptersStarted: + return "Service failed to start since none of the network adapters started with this service."; + case NERR_RplBadRegistry: + return "Service failed to start due to bad startup information in the registry."; + case NERR_RplBadDatabase: + return "Service failed to start because its database is absent or corrupt."; + case NERR_RplRplfilesShare: + return "Service failed to start because RPLFILES share is absent."; + case NERR_RplNotRplServer: + return "Service failed to start because RPLUSER group is absent."; + case NERR_RplCannotEnum: + return "Cannot enumerate service records."; + case NERR_RplWkstaInfoCorrupted: + return "Workstation record information has been corrupted."; + case NERR_RplWkstaNotFound: + return "Workstation record was not found."; + case NERR_RplWkstaNameUnavailable: + return "Workstation name is in use by some other workstation."; + case NERR_RplProfileInfoCorrupted: + return "Profile record information has been corrupted."; + case NERR_RplProfileNotFound: + return "Profile record was not found."; + case NERR_RplProfileNameUnavailable: + return "Profile name is in use by some other profile."; + case NERR_RplProfileNotEmpty: + return "There are workstations using this profile."; + case NERR_RplConfigInfoCorrupted: + return "Configuration record information has been corrupted."; + case NERR_RplConfigNotFound: + return "Configuration record was not found."; + case NERR_RplAdapterInfoCorrupted: + return "Adapter ID record information has been corrupted."; + case NERR_RplInternal: + return "An internal service error has occurred."; + case NERR_RplVendorInfoCorrupted: + return "Vendor ID record information has been corrupted."; + case NERR_RplBootInfoCorrupted: + return "Boot block record information has been corrupted."; + case NERR_RplWkstaNeedsUserAcct: + return "The user account for this workstation record is missing."; + case NERR_RplNeedsRPLUSERAcct: + return "The RPLUSER local group could not be found."; + case NERR_RplBootNotFound: + return "Boot block record was not found."; + case NERR_RplIncompatibleProfile: + return "Chosen profile is incompatible with this workstation."; + case NERR_RplAdapterNameUnavailable: + return "Chosen network adapter ID is in use by some other workstation."; + case NERR_RplConfigNotEmpty: + return "There are profiles using this configuration."; + case NERR_RplBootInUse: + return "There are workstations, profiles, or configurations using this boot block."; + case NERR_RplBackupDatabase: + return "Service failed to backup Remoteboot database."; + case NERR_RplAdapterNotFound: + return "Adapter record was not found."; + case NERR_RplVendorNotFound: + return "Vendor record was not found."; + case NERR_RplVendorNameUnavailable: + return "Vendor name is in use by some other vendor record."; + case NERR_RplBootNameUnavailable: + return "(boot name, vendor ID) is in use by some other boot block record."; + case NERR_RplConfigNameUnavailable: + return "Configuration name is in use by some other configuration."; + case NERR_DfsInternalCorruption: + return "The internal database maintained by the Dfs service is corrupt."; + case NERR_DfsVolumeDataCorrupt: + return "One of the records in the internal Dfs database is corrupt."; + case NERR_DfsNoSuchVolume: + return "There is no DFS name whose entry path matches the input Entry Path."; + case NERR_DfsVolumeAlreadyExists: + return "A root or link with the given name already exists."; + case NERR_DfsAlreadyShared: + return "The server share specified is already shared in the Dfs."; + case NERR_DfsNoSuchShare: + return "The indicated server share does not support the indicated DFS namespace."; + case NERR_DfsNotALeafVolume: + return "The operation is not valid on this portion of the namespace."; + case NERR_DfsLeafVolume: + return "The operation is not valid on this portion of the namespace."; + case NERR_DfsVolumeHasMultipleServers: + return "The operation is ambiguous because the link has multiple servers."; + case NERR_DfsCantCreateJunctionPoint: + return "Unable to create a link."; + case NERR_DfsServerNotDfsAware: + return "The server is not Dfs Aware."; + case NERR_DfsBadRenamePath: + return "The specified rename target path is invalid."; + case NERR_DfsVolumeIsOffline: + return "The specified DFS link is offline."; + case NERR_DfsNoSuchServer: + return "The specified server is not a server for this link."; + case NERR_DfsCyclicalName: + return "A cycle in the Dfs name was detected."; + case NERR_DfsNotSupportedInServerDfs: + return "The operation is not supported on a server-based Dfs."; + case NERR_DfsDuplicateService: + return "This link is already supported by the specified server-share."; + case NERR_DfsCantRemoveLastServerShare: + return "Can't remove the last server-share supporting this root or link."; + case NERR_DfsVolumeIsInterDfs: + return "The operation is not supported for an Inter-DFS link."; + case NERR_DfsInconsistent: + return "The internal state of the Dfs Service has become inconsistent."; + case NERR_DfsServerUpgraded: + return "The Dfs Service has been installed on the specified server."; + case NERR_DfsDataIsIdentical: + return "The Dfs data being reconciled is identical."; + case NERR_DfsCantRemoveDfsRoot: + return "The DFS root cannot be deleted. Uninstall DFS if required."; + case NERR_DfsChildOrParentInDfs: + return "A child or parent directory of the share is already in a Dfs."; + case NERR_DfsInternalError: + return "Dfs internal error."; + /* the following are not defined in mingw */ +#if 0 + + case NERR_SetupAlreadyJoined: + return "This machine is already joined to a domain."; + case NERR_SetupNotJoined: + return "This machine is not currently joined to a domain."; + case NERR_SetupDomainController: + return "This machine is a domain controller and cannot be unjoined from a domain."; + case NERR_DefaultJoinRequired: + return "The destination domain controller does not support creating machine accounts in OUs."; + case NERR_InvalidWorkgroupName: + return "The specified workgroup name is invalid."; + case NERR_NameUsesIncompatibleCodePage: + return "The specified computer name is incompatible with the default language used on the domain controller."; + case NERR_ComputerAccountNotFound: + return "The specified computer account could not be found."; + case NERR_PersonalSku: + return "This version of Windows cannot be joined to a domain."; + case NERR_PasswordMustChange: + return "The password must change at the next logon."; + case NERR_AccountLockedOut: + return "The account is locked out."; + case NERR_PasswordTooLong: + return "The password is too long."; + case NERR_PasswordNotComplexEnough: + return "The password does not meet the complexity policy."; + case NERR_PasswordFilterError: + return "The password does not meet the requirements of the password filter DLLs."; +#endif + + } + msg = strerror (error_number); + if (msg == NULL) + msg = "unknown"; + + return msg; +#endif //DBUS_WINCE +} + + + + + + + + + +/****************************************************************************** + +Original CVS version of dbus-sysdeps.c + +******************************************************************************/ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-sysdeps.c Wrappers around system/libc features (internal to D-Bus implementation) + * + * Copyright (C) 2002, 2003 Red Hat, Inc. + * Copyright (C) 2003 CodeFactory AB + * Copyright (C) 2005 Novell, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + + +/** + * @addtogroup DBusInternalsUtils + * @{ + */ + +int _dbus_mkdir (const char *path, + mode_t mode) +{ + return _mkdir(path); +} + +/** + * Exit the process, returning the given value. + * + * @param code the exit code + */ +void +_dbus_exit (int code) +{ + _exit (code); +} + +/** + * Creates a socket and connects to a socket at the given host + * and port. The connection fd is returned, and is set up as + * nonblocking. + * + * @param host the host name to connect to, NULL for loopback + * @param port the prot to connect to + * @param error return location for error code + * @returns connection file descriptor or -1 on error + */ +int +_dbus_connect_tcp_socket (const char *host, + dbus_uint32_t port, + DBusError *error) +{ + DBusSocket s; + int handle; + struct sockaddr_in addr; + struct hostent *he; + struct in_addr *haddr; + struct in_addr ina; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + _dbus_win_startup_winsock (); + + s.fd = socket (AF_INET, SOCK_STREAM, 0); + + if (DBUS_SOCKET_IS_INVALID (s.fd)) + { + DBUS_SOCKET_SET_ERRNO (); + dbus_set_error (error, + _dbus_error_from_errno (errno), + "Failed to create socket: %s", + _dbus_strerror (errno)); + + return -1; + } + + if (host == NULL) + { + host = "localhost"; + ina.s_addr = htonl (INADDR_LOOPBACK); + haddr = &ina; + } + + he = gethostbyname (host); + if (he == NULL) + { + DBUS_SOCKET_SET_ERRNO (); + dbus_set_error (error, + _dbus_error_from_errno (errno), + "Failed to lookup hostname: %s", + host); + DBUS_CLOSE_SOCKET (s.fd); + return -1; + } + + haddr = ((struct in_addr *) (he->h_addr_list)[0]); + + _DBUS_ZERO (addr); + memcpy (&addr.sin_addr, haddr, sizeof(struct in_addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons (port); + + if (DBUS_SOCKET_API_RETURNS_ERROR + (connect (s.fd, (struct sockaddr*) &addr, sizeof (addr)) < 0)) + { + DBUS_SOCKET_SET_ERRNO (); + dbus_set_error (error, + _dbus_error_from_errno (errno), + "Failed to connect to socket %s:%d %s", + host, port, _dbus_strerror (errno)); + + DBUS_CLOSE_SOCKET (s.fd); + s.fd = -1; + + return -1; + } + + handle = _dbus_socket_to_handle (&s); + + if (!_dbus_set_fd_nonblocking (handle, error)) + { + _dbus_close_socket (handle, NULL); + handle = -1; + + return -1; + } + + return handle; +} + +void +_dbus_daemon_init(const char *host, dbus_uint32_t port); +/** + * Creates a socket and binds it to the given port, + * then listens on the socket. The socket is + * set to be nonblocking. + * + * @param host the interface to listen on, NULL for loopback, empty for any + * @param port the port to listen on, if zero a free port will be used + * @param error return location for errors + * @returns the listening file descriptor or -1 on error + */ + +int +_dbus_listen_tcp_socket (const char *host, + dbus_uint32_t port, + DBusError *error) +{ + DBusSocket slisten; + int handle; + struct sockaddr_in addr; + struct hostent *he; + struct in_addr *haddr; + int len = sizeof (struct sockaddr); + struct in_addr ina; + + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + _dbus_win_startup_winsock (); + + slisten.fd = socket (AF_INET, SOCK_STREAM, 0); + + if (DBUS_SOCKET_IS_INVALID (slisten.fd)) + { + DBUS_SOCKET_SET_ERRNO (); + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to create socket \"%s:%d\": %s", + host, port, _dbus_strerror (errno)); + return -1; + } + if (host == NULL) + { + host = "localhost"; + ina.s_addr = htonl (INADDR_LOOPBACK); + haddr = &ina; + } + else if (!host[0]) + { + ina.s_addr = htonl (INADDR_ANY); + haddr = &ina; + } + else + { + he = gethostbyname (host); + if (he == NULL) + { + DBUS_SOCKET_SET_ERRNO (); + dbus_set_error (error, + _dbus_error_from_errno (errno), + "Failed to lookup hostname: %s", + host); + DBUS_CLOSE_SOCKET (slisten.fd); + return -1; + } + + haddr = ((struct in_addr *) (he->h_addr_list)[0]); + } + + _DBUS_ZERO (addr); + memcpy (&addr.sin_addr, haddr, sizeof (struct in_addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons (port); + + if (bind (slisten.fd, (struct sockaddr*) &addr, sizeof (struct sockaddr))) + { + DBUS_SOCKET_SET_ERRNO (); + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to bind socket \"%s:%d\": %s", + host, port, _dbus_strerror (errno)); + DBUS_CLOSE_SOCKET (slisten.fd); + return -1; + } + + if (DBUS_SOCKET_API_RETURNS_ERROR (listen (slisten.fd, 30 /* backlog */))) + { + DBUS_SOCKET_SET_ERRNO (); + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to listen on socket \"%s:%d\": %s", + host, port, _dbus_strerror (errno)); + DBUS_CLOSE_SOCKET (slisten.fd); + return -1; + } + + + getsockname(slisten.fd, (struct sockaddr*) &addr, &len); + + _dbus_daemon_init(host, ntohs(addr.sin_port)); + + handle = _dbus_socket_to_handle (&slisten); + + if (!_dbus_set_fd_nonblocking (handle, error)) + { + _dbus_close_socket (handle, NULL); + return -1; + } + + return handle; +} + +/** + * Accepts a connection on a listening socket. + * Handles EINTR for you. + * + * @param listen_fd the listen file descriptor + * @returns the connection fd of the client, or -1 on error + */ +int +_dbus_accept (int listen_handle) +{ + DBusSocket *slisten; + DBusSocket sclient; + struct sockaddr addr; + socklen_t addrlen; + + _dbus_handle_to_socket(listen_handle, &slisten); + + addrlen = sizeof (addr); + + //FIXME: why do we not try it again on Windows? +#if !defined(DBUS_WIN) && !defined(DBUS_WINCE) +retry: +#endif + + sclient.fd = accept (slisten->fd, &addr, &addrlen); + + if (DBUS_SOCKET_IS_INVALID (sclient.fd)) + { + DBUS_SOCKET_SET_ERRNO (); +#if !defined(DBUS_WIN) && !defined(DBUS_WINCE) + if (errno == EINTR) + goto retry; +#else + return -1; +#endif + } + + return _dbus_socket_to_handle (&sclient); +} + + + +dbus_bool_t +write_credentials_byte (int server_fd, + DBusError *error) +{ + /* FIXME: for the session bus credentials shouldn't matter (?), but + * for the system bus they are presumably essential. A rough outline + * of a way to implement the credential transfer would be this: + * + * client waits to *read* a byte. + * + * server creates a named pipe with a random name, sends a byte + * contining its length, and its name. + * + * client reads the name, connects to it (using Win32 API). + * + * server waits for connection to the named pipe, then calls + * ImpersonateNamedPipeClient(), notes its now-current credentials, + * calls RevertToSelf(), closes its handles to the named pipe, and + * is done. (Maybe there is some other way to get the SID of a named + * pipe client without having to use impersonation?) + * + * client closes its handles and is done. + * + */ + + return TRUE; +} + +/** + * Reads a single byte which must be nul (an error occurs otherwise), + * and reads unix credentials if available. Fills in pid/uid/gid with + * -1 if no credentials are available. Return value indicates whether + * a byte was read, not whether we got valid credentials. On some + * systems, such as Linux, reading/writing the byte isn't actually + * required, but we do it anyway just to avoid multiple codepaths. + * + * Fails if no byte is available, so you must select() first. + * + * The point of the byte is that on some systems we have to + * use sendmsg()/recvmsg() to transmit credentials. + * + * @param client_fd the client file descriptor + * @param credentials struct to fill with credentials of client + * @param error location to store error code + * @returns #TRUE on success + */ +dbus_bool_t +_dbus_read_credentials_unix_socket (int client_fd, + DBusCredentials *credentials, + DBusError *error) +{ + /* FIXME bogus testing credentials */ + _dbus_credentials_from_current_process (credentials); + + return TRUE; +} + +/** +* Checks to make sure the given directory is +* private to the user +* +* @param dir the name of the directory +* @param error error return +* @returns #FALSE on failure +**/ +dbus_bool_t +_dbus_check_dir_is_private_to_user (DBusString *dir, DBusError *error) +{ + const char *directory; + struct stat sb; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + return TRUE; +} + + +/** + * Gets user info for the given user ID. + * + * @param info user info object to initialize + * @param uid the user ID + * @param error error return + * @returns #TRUE on success + */ +dbus_bool_t +_dbus_user_info_fill_uid (DBusUserInfo *info, + dbus_uid_t uid, + DBusError *error) +{ + return fill_user_info (info, uid, + NULL, error); +} + +/** + * Gets user info for the given username. + * + * @param info user info object to initialize + * @param username the username + * @param error error return + * @returns #TRUE on success + */ +dbus_bool_t +_dbus_user_info_fill (DBusUserInfo *info, + const DBusString *username, + DBusError *error) +{ + return fill_user_info (info, DBUS_UID_UNSET, + username, error); +} + + +dbus_bool_t +fill_user_info (DBusUserInfo *info, + dbus_uid_t uid, + const DBusString *username, + DBusError *error) +{ + const char *username_c; + + /* exactly one of username/uid provided */ + _dbus_assert (username != NULL || uid != DBUS_UID_UNSET); + _dbus_assert (username == NULL || uid == DBUS_UID_UNSET); + + info->uid = DBUS_UID_UNSET; + info->primary_gid = DBUS_GID_UNSET; + info->group_ids = NULL; + info->n_group_ids = 0; + info->username = NULL; + info->homedir = NULL; + + if (username != NULL) + username_c = _dbus_string_get_const_data (username); + else + username_c = NULL; + + if (uid != DBUS_UID_UNSET) + { + if (!fill_win_user_info_from_uid (uid, info, error)) + { + _dbus_verbose("%s after fill_win_user_info_from_uid\n",__FUNCTION__); + return FALSE; + } + } + else + { + wchar_t *wname = _dbus_win_utf8_to_utf16 (username_c, error); + + if (!wname) + return FALSE; + + if (!fill_win_user_info_from_name (wname, info, error)) + { + dbus_free (wname); + return FALSE; + } + dbus_free (wname); + } + + return TRUE; +} + + +/** + * Appends the given filename to the given directory. + * + * @todo it might be cute to collapse multiple '/' such as "foo//" + * concat "//bar" + * + * @param dir the directory name + * @param next_component the filename + * @returns #TRUE on success + */ +dbus_bool_t +_dbus_concat_dir_and_file (DBusString *dir, + const DBusString *next_component) +{ + dbus_bool_t dir_ends_in_slash; + dbus_bool_t file_starts_with_slash; + + if (_dbus_string_get_length (dir) == 0 || + _dbus_string_get_length (next_component) == 0) + return TRUE; + + dir_ends_in_slash = + ('/' == _dbus_string_get_byte (dir, _dbus_string_get_length (dir) - 1) || + '\\' == _dbus_string_get_byte (dir, _dbus_string_get_length (dir) - 1)); + + file_starts_with_slash = + ('/' == _dbus_string_get_byte (next_component, 0) || + '\\' == _dbus_string_get_byte (next_component, 0)); + + if (dir_ends_in_slash && file_starts_with_slash) + { + _dbus_string_shorten (dir, 1); + } + else if (!(dir_ends_in_slash || file_starts_with_slash)) + { + if (!_dbus_string_append_byte (dir, '\\')) + return FALSE; + } + + return _dbus_string_copy (next_component, 0, dir, + _dbus_string_get_length (dir)); +} + + + + +/** + * Gets our process ID + * @returns process ID + */ +unsigned long +_dbus_getpid (void) +{ + return GetCurrentProcessId (); +} + +/** nanoseconds in a second */ +#define NANOSECONDS_PER_SECOND 1000000000 +/** microseconds in a second */ +#define MICROSECONDS_PER_SECOND 1000000 +/** milliseconds in a second */ +#define MILLISECONDS_PER_SECOND 1000 +/** nanoseconds in a millisecond */ +#define NANOSECONDS_PER_MILLISECOND 1000000 +/** microseconds in a millisecond */ +#define MICROSECONDS_PER_MILLISECOND 1000 + +/** + * Sleeps the given number of milliseconds. + * @param milliseconds number of milliseconds + */ +void +_dbus_sleep_milliseconds (int milliseconds) +{ + Sleep (milliseconds); +} + + +/** + * Get current time, as in gettimeofday(). + * + * @param tv_sec return location for number of seconds + * @param tv_usec return location for number of microseconds + */ +void +_dbus_get_current_time (long *tv_sec, + long *tv_usec) +{ + FILETIME ft; + dbus_uint64_t *time64 = (dbus_uint64_t *) &ft; + + GetSystemTimeAsFileTime (&ft); + + /* Convert from 100s of nanoseconds since 1601-01-01 + * to Unix epoch. Yes, this is Y2038 unsafe. + */ + *time64 -= DBUS_INT64_CONSTANT (116444736000000000); + *time64 /= 10; + + if (tv_sec) + *tv_sec = *time64 / 1000000; + + if (tv_usec) + *tv_usec = *time64 % 1000000; +} + + +/** + * signal (SIGPIPE, SIG_IGN); + */ +void +_dbus_disable_sigpipe (void) +{ + _dbus_verbose("FIXME: implement _dbus_disable_sigpipe (void)\n"); +} + +/** + * Gets the credentials of the current process. + * + * @param credentials credentials to fill in. + */ +void +_dbus_credentials_from_current_process (DBusCredentials *credentials) +{ + credentials->pid = _dbus_getpid (); + credentials->uid = _dbus_getuid (); + credentials->gid = _dbus_getgid (); +} + +/** + * Appends the contents of the given file to the string, + * returning error code. At the moment, won't open a file + * more than a megabyte in size. + * + * @param str the string to append to + * @param filename filename to load + * @param error place to set an error + * @returns #FALSE if error was set + */ +dbus_bool_t +_dbus_file_get_contents (DBusString *str, + const DBusString *filename, + DBusError *error) +{ + DBusFile file; + struct stat sb; + int orig_len; + int total; + const char *filename_c; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + filename_c = _dbus_string_get_const_data (filename); + + /* O_BINARY useful on Cygwin and Win32 */ + if (!_dbus_open_file (&file, filename_c, O_RDONLY | O_BINARY, -1)) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to open \"%s\": %s", + filename_c, + _dbus_strerror (errno)); + return FALSE; + } + + if (!_dbus_fstat (&file, &sb)) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to stat \"%s\": %s", + filename_c, + _dbus_strerror (errno)); + + _dbus_verbose ("fstat() failed: %s", + _dbus_strerror (errno)); + + _dbus_close_file (&file, NULL); + + return FALSE; + } + + if (sb.st_size > _DBUS_ONE_MEGABYTE) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "File size %lu of \"%s\" is too large.", + (unsigned long) sb.st_size, filename_c); + _dbus_close_file (&file, NULL); + return FALSE; + } + + total = 0; + orig_len = _dbus_string_get_length (str); + if (sb.st_size > 0 && S_ISREG (sb.st_mode)) + { + int bytes_read; + + while (total < (int) sb.st_size) + { + bytes_read = _dbus_read_file (&file, str, + sb.st_size - total); + if (bytes_read <= 0) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Error reading \"%s\": %s", + filename_c, + _dbus_strerror (errno)); + + _dbus_verbose ("read() failed: %s", + _dbus_strerror (errno)); + + _dbus_close_file (&file, NULL); + _dbus_string_set_length (str, orig_len); + return FALSE; + } + else + total += bytes_read; + } + + _dbus_close_file (&file, NULL); + return TRUE; + } + else if (sb.st_size != 0) + { + _dbus_verbose ("Can only open regular files at the moment.\n"); + dbus_set_error (error, DBUS_ERROR_FAILED, + "\"%s\" is not a regular file", + filename_c); + _dbus_close_file (&file, NULL); + return FALSE; + } + else + { + _dbus_close_file (&file, NULL); + return TRUE; + } +} + +/** + * Writes a string out to a file. If the file exists, + * it will be atomically overwritten by the new data. + * + * @param str the string to write out + * @param filename the file to save string to + * @param error error to be filled in on failure + * @returns #FALSE on failure + */ +dbus_bool_t +_dbus_string_save_to_file (const DBusString *str, + const DBusString *filename, + DBusError *error) +{ + DBusFile file; + int bytes_to_write; + const char *filename_c; + DBusString tmp_filename; + const char *tmp_filename_c; + int total; + dbus_bool_t need_unlink; + dbus_bool_t retval; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + retval = FALSE; + need_unlink = FALSE; + + if (!_dbus_string_init (&tmp_filename)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return FALSE; + } + + if (!_dbus_string_copy (filename, 0, &tmp_filename, 0)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + _dbus_string_free (&tmp_filename); + return FALSE; + } + + if (!_dbus_string_append (&tmp_filename, ".")) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + _dbus_string_free (&tmp_filename); + return FALSE; + } + +#define N_TMP_FILENAME_RANDOM_BYTES 8 + if (!_dbus_generate_random_ascii (&tmp_filename, N_TMP_FILENAME_RANDOM_BYTES)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + _dbus_string_free (&tmp_filename); + return FALSE; + } + + filename_c = _dbus_string_get_const_data (filename); + tmp_filename_c = _dbus_string_get_const_data (&tmp_filename); + + if (!_dbus_open_file (&file, tmp_filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT, + 0600)) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Could not create %s: %s", tmp_filename_c, + _dbus_strerror (errno)); + goto out; + } + + need_unlink = TRUE; + + total = 0; + bytes_to_write = _dbus_string_get_length (str); + + while (total < bytes_to_write) + { + int bytes_written; + + bytes_written = _dbus_write_file (&file, str, total, + bytes_to_write - total); + + if (bytes_written <= 0) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Could not write to %s: %s", tmp_filename_c, + _dbus_strerror (errno)); + + goto out; + } + + total += bytes_written; + } + + if (!_dbus_close_file (&file, NULL)) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Could not close file %s: %s", + tmp_filename_c, _dbus_strerror (errno)); + + goto out; + } + + + if ((unlink (filename_c) == -1 && errno != ENOENT) || + rename (tmp_filename_c, filename_c) < 0) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Could not rename %s to %s: %s", + tmp_filename_c, filename_c, + _dbus_strerror (errno)); + + goto out; + } + + need_unlink = FALSE; + + retval = TRUE; + +out: + /* close first, then unlink, to prevent ".nfs34234235" garbage + * files + */ + + if (_dbus_is_valid_file(&file)) + _dbus_close_file (&file, NULL); + + if (need_unlink && unlink (tmp_filename_c) < 0) + _dbus_verbose ("Failed to unlink temp file %s: %s\n", + tmp_filename_c, _dbus_strerror (errno)); + + _dbus_string_free (&tmp_filename); + + if (!retval) + _DBUS_ASSERT_ERROR_IS_SET (error); + + return retval; +} + + +/** Creates the given file, failing if the file already exists. + * + * @param filename the filename + * @param error error location + * @returns #TRUE if we created the file and it didn't exist + */ +dbus_bool_t +_dbus_create_file_exclusively (const DBusString *filename, + DBusError *error) +{ + DBusFile file; + const char *filename_c; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + filename_c = _dbus_string_get_const_data (filename); + + if (!_dbus_open_file (&file, filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT, + 0600)) + { + dbus_set_error (error, + DBUS_ERROR_FAILED, + "Could not create file %s: %s\n", + filename_c, + _dbus_strerror (errno)); + return FALSE; + } + + if (!_dbus_close_file (&file, NULL)) + { + dbus_set_error (error, + DBUS_ERROR_FAILED, + "Could not close file %s: %s\n", + filename_c, + _dbus_strerror (errno)); + return FALSE; + } + + return TRUE; +} + + +/** + * Creates a directory; succeeds if the directory + * is created or already existed. + * + * @param filename directory filename + * @param error initialized error object + * @returns #TRUE on success + */ +dbus_bool_t +_dbus_create_directory (const DBusString *filename, + DBusError *error) +{ + const char *filename_c; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + filename_c = _dbus_string_get_const_data (filename); + + if (_dbus_mkdir (filename_c, 0700) < 0) + { + if (errno == EEXIST) + return TRUE; + + dbus_set_error (error, DBUS_ERROR_FAILED, + "Failed to create directory %s: %s\n", + filename_c, _dbus_strerror (errno)); + return FALSE; + } + else + return TRUE; +} + + +static void +pseudorandom_generate_random_bytes_buffer (char *buffer, + int n_bytes) +{ + long tv_usec; + int i; + + /* fall back to pseudorandom */ + _dbus_verbose ("Falling back to pseudorandom for %d bytes\n", + n_bytes); + + _dbus_get_current_time (NULL, &tv_usec); + srand (tv_usec); + + i = 0; + while (i < n_bytes) + { + double r; + unsigned int b; + + r = rand (); + b = (r / (double) RAND_MAX) * 255.0; + + buffer[i] = b; + + ++i; + } +} + +static dbus_bool_t +pseudorandom_generate_random_bytes (DBusString *str, + int n_bytes) +{ + int old_len; + char *p; + + old_len = _dbus_string_get_length (str); + + if (!_dbus_string_lengthen (str, n_bytes)) + return FALSE; + + p = _dbus_string_get_data_len (str, old_len, n_bytes); + + pseudorandom_generate_random_bytes_buffer (p, n_bytes); + + return TRUE; +} + +/** + * Gets the temporary files directory by inspecting the environment variables + * TMPDIR, TMP, and TEMP in that order. If none of those are set "/tmp" is returned + * + * @returns location of temp directory + */ +const char* +_dbus_get_tmpdir(void) +{ + static const char* tmpdir = NULL; + + if (tmpdir == NULL) + { + if (tmpdir == NULL) + tmpdir = getenv("TMP"); + if (tmpdir == NULL) + tmpdir = getenv("TEMP"); + if (tmpdir == NULL) + tmpdir = getenv("TMPDIR"); + if (tmpdir == NULL) + tmpdir = "C:\\Temp"; + } + + _dbus_assert(tmpdir != NULL); + + return tmpdir; +} + + +/** + * Deletes the given file. + * + * @param filename the filename + * @param error error location + * + * @returns #TRUE if unlink() succeeded + */ +dbus_bool_t +_dbus_delete_file (const DBusString *filename, + DBusError *error) +{ + const char *filename_c; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + filename_c = _dbus_string_get_const_data (filename); + + if (unlink (filename_c) < 0) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Failed to delete file %s: %s\n", + filename_c, _dbus_strerror (errno)); + return FALSE; + } + else + return TRUE; +} + +/** + * Generates the given number of random bytes, + * using the best mechanism we can come up with. + * + * @param str the string + * @param n_bytes the number of random bytes to append to string + * @returns #TRUE on success, #FALSE if no memory + */ +dbus_bool_t +_dbus_generate_random_bytes (DBusString *str, + int n_bytes) +{ + return pseudorandom_generate_random_bytes (str, n_bytes); +} + +#if !defined (DBUS_DISABLE_ASSERT) || defined(DBUS_BUILD_TESTS) + +#ifdef _MSC_VER +# ifdef BACKTRACES +# undef BACKTRACES +# endif +#else +# define BACKTRACES +#endif + +#ifdef BACKTRACES +/* + * Backtrace Generator + * + * Copyright 2004 Eric Poech + * Copyright 2004 Robert Shearman + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include + +#define DPRINTF _dbus_warn + +#ifdef _MSC_VER +#define BOOL int + +#define __i386__ +#endif + +//#define MAKE_FUNCPTR(f) static typeof(f) * p##f + +//MAKE_FUNCPTR(StackWalk); +//MAKE_FUNCPTR(SymGetModuleBase); +//MAKE_FUNCPTR(SymFunctionTableAccess); +//MAKE_FUNCPTR(SymInitialize); +//MAKE_FUNCPTR(SymGetSymFromAddr); +//MAKE_FUNCPTR(SymGetModuleInfo); +static BOOL (WINAPI *pStackWalk)( + DWORD MachineType, + HANDLE hProcess, + HANDLE hThread, + LPSTACKFRAME StackFrame, + PVOID ContextRecord, + PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine, + PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine, + PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine, + PTRANSLATE_ADDRESS_ROUTINE TranslateAddress +); +static DWORD (WINAPI *pSymGetModuleBase)( + HANDLE hProcess, + DWORD dwAddr +); +static PVOID (WINAPI *pSymFunctionTableAccess)( + HANDLE hProcess, + DWORD AddrBase +); +static BOOL (WINAPI *pSymInitialize)( + HANDLE hProcess, + PSTR UserSearchPath, + BOOL fInvadeProcess +); +static BOOL (WINAPI *pSymGetSymFromAddr)( + HANDLE hProcess, + DWORD Address, + PDWORD Displacement, + PIMAGEHLP_SYMBOL Symbol +); +static BOOL (WINAPI *pSymGetModuleInfo)( + HANDLE hProcess, + DWORD dwAddr, + PIMAGEHLP_MODULE ModuleInfo +); +static DWORD (WINAPI *pSymSetOptions)( + DWORD SymOptions +); + + +static BOOL init_backtrace() +{ + HMODULE hmodDbgHelp = LoadLibraryA("dbghelp"); +/* + #define GETFUNC(x) \ + p##x = (typeof(x)*)GetProcAddress(hmodDbgHelp, #x); \ + if (!p##x) \ + { \ + return FALSE; \ + } + */ + + +// GETFUNC(StackWalk); +// GETFUNC(SymGetModuleBase); +// GETFUNC(SymFunctionTableAccess); +// GETFUNC(SymInitialize); +// GETFUNC(SymGetSymFromAddr); +// GETFUNC(SymGetModuleInfo); + +#define FUNC(x) #x + + pStackWalk = (BOOL (WINAPI *)( +DWORD MachineType, +HANDLE hProcess, +HANDLE hThread, +LPSTACKFRAME StackFrame, +PVOID ContextRecord, +PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine, +PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine, +PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine, +PTRANSLATE_ADDRESS_ROUTINE TranslateAddress +))GetProcAddress (hmodDbgHelp, FUNC(StackWalk)); + pSymGetModuleBase=(DWORD (WINAPI *)( + HANDLE hProcess, + DWORD dwAddr +))GetProcAddress (hmodDbgHelp, FUNC(SymGetModuleBase)); + pSymFunctionTableAccess=(PVOID (WINAPI *)( + HANDLE hProcess, + DWORD AddrBase +))GetProcAddress (hmodDbgHelp, FUNC(SymFunctionTableAccess)); + pSymInitialize = (BOOL (WINAPI *)( + HANDLE hProcess, + PSTR UserSearchPath, + BOOL fInvadeProcess +))GetProcAddress (hmodDbgHelp, FUNC(SymInitialize)); + pSymGetSymFromAddr = (BOOL (WINAPI *)( + HANDLE hProcess, + DWORD Address, + PDWORD Displacement, + PIMAGEHLP_SYMBOL Symbol +))GetProcAddress (hmodDbgHelp, FUNC(SymGetSymFromAddr)); + pSymGetModuleInfo = (BOOL (WINAPI *)( + HANDLE hProcess, + DWORD dwAddr, + PIMAGEHLP_MODULE ModuleInfo +))GetProcAddress (hmodDbgHelp, FUNC(SymGetModuleInfo)); +pSymSetOptions = (DWORD (WINAPI *)( +DWORD SymOptions +))GetProcAddress (hmodDbgHelp, FUNC(SymSetOptions)); + + + pSymSetOptions(SYMOPT_UNDNAME); + + pSymInitialize(GetCurrentProcess(), NULL, TRUE); + + return TRUE; +} + +static void dump_backtrace_for_thread(HANDLE hThread) +{ + STACKFRAME sf; + CONTEXT context; + DWORD dwImageType; + + if (!pStackWalk) + if (!init_backtrace()) + return; + + /* can't use this function for current thread as GetThreadContext + * doesn't support getting context from current thread */ + if (hThread == GetCurrentThread()) + return; + + DPRINTF("Backtrace:\n"); + + memset(&context, 0, sizeof(context)); + context.ContextFlags = CONTEXT_FULL; + + SuspendThread(hThread); + + if (!GetThreadContext(hThread, &context)) + { + DPRINTF("Couldn't get thread context (error %ld)\n", GetLastError()); + ResumeThread(hThread); + return; + } + + memset(&sf, 0, sizeof(sf)); + +#ifdef __i386__ + sf.AddrFrame.Offset = context.Ebp; + sf.AddrFrame.Mode = AddrModeFlat; + sf.AddrPC.Offset = context.Eip; + sf.AddrPC.Mode = AddrModeFlat; + dwImageType = IMAGE_FILE_MACHINE_I386; +#else +# error You need to fill in the STACKFRAME structure for your architecture +#endif + + while (pStackWalk(dwImageType, GetCurrentProcess(), + hThread, &sf, &context, NULL, pSymFunctionTableAccess, + pSymGetModuleBase, NULL)) + { + BYTE buffer[256]; + IMAGEHLP_SYMBOL * pSymbol = (IMAGEHLP_SYMBOL *)buffer; + DWORD dwDisplacement; + + pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL); + pSymbol->MaxNameLength = sizeof(buffer) - sizeof(IMAGEHLP_SYMBOL) + 1; + + if (!pSymGetSymFromAddr(GetCurrentProcess(), sf.AddrPC.Offset, + &dwDisplacement, pSymbol)) + { + IMAGEHLP_MODULE ModuleInfo; + ModuleInfo.SizeOfStruct = sizeof(ModuleInfo); + + if (!pSymGetModuleInfo(GetCurrentProcess(), sf.AddrPC.Offset, + &ModuleInfo)) + DPRINTF("1\t%p\n", (void*)sf.AddrPC.Offset); + else + DPRINTF("2\t%s+0x%lx\n", ModuleInfo.ImageName, + sf.AddrPC.Offset - ModuleInfo.BaseOfImage); + } + else if (dwDisplacement) + DPRINTF("3\t%s+0x%lx\n", pSymbol->Name, dwDisplacement); + else + DPRINTF("4\t%s\n", pSymbol->Name); + } + + ResumeThread(hThread); +} + +static DWORD WINAPI dump_thread_proc(LPVOID lpParameter) +{ + dump_backtrace_for_thread((HANDLE)lpParameter); + return 0; +} + +/* cannot get valid context from current thread, so we have to execute + * backtrace from another thread */ +static void dump_backtrace() +{ + HANDLE hCurrentThread; + HANDLE hThread; + DWORD dwThreadId; + DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), + GetCurrentProcess(), &hCurrentThread, 0, FALSE, DUPLICATE_SAME_ACCESS); + hThread = CreateThread(NULL, 0, dump_thread_proc, (LPVOID)hCurrentThread, + 0, &dwThreadId); + WaitForSingleObject(hThread, INFINITE); + CloseHandle(hThread); + CloseHandle(hCurrentThread); +} + +void _dbus_print_backtrace(void) +{ + init_backtrace(); + dump_backtrace(); +} +#else +void _dbus_print_backtrace(void) +{ + _dbus_verbose (" D-Bus not compiled with backtrace support\n"); +} +#endif + +/** + * Sends a single nul byte with our UNIX credentials as ancillary + * data. Returns #TRUE if the data was successfully written. On + * systems that don't support sending credentials, just writes a byte, + * doesn't send any credentials. On some systems, such as Linux, + * reading/writing the byte isn't actually required, but we do it + * anyway just to avoid multiple codepaths. + * + * Fails if no byte can be written, so you must select() first. + * + * The point of the byte is that on some systems we have to + * use sendmsg()/recvmsg() to transmit credentials. + * + * @param server_fd file descriptor for connection to server + * @param error return location for error code + * @returns #TRUE if the byte was sent + */ +dbus_bool_t +_dbus_send_credentials_unix_socket (int server_fd, + DBusError *error) +{ + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (write_credentials_byte (server_fd, error)) + return TRUE; + else + return FALSE; +} + +static dbus_uint32_t fromAscii(char ascii) +{ + if(ascii >= '0' && ascii <= '9') + return ascii - '0'; + if(ascii >= 'A' && ascii <= 'F') + return ascii - 'A' + 10; + if(ascii >= 'a' && ascii <= 'f') + return ascii - 'a' + 10; + return 0; +} + +dbus_bool_t _dbus_read_local_machine_uuid (DBusGUID *machine_id, + dbus_bool_t create_if_not_found, + DBusError *error) +{ +#ifdef DBUS_WINCE + return TRUE; + // TODO +#else + HW_PROFILE_INFOA info; + char *lpc = &info.szHwProfileGuid[0]; + dbus_uint32_t u; + + // the hw-profile guid lives long enough + if(!GetCurrentHwProfileA(&info)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); // FIXME + return FALSE; + } + + // Form: {12340001-4980-1920-6788-123456789012} + lpc++; + // 12340001 + u = ((fromAscii(lpc[0]) << 0) | + (fromAscii(lpc[1]) << 4) | + (fromAscii(lpc[2]) << 8) | + (fromAscii(lpc[3]) << 12) | + (fromAscii(lpc[4]) << 16) | + (fromAscii(lpc[5]) << 20) | + (fromAscii(lpc[6]) << 24) | + (fromAscii(lpc[7]) << 28)); + machine_id->as_uint32s[0] = u; + + lpc += 9; + // 4980-1920 + u = ((fromAscii(lpc[0]) << 0) | + (fromAscii(lpc[1]) << 4) | + (fromAscii(lpc[2]) << 8) | + (fromAscii(lpc[3]) << 12) | + (fromAscii(lpc[5]) << 16) | + (fromAscii(lpc[6]) << 20) | + (fromAscii(lpc[7]) << 24) | + (fromAscii(lpc[8]) << 28)); + machine_id->as_uint32s[1] = u; + + lpc += 10; + // 6788-1234 + u = ((fromAscii(lpc[0]) << 0) | + (fromAscii(lpc[1]) << 4) | + (fromAscii(lpc[2]) << 8) | + (fromAscii(lpc[3]) << 12) | + (fromAscii(lpc[5]) << 16) | + (fromAscii(lpc[6]) << 20) | + (fromAscii(lpc[7]) << 24) | + (fromAscii(lpc[8]) << 28)); + machine_id->as_uint32s[2] = u; + + lpc += 9; + // 56789012 + u = ((fromAscii(lpc[0]) << 0) | + (fromAscii(lpc[1]) << 4) | + (fromAscii(lpc[2]) << 8) | + (fromAscii(lpc[3]) << 12) | + (fromAscii(lpc[4]) << 16) | + (fromAscii(lpc[5]) << 20) | + (fromAscii(lpc[6]) << 24) | + (fromAscii(lpc[7]) << 28)); + machine_id->as_uint32s[3] = u; +#endif + return TRUE; +} + +static +HANDLE _dbus_global_lock (const char *mutexname) +{ + HANDLE mutex; + DWORD gotMutex; + + mutex = CreateMutex( NULL, FALSE, mutexname ); + if( !mutex ) + { + return FALSE; + } + + gotMutex = WaitForSingleObject( mutex, INFINITE ); + switch( gotMutex ) + { + case WAIT_ABANDONED: + ReleaseMutex (mutex); + CloseHandle (mutex); + return 0; + case WAIT_FAILED: + case WAIT_TIMEOUT: + return 0; + } + + return mutex; +} + +static +void _dbus_global_unlock (HANDLE mutex) +{ + ReleaseMutex (mutex); + CloseHandle (mutex); +} + +// for proper cleanup in dbus-daemon +static HANDLE hDBusDaemonMutex = NULL; +static HANDLE hDBusSharedMem = NULL; +// sync _dbus_daemon_init, _dbus_daemon_uninit and _dbus_daemon_already_runs +static const char *cUniqueDBusInitMutex = "UniqueDBusInitMutex"; +// sync _dbus_get_autolaunch_address +static const char *cDBusAutolaunchMutex = "DBusAutolaunchMutex"; +// mutex to determine if dbus-daemon is already started (per user) +static const char *cDBusDaemonMutex = "DBusDaemonMutex"; +// named shm for dbus adress info (per user) +static const char *cDBusDaemonAddressInfo = "DBusDaemonAddressInfo"; + +void +_dbus_daemon_init(const char *host, dbus_uint32_t port) +{ + HANDLE lock; + const char *adr = NULL; + char szUserName[64]; + DWORD dwUserNameSize = sizeof(szUserName); + char szDBusDaemonMutex[128]; + char szDBusDaemonAddressInfo[128]; + char szAddress[128]; + + _dbus_assert(host); + _dbus_assert(port); + + _snprintf(szAddress, sizeof(szAddress) - 1, "tcp:host=%s,port=%d", host, port); + + _dbus_assert( GetUserName(szUserName, &dwUserNameSize) != 0); + _snprintf(szDBusDaemonMutex, sizeof(szDBusDaemonMutex) - 1, "%s:%s", + cDBusDaemonMutex, szUserName); + _snprintf(szDBusDaemonAddressInfo, sizeof(szDBusDaemonAddressInfo) - 1, "%s:%s", + cDBusDaemonAddressInfo, szUserName); + + // before _dbus_global_lock to keep correct lock/release order + hDBusDaemonMutex = CreateMutex( NULL, FALSE, szDBusDaemonMutex ); + + _dbus_assert(WaitForSingleObject( hDBusDaemonMutex, 1000 ) == WAIT_OBJECT_0); + + // sync _dbus_daemon_init, _dbus_daemon_uninit and _dbus_daemon_already_runs + lock = _dbus_global_lock( cUniqueDBusInitMutex ); + + // create shm + hDBusSharedMem = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, + 0, strlen( szAddress ) + 1, szDBusDaemonAddressInfo ); + _dbus_assert( hDBusSharedMem ); + + adr = MapViewOfFile( hDBusSharedMem, FILE_MAP_WRITE, 0, 0, 0 ); + + _dbus_assert( adr ); + + strcpy(adr, szAddress); + + // cleanup + UnmapViewOfFile( adr ); + + _dbus_global_unlock( lock ); +} + +void +_dbus_daemon_release() +{ + HANDLE lock; + + // sync _dbus_daemon_init, _dbus_daemon_uninit and _dbus_daemon_already_runs + lock = _dbus_global_lock( cUniqueDBusInitMutex ); + + CloseHandle( hDBusSharedMem ); + + hDBusSharedMem = NULL; + + ReleaseMutex( hDBusDaemonMutex ); + + CloseHandle( hDBusDaemonMutex ); + + hDBusDaemonMutex = NULL; + + _dbus_global_unlock( lock ); +} + +static dbus_bool_t +_dbus_get_autolaunch_shm(DBusString *adress) +{ + HANDLE sharedMem; + const char *adr; + char szUserName[64]; + DWORD dwUserNameSize = sizeof(szUserName); + char szDBusDaemonAddressInfo[128]; + + if( !GetUserName(szUserName, &dwUserNameSize) ) + return FALSE; + _snprintf(szDBusDaemonAddressInfo, sizeof(szDBusDaemonAddressInfo) - 1, "%s:%s", + cDBusDaemonAddressInfo, szUserName); + + // read shm + do { + // we know that dbus-daemon is available, so we wait until shm is available + sharedMem = OpenFileMapping( FILE_MAP_READ, FALSE, szDBusDaemonAddressInfo ); + if( sharedMem == 0 ) + Sleep( 100 ); + } while( sharedMem == 0 ); + + if( sharedMem == 0 ) + return FALSE; + + adr = MapViewOfFile( sharedMem, FILE_MAP_READ, 0, 0, 0 ); + + if( adr == 0 ) + return FALSE; + + _dbus_string_init( adress ); + + _dbus_string_append( adress, adr ); + + // cleanup + UnmapViewOfFile( adr ); + + CloseHandle( sharedMem ); + + return TRUE; +} + +static dbus_bool_t +_dbus_daemon_already_runs (DBusString *adress) +{ + HANDLE lock; + HANDLE daemon; + dbus_bool_t bRet = TRUE; + char szUserName[64]; + DWORD dwUserNameSize = sizeof(szUserName); + char szDBusDaemonMutex[128]; + + // sync _dbus_daemon_init, _dbus_daemon_uninit and _dbus_daemon_already_runs + lock = _dbus_global_lock( cUniqueDBusInitMutex ); + + if( !GetUserName(szUserName, &dwUserNameSize) ) + return FALSE; + _snprintf(szDBusDaemonMutex, sizeof(szDBusDaemonMutex) - 1, "%s:%s", + cDBusDaemonMutex, szUserName); + + // do checks + daemon = CreateMutex( NULL, FALSE, szDBusDaemonMutex ); + if(WaitForSingleObject( daemon, 10 ) != WAIT_TIMEOUT) + { + ReleaseMutex (daemon); + CloseHandle (daemon); + + _dbus_global_unlock( lock ); + return FALSE; + } + + // read shm + bRet = _dbus_get_autolaunch_shm( adress ); + + // cleanup + CloseHandle ( daemon ); + + _dbus_global_unlock( lock ); + + return bRet; +} + +dbus_bool_t +_dbus_get_autolaunch_address (DBusString *address, + DBusError *error) +{ + HANDLE mutex; + STARTUPINFOA si; + PROCESS_INFORMATION pi; + dbus_bool_t retval = FALSE; + LPSTR lpFile; + char dbus_exe_path[MAX_PATH]; + char dbus_args[MAX_PATH * 2]; + + mutex = _dbus_global_lock ( cDBusAutolaunchMutex ); + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (_dbus_daemon_already_runs(address)) + { + printf("dbus daemon already exists\n"); + retval = TRUE; + goto out; + } + + if (!SearchPathA(NULL, "dbus-daemon.exe", NULL, sizeof(dbus_exe_path), dbus_exe_path, &lpFile)) + { + printf ("could not find dbus-daemon executable\n"); + goto out; + } + + // Create process + ZeroMemory( &si, sizeof(si) ); + si.cb = sizeof(si); + ZeroMemory( &pi, sizeof(pi) ); + + _snprintf(dbus_args, sizeof(dbus_args) - 1, "\"%s\" %s", dbus_exe_path, " --session"); + +// argv[i] = "--config-file=bus\\session.conf"; + printf("create process \"%s\" %s\n", dbus_exe_path, dbus_args); + if(CreateProcessA(dbus_exe_path, dbus_args, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) + { + retval = TRUE; + + // Wait until started (see _dbus_get_autolaunch_shm()) + WaitForInputIdle(pi.hProcess, INFINITE); + + retval = _dbus_get_autolaunch_shm( address ); + } else { + retval = FALSE; + } + +out: + if (retval) + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + else + _DBUS_ASSERT_ERROR_IS_SET (error); + + _dbus_global_unlock (mutex); + + return retval; + } + + +/** Makes the file readable by every user in the system. + * + * @param filename the filename + * @param error error location + * @returns #TRUE if the file's permissions could be changed. + */ +dbus_bool_t +_dbus_make_file_world_readable(const DBusString *filename, + DBusError *error) +{ + // TODO + return TRUE; +} + + +#define DBUS_STANDARD_SESSION_SERVICEDIR "/dbus-1/services" + +// @TODO: this function is duplicated from dbus-sysdeps-unix.c +// and differs only in the path separator, may be we should +// use a dbus path separator variable + +#define _dbus_path_seperator ";" + +static dbus_bool_t +split_paths_and_append (DBusString *dirs, + const char *suffix, + DBusList **dir_list) +{ + int start; + int i; + int len; + char *cpath; + const DBusString file_suffix; + + start = 0; + i = 0; + + _dbus_string_init_const (&file_suffix, suffix); + + len = _dbus_string_get_length (dirs); + + while (_dbus_string_find (dirs, start, _dbus_path_seperator, &i)) + { + DBusString path; + + if (!_dbus_string_init (&path)) + goto oom; + + if (!_dbus_string_copy_len (dirs, + start, + i - start, + &path, + 0)) + { + _dbus_string_free (&path); + goto oom; + } + + _dbus_string_chop_white (&path); + + /* check for an empty path */ + if (_dbus_string_get_length (&path) == 0) + goto next; + + if (!_dbus_concat_dir_and_file (&path, + &file_suffix)) + { + _dbus_string_free (&path); + goto oom; + } + + if (!_dbus_string_copy_data(&path, &cpath)) + { + _dbus_string_free (&path); + goto oom; + } + + if (!_dbus_list_append (dir_list, cpath)) + { + _dbus_string_free (&path); + dbus_free (cpath); + goto oom; + } + + next: + _dbus_string_free (&path); + start = i + 1; + } + + if (start != len) + { + DBusString path; + + if (!_dbus_string_init (&path)) + goto oom; + + if (!_dbus_string_copy_len (dirs, + start, + len - start, + &path, + 0)) + { + _dbus_string_free (&path); + goto oom; + } + + if (!_dbus_concat_dir_and_file (&path, + &file_suffix)) + { + _dbus_string_free (&path); + goto oom; + } + + if (!_dbus_string_copy_data(&path, &cpath)) + { + _dbus_string_free (&path); + goto oom; + } + + if (!_dbus_list_append (dir_list, cpath)) + { + _dbus_string_free (&path); + dbus_free (cpath); + goto oom; + } + + _dbus_string_free (&path); + } + + return TRUE; + + oom: + _dbus_list_foreach (dir_list, (DBusForeachFunction)dbus_free, NULL); + _dbus_list_clear (dir_list); + return FALSE; +} + +/** + * Returns the standard directories for a session bus to look for service + * activation files + * + * On Windows this should be data directories: + * + * %CommonProgramFiles%/dbus + * + * and + * + * DBUS_DATADIR + * + * @param dirs the directory list we are returning + * @returns #FALSE on OOM + */ + +dbus_bool_t +_dbus_get_standard_session_servicedirs (DBusList **dirs) +{ + const char *common_progs; + DBusString servicedir_path; + + if (!_dbus_string_init (&servicedir_path)) + return FALSE; + + if (!_dbus_string_append (&servicedir_path, DBUS_DATADIR";")) + goto oom; + + common_progs = _dbus_getenv ("CommonProgramFiles"); + + if (common_progs != NULL) + { + if (!_dbus_string_append (&servicedir_path, common_progs)) + goto oom; + + if (!_dbus_string_append (&servicedir_path, ";")) + goto oom; + } + + if (!split_paths_and_append (&servicedir_path, + DBUS_STANDARD_SESSION_SERVICEDIR, + dirs)) + goto oom; + + _dbus_string_free (&servicedir_path); + return TRUE; + + oom: + _dbus_string_free (&servicedir_path); + return FALSE; +} + +_DBUS_DEFINE_GLOBAL_LOCK (atomic); + +/** + * Atomically increments an integer + * + * @param atomic pointer to the integer to increment + * @returns the value before incrementing + * + */ +dbus_int32_t +_dbus_atomic_inc (DBusAtomic *atomic) +{ + // +/- 1 is needed here! + return InterlockedIncrement (&atomic->value) - 1; +} + +/** + * Atomically decrement an integer + * + * @param atomic pointer to the integer to decrement + * @returns the value before decrementing + * + */ +dbus_int32_t +_dbus_atomic_dec (DBusAtomic *atomic) +{ + // +/- 1 is needed here! + return InterlockedDecrement (&atomic->value) + 1; +} + +#endif /* asserts or tests enabled */ + +/** @} end of sysdeps-win */ + +/* tests in dbus-sysdeps-util.c */ -- cgit