[daemon-fix] Fixed sending daemon match rules for kdbus broadcasts
[platform/upstream/dbus.git] / dbus / dbus-sysdeps-util-win.c
index 3b308f8..4678b11 100644 (file)
@@ -1,4 +1,4 @@
-/* -*- mode: C; c-file-style: "gnu" -*- */
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 /* dbus-sysdeps-util.c Would be in dbus-sysdeps.c, but not used in libdbus
  * 
  * Copyright (C) 2002, 2003, 2004, 2005  Red Hat, Inc.
  * 
  * 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
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
 
-#undef open
+#include <config.h>
 
 #define STRSAFE_NO_DEPRECATE
 
 #include "dbus-string.h"
 #include "dbus-sysdeps.h"
 #include "dbus-sysdeps-win.h"
+#include "dbus-sockets-win.h"
 #include "dbus-memory.h"
-
-#include <io.h>
-#include <sys/stat.h>
-#include <aclapi.h>
+#include "dbus-pipe.h"
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <fcntl.h>
-
-#ifdef __MINGW32__
-/* save string functions version
-   using DBusString needs to much time because of uncommon api 
-*/ 
-#define errno_t int
-
-errno_t strcat_s(char *dest, int size, char *src) 
-{
-  _dbus_assert(strlen(dest) + strlen(src) +1 <= size);
-  strcat(dest,src);
-  return 0;
-}
-
-errno_t strcpy_s(char *dest, int size, char *src)
-{
-  _dbus_assert(strlen(src) +1 <= size);
-  strcpy(dest,src);  
-  return 0;
-}
+#if HAVE_ERRNO_H
+#include <errno.h>
 #endif
+#include <winsock2.h>   // WSA error codes
 
-/**
- * return the absolute path of the dbus installation 
- *
- * @param s buffer for installation path
- * @param len length of buffer
- * @returns #FALSE on failure
- */
-dbus_bool_t 
-_dbus_get_install_root(char *s, int len)
-{
-  char *p = NULL;
-  int ret = GetModuleFileName(NULL,s,len);
-  if ( ret == 0 
-    || ret == len && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
-    {
-      *s = '\0';
-      return FALSE;
-    }
-  else if ((p = strstr(s,"\\bin\\")))
-    {
-      *(p+1)= '\0';
-      return TRUE;
-    }
-  else
-    {
-      *s = '\0';
-      return FALSE;
-    }
-}
-
-/* 
-  find session.conf either from installation or build root according to 
-  the following path layout 
-    install-root/
-      bin/dbus-daemon[d].exe
-      etc/session.conf 
-
-    build-root/
-      bin/dbus-daemon[d].exe
-      bus/session.conf 
-*/             
-dbus_bool_t 
-_dbus_get_config_file_name(DBusString *config_file, char *s)
-{
-  char path[MAX_PATH*2];
-  int path_size = sizeof(path);
+#ifndef DBUS_WINCE
+#include <io.h>
+#include <lm.h>
+#include <sys/stat.h>
+#endif
 
-  if (!_dbus_get_install_root(path,path_size))
-    return FALSE;
 
-  strcat_s(path,path_size,"etc\\");
-  strcat_s(path,path_size,s);
-  if (_dbus_file_exists(path)) 
-    {
-      // find path from executable 
-      if (!_dbus_string_append (config_file, path))
-        return FALSE;
-    }
-  else 
-    {
-      if (!_dbus_get_install_root(path,path_size))
-        return FALSE;
-      strcat_s(path,path_size,"bus\\");
-      strcat_s(path,path_size,s);
-  
-      if (_dbus_file_exists(path)) 
-        {
-          if (!_dbus_string_append (config_file, path))
-            return FALSE;
-        }
-    }
-  return TRUE;
-}    
-    
 /**
  * Does the chdir, fork, setsid, etc. to become a daemon process.
  *
  * @param pidfile #NULL, or pidfile to create
- * @param print_pid_fd file descriptor to print daemon's pid to, or -1 for none
+ * @param print_pid_pipe file descriptor to print daemon's pid to, or -1 for none
  * @param error return location for errors
+ * @param keep_umask #TRUE to keep the original umask
  * @returns #FALSE on failure
  */
 dbus_bool_t
 _dbus_become_daemon (const DBusString *pidfile,
                      DBusPipe         *print_pid_pipe,
-                     DBusError        *error)
+                     DBusError        *error,
+                     dbus_bool_t       keep_umask)
 {
-  return TRUE;
+  dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED,
+                  "Cannot daemonize on Windows");
+  return FALSE;
 }
 
 /**
@@ -161,48 +78,76 @@ _dbus_become_daemon (const DBusString *pidfile,
  * @param error return location for errors
  * @returns #FALSE on failure
  */
-dbus_bool_t
+static dbus_bool_t
 _dbus_write_pid_file (const DBusString *filename,
                       unsigned long     pid,
                       DBusError        *error)
 {
   const char *cfilename;
-  DBusFile file;
-  FILE *f;
+  HANDLE hnd;
+  char pidstr[20];
+  int total;
+  int bytes_to_write;
+
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
   cfilename = _dbus_string_get_const_data (filename);
 
-  if (!_dbus_file_open(&file, cfilename, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644))
+  hnd = CreateFileA (cfilename, GENERIC_WRITE,
+                     FILE_SHARE_READ | FILE_SHARE_WRITE,
+                     NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL,
+                     INVALID_HANDLE_VALUE);
+  if (hnd == INVALID_HANDLE_VALUE)
     {
-      dbus_set_error (error, _dbus_error_from_errno (errno),
-                      "Failed to open \"%s\": %s", cfilename,
-                      _dbus_strerror (errno));
+      char *emsg = _dbus_win_error_string (GetLastError ());
+      dbus_set_error (error, _dbus_win_error_from_last_error (),
+                      "Could not create PID file %s: %s",
+                      cfilename, emsg);
+      _dbus_win_free_error_string (emsg);
       return FALSE;
     }
 
-  if ((f = fdopen (file.FDATA, "w")) == NULL)
+  if (snprintf (pidstr, sizeof (pidstr), "%lu\n", pid) < 0)
     {
-      dbus_set_error (error, _dbus_error_from_errno (errno),
-                      "Failed to fdopen fd %d: %s", file.FDATA, _dbus_strerror (errno));
-      _dbus_file_close (&file, NULL);
+      dbus_set_error (error, _dbus_error_from_system_errno (),
+                      "Failed to format PID for \"%s\": %s", cfilename,
+                      _dbus_strerror_from_errno ());
+      CloseHandle (hnd);
       return FALSE;
     }
 
-  if (fprintf (f, "%lu\n", pid) < 0)
+  total = 0;
+  bytes_to_write = strlen (pidstr);;
+
+  while (total < bytes_to_write)
     {
-      dbus_set_error (error, _dbus_error_from_errno (errno),
-                      "Failed to write to \"%s\": %s", cfilename,
-                      _dbus_strerror (errno));
+      DWORD bytes_written;
+      BOOL res;
 
-      fclose (f);
-      return FALSE;
+      res = WriteFile (hnd, pidstr + total, bytes_to_write - total,
+                       &bytes_written, NULL);
+
+      if (res == 0 || bytes_written <= 0)
+        {
+          char *emsg = _dbus_win_error_string (GetLastError ());
+          dbus_set_error (error, _dbus_win_error_from_last_error (),
+                           "Could not write to %s: %s", cfilename, emsg);
+          _dbus_win_free_error_string (emsg);
+          CloseHandle (hnd);
+          return FALSE;
+        }
+
+      total += bytes_written;
     }
 
-  if (fclose (f) == EOF)
+  if (CloseHandle (hnd) == 0)
     {
-      dbus_set_error (error, _dbus_error_from_errno (errno),
-                      "Failed to close \"%s\": %s", cfilename,
-                      _dbus_strerror (errno));
+      char *emsg = _dbus_win_error_string (GetLastError ());
+      dbus_set_error (error, _dbus_win_error_from_last_error (),
+                       "Could not close file %s: %s",
+                      cfilename, emsg);
+      _dbus_win_free_error_string (emsg);
+
       return FALSE;
     }
 
@@ -210,132 +155,167 @@ _dbus_write_pid_file (const DBusString *filename,
 }
 
 /**
- * Changes the user and group the bus is running as.
+ * Writes the given pid_to_write to a pidfile (if non-NULL) and/or to a
+ * pipe (if non-NULL). Does nothing if pidfile and print_pid_pipe are both
+ * NULL.
  *
- * @param uid the new user ID
- * @param gid the new group ID
- * @param error return location for errors
- * @returns #FALSE on failure
+ * @param pidfile the file to write to or #NULL
+ * @param print_pid_pipe the pipe to write to or #NULL
+ * @param pid_to_write the pid to write out
+ * @param error error on failure
+ * @returns FALSE if error is set
  */
 dbus_bool_t
-_dbus_change_identity  (dbus_uid_t     uid,
-                        dbus_gid_t     gid,
-                        DBusError     *error)
-{
-  return TRUE;
-}
-
-/** Checks if user is at the console
-*
-* @param username user to check
-* @param error return location for errors
-* @returns #TRUE is the user is at the consolei and there are no errors
-*/
-dbus_bool_t
-_dbus_user_at_console(const char *username,
-                      DBusError  *error)
+_dbus_write_pid_to_file_and_pipe (const DBusString *pidfile,
+                                  DBusPipe         *print_pid_pipe,
+                                  dbus_pid_t        pid_to_write,
+                                  DBusError        *error)
 {
-#ifdef DBUS_WINCE
-       return TRUE;
-#else
-  dbus_bool_t retval = FALSE;
-  wchar_t *wusername;
-  DWORD sid_length;
-  PSID user_sid, console_user_sid;
-  HWINSTA winsta;
-
-  wusername = _dbus_win_utf8_to_utf16 (username, error);
-  if (!wusername)
-    return FALSE;
-
-  if (!_dbus_win_account_to_sid (wusername, &user_sid, error))
-    goto out0;
-
-  /* Now we have the SID for username. Get the SID of the
-   * user at the "console" (window station WinSta0)
-   */
-  if (!(winsta = OpenWindowStation ("WinSta0", FALSE, READ_CONTROL)))
+  if (pidfile)
     {
-      _dbus_win_set_error_from_win_error (error, GetLastError ());
-      goto out2;
+      _dbus_verbose ("writing pid file %s\n", _dbus_string_get_const_data (pidfile));
+      if (!_dbus_write_pid_file (pidfile,
+                                 pid_to_write,
+                                 error))
+        {
+          _dbus_verbose ("pid file write failed\n");
+          _DBUS_ASSERT_ERROR_IS_SET(error);
+          return FALSE;
+        }
     }
-
-  sid_length = 0;
-  GetUserObjectInformation (winsta, UOI_USER_SID,
-                            NULL, 0, &sid_length);
-  if (sid_length == 0)
+  else
     {
-      /* Nobody is logged on */
-      goto out2;
+      _dbus_verbose ("No pid file requested\n");
     }
 
-  if (sid_length < 0 || sid_length > 1000)
+  if (print_pid_pipe != NULL && _dbus_pipe_is_valid (print_pid_pipe))
     {
-      dbus_set_error_const (error, DBUS_ERROR_FAILED, "Invalid SID length");
-      goto out3;
-    }
+      DBusString pid;
+      int bytes;
 
-  console_user_sid = dbus_malloc (sid_length);
-  if (!console_user_sid)
-    {
-      _DBUS_SET_OOM (error);
-      goto out3;
-    }
+      _dbus_verbose ("writing our pid to pipe %d\n", print_pid_pipe->fd);
 
-  if (!GetUserObjectInformation (winsta, UOI_USER_SID,
-                                 console_user_sid, sid_length, &sid_length))
-    {
-      _dbus_win_set_error_from_win_error (error, GetLastError ());
-      goto out4;
-    }
+      if (!_dbus_string_init (&pid))
+        {
+          _DBUS_SET_OOM (error);
+          return FALSE;
+        }
+
+      if (!_dbus_string_append_int (&pid, pid_to_write) ||
+          !_dbus_string_append (&pid, "\n"))
+        {
+          _dbus_string_free (&pid);
+          _DBUS_SET_OOM (error);
+          return FALSE;
+        }
+
+      bytes = _dbus_string_get_length (&pid);
+      if (_dbus_pipe_write (print_pid_pipe, &pid, 0, bytes, error) != bytes)
+        {
+          /* _dbus_pipe_write sets error only on failure, not short write */
+          if (error != NULL && !dbus_error_is_set(error))
+            {
+              dbus_set_error (error, DBUS_ERROR_FAILED,
+                              "Printing message bus PID: did not write enough bytes\n");
+            }
+          _dbus_string_free (&pid);
+          return FALSE;
+        }
 
-  if (!IsValidSid (console_user_sid))
+      _dbus_string_free (&pid);
+    }
+  else
     {
-      dbus_set_error_const (error, DBUS_ERROR_FAILED, "Invalid SID");
-      goto out4;
+      _dbus_verbose ("No pid pipe to write to\n");
     }
 
-  retval = EqualSid (user_sid, console_user_sid);
-
-out4:
-  dbus_free (console_user_sid);
-out3:
-  CloseWindowStation (winsta);
-out2:
-  dbus_free (user_sid);
-out0:
-  dbus_free (wusername);
+  return TRUE;
+}
 
-  return retval;
-#endif //DBUS_WINCE
+/**
+ * Verify that after the fork we can successfully change to this user.
+ *
+ * @param user the username given in the daemon configuration
+ * @returns #TRUE if username is valid
+ */
+dbus_bool_t
+_dbus_verify_daemon_user (const char *user)
+{
+  return TRUE;
 }
 
 /**
- * Removes a directory; Directory must be empty
- * 
- * @param filename directory filename
- * @param error initialized error object
- * @returns #TRUE on success
+ * Changes the user and group the bus is running as.
+ *
+ * @param user the user to become
+ * @param error return location for errors
+ * @returns #FALSE on failure
  */
 dbus_bool_t
-_dbus_delete_directory (const DBusString *filename,
-                        DBusError        *error)
+_dbus_change_to_daemon_user  (const char    *user,
+                              DBusError     *error)
 {
-  const char *filename_c;
+  return TRUE;
+}
 
-  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+void
+_dbus_request_file_descriptor_limit (unsigned int limit)
+{
+}
 
-  filename_c = _dbus_string_get_const_data (filename);
+void
+_dbus_init_system_log (dbus_bool_t is_daemon)
+{
+  /* OutputDebugStringA doesn't need any special initialization, do nothing */
+}
 
-  if (rmdir (filename_c) != 0)
-    {
-      dbus_set_error (error, DBUS_ERROR_FAILED,
-                      "Failed to remove directory %s: %s\n",
-                      filename_c, _dbus_strerror (errno));
-      return FALSE;
-    }
+/**
+ * Log a message to the system log file (e.g. syslog on Unix).
+ *
+ * @param severity a severity value
+ * @param msg a printf-style format string
+ */
+void
+_dbus_system_log (DBusSystemLogSeverity severity, const char *msg, ...)
+{
+  va_list args;
 
-  return TRUE;
+  va_start (args, msg);
+
+  _dbus_system_logv (severity, msg, args);
+
+  va_end (args);
+}
+
+/**
+ * Log a message to the system log file (e.g. syslog on Unix).
+ *
+ * @param severity a severity value
+ * @param msg a printf-style format string
+ * @param args arguments for the format string
+ *
+ * If the FATAL severity is given, this function will terminate the program
+ * with an error code.
+ */
+void
+_dbus_system_logv (DBusSystemLogSeverity severity, const char *msg, va_list args)
+{
+  char *s = "";
+  char buf[1024];
+  
+  switch(severity) 
+   {
+     case DBUS_SYSTEM_LOG_INFO: s = "info"; break;
+     case DBUS_SYSTEM_LOG_SECURITY: s = "security"; break;
+     case DBUS_SYSTEM_LOG_FATAL: s = "fatal"; break;
+   }
+   
+  sprintf(buf,"%s%s",s,msg);
+  vsprintf(buf,buf,args);
+  OutputDebugStringA(buf);
+  
+  if (severity == DBUS_SYSTEM_LOG_FATAL)
+    exit (1);
 }
 
 /** Installs a signal handler
@@ -350,34 +330,6 @@ _dbus_set_signal_handler (int               sig,
   _dbus_verbose ("_dbus_set_signal_handler() has to be implemented\n");
 }
 
-/** Checks if a file exists
-*
-* @param file full path to the file
-* @returns #TRUE if file exists
-*/
-dbus_bool_t 
-_dbus_file_exists (const char *file)
-{
-  HANDLE h = CreateFile(
-          file, /* LPCTSTR lpFileName*/
-          0, /* DWORD dwDesiredAccess */
-          0, /* DWORD dwShareMode*/
-          NULL, /* LPSECURITY_ATTRIBUTES lpSecurityAttributes */
-          OPEN_EXISTING, /* DWORD dwCreationDisposition */
-          FILE_ATTRIBUTE_NORMAL, /* DWORD dwFlagsAndAttributes */
-          NULL /* HANDLE hTemplateFile */
-        );
-
-    /* file not found, use local copy of session.conf  */
-    if (h != INVALID_HANDLE_VALUE && GetLastError() != ERROR_PATH_NOT_FOUND)
-      {
-        CloseHandle(h);
-        return TRUE;
-      }
-    else
-        return FALSE;  
-}
-
 /**
  * stat() wrapper.
  *
@@ -391,28 +343,16 @@ _dbus_stat(const DBusString *filename,
            DBusStat         *statbuf,
            DBusError        *error)
 {
-#ifdef DBUS_WINCE
-       return TRUE;
-       //TODO
-#else
   const char *filename_c;
-#if !defined(DBUS_WIN) && !defined(DBUS_WINCE)
-
-  struct stat sb;
-#else
-
   WIN32_FILE_ATTRIBUTE_DATA wfad;
   char *lastdot;
   DWORD rc;
-  PSID owner_sid, group_sid;
-  PSECURITY_DESCRIPTOR sd;
-#endif
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
   filename_c = _dbus_string_get_const_data (filename);
 
-  if (!GetFileAttributesEx (filename_c, GetFileExInfoStandard, &wfad))
+  if (!GetFileAttributesExA (filename_c, GetFileExInfoStandard, &wfad))
     {
       _dbus_win_set_error_from_win_error (error, GetLastError ());
       return FALSE;
@@ -436,25 +376,36 @@ _dbus_stat(const DBusString *filename,
 
   statbuf->nlink = 1;
 
-  sd = NULL;
-  rc = GetNamedSecurityInfo ((char *) filename_c, SE_FILE_OBJECT,
-                             OWNER_SECURITY_INFORMATION |
-                             GROUP_SECURITY_INFORMATION,
-                             &owner_sid, &group_sid,
-                             NULL, NULL,
-                             &sd);
-  if (rc != ERROR_SUCCESS)
-    {
-      _dbus_win_set_error_from_win_error (error, rc);
-      if (sd != NULL)
-        LocalFree (sd);
-      return FALSE;
-    }
-
-  statbuf->uid = _dbus_win_sid_to_uid_t (owner_sid);
-  statbuf->gid = _dbus_win_sid_to_uid_t (group_sid);
+#ifdef ENABLE_UID_TO_SID
+  {
+    PSID owner_sid, group_sid;
+    PSECURITY_DESCRIPTOR sd;
+
+    sd = NULL;
+    rc = GetNamedSecurityInfo ((char *) filename_c, SE_FILE_OBJECT,
+                               OWNER_SECURITY_INFORMATION |
+                               GROUP_SECURITY_INFORMATION,
+                               &owner_sid, &group_sid,
+                               NULL, NULL,
+                               &sd);
+    if (rc != ERROR_SUCCESS)
+      {
+        _dbus_win_set_error_from_win_error (error, rc);
+        if (sd != NULL)
+          LocalFree (sd);
+        return FALSE;
+      }
+    
+    /* FIXME */
+    statbuf->uid = _dbus_win_sid_to_uid_t (owner_sid);
+    statbuf->gid = _dbus_win_sid_to_uid_t (group_sid);
 
-  LocalFree (sd);
+    LocalFree (sd);
+  }
+#else
+  statbuf->uid = DBUS_UID_UNSET;
+  statbuf->gid = DBUS_GID_UNSET;
+#endif
 
   statbuf->size = ((dbus_int64_t) wfad.nFileSizeHigh << 32) + wfad.nFileSizeLow;
 
@@ -471,27 +422,9 @@ _dbus_stat(const DBusString *filename,
      wfad.ftCreationTime.dwLowDateTime) / 10000000 - DBUS_INT64_CONSTANT (116444736000000000);
 
   return TRUE;
-#endif //DBUS_WINCE
 }
 
 
-#ifdef HAVE_DIRENT_H
-
-// mingw ships with dirent.h
-#include <dirent.h>
-#define _dbus_opendir opendir
-#define _dbus_readdir readdir
-#define _dbus_closedir closedir
-
-#else
-
-#ifdef HAVE_IO_H
-#include <io.h> // win32 file functions
-#endif
-
-#include <sys/types.h>
-#include <stdlib.h>
-
 /* This file is part of the KDE project
 Copyright (C) 2000 Werner Almesberger
 
@@ -531,10 +464,10 @@ struct dirent
 /* typedef DIR - not the same as Unix */
 typedef struct
   {
-    long handle;                /* _findfirst/_findnext handle */
-    short offset;                /* offset into directory */
+    HANDLE handle;              /* FindFirst/FindNext handle */
+    short offset;               /* offset into directory */
     short finished;             /* 1 if there are not more files */
-    struct _finddata_t fileinfo;  /* from _findfirst/_findnext */
+    WIN32_FIND_DATAA fileinfo;  /* from FindFirst/FindNext */
     char *dir;                  /* the dir we are reading */
     struct dirent dent;         /* the dirent to return */
   }
@@ -550,14 +483,16 @@ DIR;
 * The dirent struct is compatible with Unix, except that d_ino is
 * always 1 and d_off is made up as we go along.
 *
+* Error codes are not available with errno but GetLastError.
+*
 * The DIR typedef is not compatible with Unix.
 **********************************************************************/
 
-DIR * _dbus_opendir(const char *dir)
+static DIR * _dbus_opendir(const char *dir)
 {
   DIR *dp;
   char *filespec;
-  long handle;
+  HANDLE handle;
   int index;
 
   filespec = malloc(strlen(dir) + 2 + 1);
@@ -572,9 +507,10 @@ DIR * _dbus_opendir(const char *dir)
   dp->finished = 0;
   dp->dir = strdup(dir);
 
-  if ((handle = _findfirst(filespec, &(dp->fileinfo))) < 0)
+  handle = FindFirstFileA(filespec, &(dp->fileinfo));
+  if (handle == INVALID_HANDLE_VALUE)
     {
-      if (errno == ENOENT)
+      if (GetLastError() == ERROR_NO_MORE_FILES)
         dp->finished = 1;
       else
         return NULL;
@@ -586,36 +522,41 @@ DIR * _dbus_opendir(const char *dir)
   return dp;
 }
 
-struct dirent * _dbus_readdir(DIR *dp)
-  {
-    if (!dp || dp->finished)
-      return NULL;
-
-    if (dp->offset != 0)
-      {
-        if (_findnext(dp->handle, &(dp->fileinfo)) < 0)
-          {
-            dp->finished = 1;
-            errno = 0;
-            return NULL;
-          }
-      }
-    dp->offset++;
+static struct dirent * _dbus_readdir(DIR *dp)
+{
+  int saved_err = GetLastError();
 
-    strncpy(dp->dent.d_name, dp->fileinfo.name, _MAX_FNAME);
-    dp->dent.d_ino = 1;
-    dp->dent.d_reclen = strlen(dp->dent.d_name);
-    dp->dent.d_off = dp->offset;
+  if (!dp || dp->finished)
+    return NULL;
 
-    return &(dp->dent);
-  }
+  if (dp->offset != 0)
+    {
+      if (FindNextFileA(dp->handle, &(dp->fileinfo)) == 0)
+        {
+          if (GetLastError() == ERROR_NO_MORE_FILES)
+            {
+              SetLastError(saved_err);
+              dp->finished = 1;
+            }
+          return NULL;
+        }
+    }
+  dp->offset++;
+  
+  strncpy(dp->dent.d_name, dp->fileinfo.cFileName, _MAX_FNAME);
+  dp->dent.d_ino = 1;
+  dp->dent.d_reclen = strlen(dp->dent.d_name);
+  dp->dent.d_off = dp->offset;
+  
+  return &(dp->dent);
+}
 
 
-int _dbus_closedir(DIR *dp)
+static int _dbus_closedir(DIR *dp)
 {
   if (!dp)
     return 0;
-  _findclose(dp->handle);
+  FindClose(dp->handle);
   if (dp->dir)
     free(dp->dir);
   if (dp)
@@ -624,7 +565,6 @@ int _dbus_closedir(DIR *dp)
   return 0;
 }
 
-#endif //#ifdef HAVE_DIRENT_H
 
 /**
  * Internals of directory iterator
@@ -657,10 +597,11 @@ _dbus_directory_open (const DBusString *filename,
   d = _dbus_opendir (filename_c);
   if (d == NULL)
     {
-      dbus_set_error (error, _dbus_error_from_errno (errno),
+      char *emsg = _dbus_win_error_string (GetLastError ());
+      dbus_set_error (error, _dbus_win_error_from_last_error (),
                       "Failed to read directory \"%s\": %s",
-                      filename_c,
-                      _dbus_strerror (errno));
+                      filename_c, emsg);
+      _dbus_win_free_error_string (emsg);
       return NULL;
     }
   iter = dbus_new0 (DBusDirIter, 1);
@@ -700,14 +641,17 @@ _dbus_directory_get_next_file (DBusDirIter      *iter,
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
 again:
-  errno = 0;
+  SetLastError (0);
   ent = _dbus_readdir (iter->d);
   if (ent == NULL)
     {
-      if (errno != 0)
-        dbus_set_error (error,
-                        _dbus_error_from_errno (errno),
-                        "%s", _dbus_strerror (errno));
+      if (GetLastError() != 0)
+        {
+          char *emsg = _dbus_win_error_string (GetLastError ());
+          dbus_set_error (error, _dbus_win_error_from_last_error (),
+                          "Failed to get next in directory: %s", emsg);
+          _dbus_win_free_error_string (emsg);
+        }
       return FALSE;
     }
   else if (ent->d_name[0] == '.' &&
@@ -738,135 +682,6 @@ _dbus_directory_close (DBusDirIter *iter)
   dbus_free (iter);
 }
 
-/**
- * Checks whether the filename is an absolute path
- *
- * @param filename the filename
- * @returns #TRUE if an absolute path
- */
-dbus_bool_t
-_dbus_path_is_absolute (const DBusString *filename)
-{
-  if (_dbus_string_get_length (filename) > 0)
-    return _dbus_string_get_byte (filename, 1) == ':'
-           || _dbus_string_get_byte (filename, 0) == '\\'
-           || _dbus_string_get_byte (filename, 0) == '/';
-  else
-    return FALSE;
-}
-
-
-static dbus_bool_t
-fill_group_info(DBusGroupInfo    *info,
-                dbus_gid_t        gid,
-                const DBusString *groupname,
-                DBusError        *error)
-{
-  const char *group_c_str;
-
-  _dbus_assert (groupname != NULL || gid != DBUS_GID_UNSET);
-  _dbus_assert (groupname == NULL || gid == DBUS_GID_UNSET);
-
-  if (groupname)
-    group_c_str = _dbus_string_get_const_data (groupname);
-  else
-    group_c_str = NULL;
-
-  if (group_c_str)
-    {
-      PSID group_sid;
-      wchar_t *wgroupname = _dbus_win_utf8_to_utf16 (group_c_str, error);
-
-      if (!wgroupname)
-        return FALSE;
-
-      if (!_dbus_win_account_to_sid (wgroupname, &group_sid, error))
-        {
-          dbus_free (wgroupname);
-          return FALSE;
-        }
-
-      info->gid = _dbus_win_sid_to_uid_t (group_sid);
-      info->groupname = _dbus_strdup (group_c_str);
-
-      dbus_free (group_sid);
-      dbus_free (wgroupname);
-
-      return TRUE;
-    }
-  else
-    {
-      dbus_bool_t retval = FALSE;
-      wchar_t *wname, *wdomain;
-      char *name, *domain;
-
-      info->gid = gid;
-
-      if (!_dbus_win_sid_to_name_and_domain (gid, &wname, &wdomain, error))
-        return FALSE;
-
-      name = _dbus_win_utf16_to_utf8 (wname, error);
-      if (!name)
-        goto out0;
-
-      domain = _dbus_win_utf16_to_utf8 (wdomain, error);
-      if (!domain)
-        goto out1;
-
-      info->groupname = dbus_malloc (strlen (domain) + 1 + strlen (name) + 1);
-
-      strcpy (info->groupname, domain);
-      strcat (info->groupname, "\\");
-      strcat (info->groupname, name);
-
-      retval = TRUE;
-
-      dbus_free (domain);
-out1:
-      dbus_free (name);
-out0:
-      dbus_free (wname);
-      dbus_free (wdomain);
-
-      return retval;
-    }
-}
-
-/**
- * Initializes the given DBusGroupInfo struct
- * with information about the given group ID.
- *
- * @param info the group info struct
- * @param gid group ID
- * @param error the error return
- * @returns #FALSE if error is set
- */
-dbus_bool_t
-_dbus_group_info_fill_gid (DBusGroupInfo *info,
-                           dbus_gid_t     gid,
-                           DBusError     *error)
-{
-  return fill_group_info (info, gid, NULL, error);
-}
-
-/**
- * Initializes the given DBusGroupInfo struct
- * with information about the given group name.
- *
- * @param info the group info struct
- * @param groupname name of group
- * @param error the error return
- * @returns #FALSE if error is set
- */
-dbus_bool_t
-_dbus_group_info_fill (DBusGroupInfo    *info,
-                       const DBusString *groupname,
-                       DBusError        *error)
-{
-  return fill_group_info (info, DBUS_GID_UNSET,
-                          groupname, error);
-}
-
 /** @} */ /* End of DBusInternalsUtils functions */
 
 /**
@@ -940,5 +755,982 @@ _dbus_string_get_dirname(const DBusString *filename,
                                   dirname, _dbus_string_get_length (dirname));
 }
 
+
+/**
+ * Checks to see if the UNIX user ID matches the UID of
+ * the process. Should always return #FALSE on Windows.
+ *
+ * @param uid the UNIX user ID
+ * @returns #TRUE if this uid owns the process.
+ */
+dbus_bool_t
+_dbus_unix_user_is_process_owner (dbus_uid_t uid)
+{
+  return FALSE;
+}
+
+dbus_bool_t _dbus_windows_user_is_process_owner (const char *windows_sid)
+{
+  return TRUE;
+}
+
+/*=====================================================================
+  unix emulation functions - should be removed sometime in the future
+ =====================================================================*/
+
+/**
+ * Checks to see if the UNIX user ID is at the console.
+ * Should always fail on Windows (set the error to
+ * #DBUS_ERROR_NOT_SUPPORTED).
+ *
+ * @param uid UID of person to check 
+ * @param error return location for errors
+ * @returns #TRUE if the UID is the same as the console user and there are no errors
+ */
+dbus_bool_t
+_dbus_unix_user_is_at_console (dbus_uid_t         uid,
+                               DBusError         *error)
+{
+  dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED,
+                  "UNIX user IDs not supported on Windows\n");
+  return FALSE;
+}
+
+
+/**
+ * Parse a UNIX group from the bus config file. On Windows, this should
+ * simply always fail (just return #FALSE).
+ *
+ * @param groupname the groupname text
+ * @param gid_p place to return the gid
+ * @returns #TRUE on success
+ */
+dbus_bool_t
+_dbus_parse_unix_group_from_config (const DBusString  *groupname,
+                                    dbus_gid_t        *gid_p)
+{
+  return FALSE;
+}
+
+/**
+ * Parse a UNIX user from the bus config file. On Windows, this should
+ * simply always fail (just return #FALSE).
+ *
+ * @param username the username text
+ * @param uid_p place to return the uid
+ * @returns #TRUE on success
+ */
+dbus_bool_t
+_dbus_parse_unix_user_from_config (const DBusString  *username,
+                                   dbus_uid_t        *uid_p)
+{
+  return FALSE;
+}
+
+
+/**
+ * Gets all groups corresponding to the given UNIX user ID. On UNIX,
+ * just calls _dbus_groups_from_uid(). On Windows, should always
+ * fail since we don't know any UNIX groups.
+ *
+ * @param uid the UID
+ * @param group_ids return location for array of group IDs
+ * @param n_group_ids return location for length of returned array
+ * @returns #TRUE if the UID existed and we got some credentials
+ */
+dbus_bool_t
+_dbus_unix_groups_from_uid (dbus_uid_t            uid,
+                            dbus_gid_t          **group_ids,
+                            int                  *n_group_ids)
+{
+  return FALSE;
+}
+
+
+
 /** @} */ /* DBusString stuff */
 
+/************************************************************************
+ error handling
+ ************************************************************************/
+
+
+
+
+
+/* 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
+}
+
+/**
+ * Get a printable string describing the command used to execute
+ * the process with pid.  This string should only be used for
+ * informative purposes such as logging; it may not be trusted.
+ *
+ * The command is guaranteed to be printable ASCII and no longer
+ * than max_len.
+ *
+ * @param pid Process id
+ * @param str Append command to this string
+ * @param max_len Maximum length of returned command
+ * @param error return location for errors
+ * @returns #FALSE on error
+ */
+dbus_bool_t
+_dbus_command_for_pid (unsigned long  pid,
+                       DBusString    *str,
+                       int            max_len,
+                       DBusError     *error)
+{
+  // FIXME
+  return FALSE;
+}
+
+/*
+ * replaces the term DBUS_PREFIX in configure_time_path by the
+ * current dbus installation directory. On unix this function is a noop
+ *
+ * @param configure_time_path
+ * @return real path
+ */
+const char *
+_dbus_replace_install_prefix (const char *configure_time_path)
+{
+#ifndef DBUS_PREFIX
+  return configure_time_path;
+#else
+  static char retval[1000];
+  static char runtime_prefix[1000];
+  int len = 1000;
+  int i;
+
+  if (!configure_time_path)
+    return NULL;
+
+  if ((!_dbus_get_install_root(runtime_prefix, len) ||
+       strncmp (configure_time_path, DBUS_PREFIX "/",
+                strlen (DBUS_PREFIX) + 1))) {
+     strcat (retval, configure_time_path);
+     return retval;
+  }
+
+  strcpy (retval, runtime_prefix);
+  strcat (retval, configure_time_path + strlen (DBUS_PREFIX) + 1);
+
+  /* Somehow, in some situations, backslashes get collapsed in the string.
+   * Since windows C library accepts both forward and backslashes as
+   * path separators, convert all backslashes to forward slashes.
+   */
+
+  for(i = 0; retval[i] != '\0'; i++) {
+    if(retval[i] == '\\')
+      retval[i] = '/';
+  }
+  return retval;
+#endif
+}
+
+/**
+ * return the relocated DATADIR
+ *
+ * @returns relocated DATADIR static string
+ */
+
+static const char *
+_dbus_windows_get_datadir (void)
+{
+       return _dbus_replace_install_prefix(DBUS_DATADIR);
+}
+
+#undef DBUS_DATADIR
+#define DBUS_DATADIR _dbus_windows_get_datadir ()
+
+
+#define DBUS_STANDARD_SESSION_SERVICEDIR "/dbus-1/services"
+#define DBUS_STANDARD_SYSTEM_SERVICEDIR "/dbus-1/system-services"
+
+/**
+ * Returns the standard directories for a session bus to look for service
+ * activation files
+ *
+ * On Windows this should be data directories:
+ *
+ * %CommonProgramFiles%/dbus
+ *
+ * and
+ *
+ * relocated 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;
+
+#ifdef DBUS_WINCE
+  {
+    /* On Windows CE, we adjust datadir dynamically to installation location.  */
+    const char *data_dir = _dbus_getenv ("DBUS_DATADIR");
+
+    if (data_dir != NULL)
+      {
+        if (!_dbus_string_append (&servicedir_path, data_dir))
+          goto oom;
+
+        if (!_dbus_string_append (&servicedir_path, _DBUS_PATH_SEPARATOR))
+          goto oom;
+      }
+  }
+#else
+/*
+ the code for accessing services requires absolute base pathes
+ in case DBUS_DATADIR is relative make it absolute
+*/
+#ifdef DBUS_WIN
+  {
+    DBusString p;
+
+    _dbus_string_init_const (&p, DBUS_DATADIR);
+
+    if (!_dbus_path_is_absolute (&p))
+      {
+        char install_root[1000];
+        if (_dbus_get_install_root (install_root, sizeof(install_root)))
+          if (!_dbus_string_append (&servicedir_path, install_root))
+            goto oom;
+      }
+  }
+#endif
+  if (!_dbus_string_append (&servicedir_path, DBUS_DATADIR))
+    goto oom;
+
+  if (!_dbus_string_append (&servicedir_path, _DBUS_PATH_SEPARATOR))
+    goto oom;
+#endif
+
+  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, _DBUS_PATH_SEPARATOR))
+        goto oom;
+    }
+
+  if (!_dbus_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;
+}
+
+/**
+ * Returns the standard directories for a system bus to look for service
+ * activation files
+ *
+ * On UNIX this should be the standard xdg freedesktop.org data directories:
+ *
+ * XDG_DATA_DIRS=${XDG_DATA_DIRS-/usr/local/share:/usr/share}
+ *
+ * and
+ *
+ * DBUS_DATADIR
+ *
+ * On Windows there is no system bus and this function can return nothing.
+ *
+ * @param dirs the directory list we are returning
+ * @returns #FALSE on OOM
+ */
+
+dbus_bool_t
+_dbus_get_standard_system_servicedirs (DBusList **dirs)
+{
+  *dirs = NULL;
+  return TRUE;
+}
+
+/**
+ * Append the absolute path of the system.conf file
+ * (there is no system bus on Windows so this can just
+ * return FALSE and print a warning or something)
+ *
+ * @param str the string to append to
+ * @returns #FALSE if no memory
+ */
+dbus_bool_t
+_dbus_append_system_config_file (DBusString *str)
+{
+  return _dbus_get_config_file_name(str, "system.conf");
+}
+
+/**
+ * Append the absolute path of the session.conf file.
+ *
+ * @param str the string to append to
+ * @returns #FALSE if no memory
+ */
+dbus_bool_t
+_dbus_append_session_config_file (DBusString *str)
+{
+  return _dbus_get_config_file_name(str, "session.conf");
+}