1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-sysdeps-util.c Would be in dbus-sysdeps.c, but not used in libdbus
4 * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc.
5 * Copyright (C) 2003 CodeFactory AB
7 * Licensed under the Academic Free License version 2.1
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #define STRSAFE_NO_DEPRECATE
29 #include "dbus-sysdeps.h"
30 #include "dbus-internals.h"
31 #include "dbus-protocol.h"
32 #include "dbus-string.h"
33 #include "dbus-sysdeps.h"
34 #include "dbus-sysdeps-win.h"
35 #include "dbus-memory.h"
46 /* save string functions version
47 using DBusString needs to much time because of uncommon api
51 errno_t strcat_s(char *dest, int size, char *src)
53 _dbus_assert(strlen(dest) + strlen(src) +1 <= size);
58 errno_t strcpy_s(char *dest, int size, char *src)
60 _dbus_assert(strlen(src) +1 <= size);
67 * return the absolute path of the dbus installation
69 * @param s buffer for installation path
70 * @param len length of buffer
71 * @returns #FALSE on failure
74 _dbus_get_install_root(char *s, int len)
77 int ret = GetModuleFileName(NULL,s,len);
79 || ret == len && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
84 else if ((p = strstr(s,"\\bin\\")))
97 find session.conf either from installation or build root according to
98 the following path layout
100 bin/dbus-daemon[d].exe
104 bin/dbus-daemon[d].exe
108 _dbus_get_config_file_name(DBusString *config_file, char *s)
110 char path[MAX_PATH*2];
111 int path_size = sizeof(path);
113 if (!_dbus_get_install_root(path,path_size))
116 strcat_s(path,path_size,"etc\\");
117 strcat_s(path,path_size,s);
118 if (_dbus_file_exists(path))
120 // find path from executable
121 if (!_dbus_string_append (config_file, path))
126 if (!_dbus_get_install_root(path,path_size))
128 strcat_s(path,path_size,"bus\\");
129 strcat_s(path,path_size,s);
131 if (_dbus_file_exists(path))
133 if (!_dbus_string_append (config_file, path))
141 * Does the chdir, fork, setsid, etc. to become a daemon process.
143 * @param pidfile #NULL, or pidfile to create
144 * @param print_pid_fd file descriptor to print daemon's pid to, or -1 for none
145 * @param error return location for errors
146 * @returns #FALSE on failure
149 _dbus_become_daemon (const DBusString *pidfile,
150 DBusPipe *print_pid_pipe,
157 * Creates a file containing the process ID.
159 * @param filename the filename to write to
160 * @param pid our process ID
161 * @param error return location for errors
162 * @returns #FALSE on failure
165 _dbus_write_pid_file (const DBusString *filename,
169 const char *cfilename;
173 cfilename = _dbus_string_get_const_data (filename);
175 if (!_dbus_file_open(&file, cfilename, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644))
177 dbus_set_error (error, _dbus_error_from_errno (errno),
178 "Failed to open \"%s\": %s", cfilename,
179 _dbus_strerror (errno));
183 if ((f = fdopen (file.FDATA, "w")) == NULL)
185 dbus_set_error (error, _dbus_error_from_errno (errno),
186 "Failed to fdopen fd %d: %s", file.FDATA, _dbus_strerror (errno));
187 _dbus_file_close (&file, NULL);
191 if (fprintf (f, "%lu\n", pid) < 0)
193 dbus_set_error (error, _dbus_error_from_errno (errno),
194 "Failed to write to \"%s\": %s", cfilename,
195 _dbus_strerror (errno));
201 if (fclose (f) == EOF)
203 dbus_set_error (error, _dbus_error_from_errno (errno),
204 "Failed to close \"%s\": %s", cfilename,
205 _dbus_strerror (errno));
213 * Changes the user and group the bus is running as.
215 * @param uid the new user ID
216 * @param gid the new group ID
217 * @param error return location for errors
218 * @returns #FALSE on failure
221 _dbus_change_identity (dbus_uid_t uid,
228 /** Checks if user is at the console
230 * @param username user to check
231 * @param error return location for errors
232 * @returns #TRUE is the user is at the consolei and there are no errors
235 _dbus_user_at_console(const char *username,
241 dbus_bool_t retval = FALSE;
244 PSID user_sid, console_user_sid;
247 wusername = _dbus_win_utf8_to_utf16 (username, error);
251 if (!_dbus_win_account_to_sid (wusername, &user_sid, error))
254 /* Now we have the SID for username. Get the SID of the
255 * user at the "console" (window station WinSta0)
257 if (!(winsta = OpenWindowStation ("WinSta0", FALSE, READ_CONTROL)))
259 _dbus_win_set_error_from_win_error (error, GetLastError ());
264 GetUserObjectInformation (winsta, UOI_USER_SID,
265 NULL, 0, &sid_length);
268 /* Nobody is logged on */
272 if (sid_length < 0 || sid_length > 1000)
274 dbus_set_error_const (error, DBUS_ERROR_FAILED, "Invalid SID length");
278 console_user_sid = dbus_malloc (sid_length);
279 if (!console_user_sid)
281 _DBUS_SET_OOM (error);
285 if (!GetUserObjectInformation (winsta, UOI_USER_SID,
286 console_user_sid, sid_length, &sid_length))
288 _dbus_win_set_error_from_win_error (error, GetLastError ());
292 if (!IsValidSid (console_user_sid))
294 dbus_set_error_const (error, DBUS_ERROR_FAILED, "Invalid SID");
298 retval = EqualSid (user_sid, console_user_sid);
301 dbus_free (console_user_sid);
303 CloseWindowStation (winsta);
305 dbus_free (user_sid);
307 dbus_free (wusername);
314 * Removes a directory; Directory must be empty
316 * @param filename directory filename
317 * @param error initialized error object
318 * @returns #TRUE on success
321 _dbus_delete_directory (const DBusString *filename,
324 const char *filename_c;
326 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
328 filename_c = _dbus_string_get_const_data (filename);
330 if (rmdir (filename_c) != 0)
332 dbus_set_error (error, DBUS_ERROR_FAILED,
333 "Failed to remove directory %s: %s\n",
334 filename_c, _dbus_strerror (errno));
341 /** Installs a signal handler
343 * @param sig the signal to handle
344 * @param handler the handler
347 _dbus_set_signal_handler (int sig,
348 DBusSignalHandler handler)
350 _dbus_verbose ("_dbus_set_signal_handler() has to be implemented\n");
353 /** Checks if a file exists
355 * @param file full path to the file
356 * @returns #TRUE if file exists
359 _dbus_file_exists (const char *file)
361 HANDLE h = CreateFile(
362 file, /* LPCTSTR lpFileName*/
363 0, /* DWORD dwDesiredAccess */
364 0, /* DWORD dwShareMode*/
365 NULL, /* LPSECURITY_ATTRIBUTES lpSecurityAttributes */
366 OPEN_EXISTING, /* DWORD dwCreationDisposition */
367 FILE_ATTRIBUTE_NORMAL, /* DWORD dwFlagsAndAttributes */
368 NULL /* HANDLE hTemplateFile */
371 /* file not found, use local copy of session.conf */
372 if (h != INVALID_HANDLE_VALUE && GetLastError() != ERROR_PATH_NOT_FOUND)
384 * @param filename the filename to stat
385 * @param statbuf the stat info to fill in
386 * @param error return location for error
387 * @returns #FALSE if error was set
390 _dbus_stat(const DBusString *filename,
398 const char *filename_c;
399 #if !defined(DBUS_WIN) && !defined(DBUS_WINCE)
404 WIN32_FILE_ATTRIBUTE_DATA wfad;
407 PSID owner_sid, group_sid;
408 PSECURITY_DESCRIPTOR sd;
411 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
413 filename_c = _dbus_string_get_const_data (filename);
415 if (!GetFileAttributesEx (filename_c, GetFileExInfoStandard, &wfad))
417 _dbus_win_set_error_from_win_error (error, GetLastError ());
421 if (wfad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
422 statbuf->mode = _S_IFDIR;
424 statbuf->mode = _S_IFREG;
426 statbuf->mode |= _S_IREAD;
427 if (wfad.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
428 statbuf->mode |= _S_IWRITE;
430 lastdot = strrchr (filename_c, '.');
431 if (lastdot && stricmp (lastdot, ".exe") == 0)
432 statbuf->mode |= _S_IEXEC;
434 statbuf->mode |= (statbuf->mode & 0700) >> 3;
435 statbuf->mode |= (statbuf->mode & 0700) >> 6;
440 rc = GetNamedSecurityInfo ((char *) filename_c, SE_FILE_OBJECT,
441 OWNER_SECURITY_INFORMATION |
442 GROUP_SECURITY_INFORMATION,
443 &owner_sid, &group_sid,
446 if (rc != ERROR_SUCCESS)
448 _dbus_win_set_error_from_win_error (error, rc);
454 statbuf->uid = _dbus_win_sid_to_uid_t (owner_sid);
455 statbuf->gid = _dbus_win_sid_to_uid_t (group_sid);
459 statbuf->size = ((dbus_int64_t) wfad.nFileSizeHigh << 32) + wfad.nFileSizeLow;
462 (((dbus_int64_t) wfad.ftLastAccessTime.dwHighDateTime << 32) +
463 wfad.ftLastAccessTime.dwLowDateTime) / 10000000 - DBUS_INT64_CONSTANT (116444736000000000);
466 (((dbus_int64_t) wfad.ftLastWriteTime.dwHighDateTime << 32) +
467 wfad.ftLastWriteTime.dwLowDateTime) / 10000000 - DBUS_INT64_CONSTANT (116444736000000000);
470 (((dbus_int64_t) wfad.ftCreationTime.dwHighDateTime << 32) +
471 wfad.ftCreationTime.dwLowDateTime) / 10000000 - DBUS_INT64_CONSTANT (116444736000000000);
480 // mingw ships with dirent.h
482 #define _dbus_opendir opendir
483 #define _dbus_readdir readdir
484 #define _dbus_closedir closedir
489 #include <io.h> // win32 file functions
492 #include <sys/types.h>
495 /* This file is part of the KDE project
496 Copyright (C) 2000 Werner Almesberger
498 libc/sys/linux/sys/dirent.h - Directory entry as returned by readdir
500 This program is free software; you can redistribute it and/or
501 modify it under the terms of the GNU Library General Public
502 License as published by the Free Software Foundation; either
503 version 2 of the License, or (at your option) any later version.
505 This program is distributed in the hope that it will be useful,
506 but WITHOUT ANY WARRANTY; without even the implied warranty of
507 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
508 Library General Public License for more details.
510 You should have received a copy of the GNU Library General Public License
511 along with this program; see the file COPYING. If not, write to
512 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
513 Boston, MA 02110-1301, USA.
515 #define HAVE_NO_D_NAMLEN /* no struct dirent->d_namlen */
516 #define HAVE_DD_LOCK /* have locking mechanism */
518 #define MAXNAMLEN 255 /* sizeof(struct dirent.d_name)-1 */
520 #define __dirfd(dir) (dir)->dd_fd
522 /* struct dirent - same as Unix */
525 long d_ino; /* inode (always 1 in WIN32) */
526 off_t d_off; /* offset to this dirent */
527 unsigned short d_reclen; /* length of d_name */
528 char d_name[_MAX_FNAME+1]; /* filename (null terminated) */
531 /* typedef DIR - not the same as Unix */
534 long handle; /* _findfirst/_findnext handle */
535 short offset; /* offset into directory */
536 short finished; /* 1 if there are not more files */
537 struct _finddata_t fileinfo; /* from _findfirst/_findnext */
538 char *dir; /* the dir we are reading */
539 struct dirent dent; /* the dirent to return */
543 /**********************************************************************
544 * Implement dirent-style opendir/readdir/closedir on Window 95/NT
546 * Functions defined are opendir(), readdir() and closedir() with the
547 * same prototypes as the normal dirent.h implementation.
549 * Does not implement telldir(), seekdir(), rewinddir() or scandir().
550 * The dirent struct is compatible with Unix, except that d_ino is
551 * always 1 and d_off is made up as we go along.
553 * The DIR typedef is not compatible with Unix.
554 **********************************************************************/
556 DIR * _dbus_opendir(const char *dir)
563 filespec = malloc(strlen(dir) + 2 + 1);
564 strcpy(filespec, dir);
565 index = strlen(filespec) - 1;
566 if (index >= 0 && (filespec[index] == '/' || filespec[index] == '\\'))
567 filespec[index] = '\0';
568 strcat(filespec, "\\*");
570 dp = (DIR *)malloc(sizeof(DIR));
573 dp->dir = strdup(dir);
575 if ((handle = _findfirst(filespec, &(dp->fileinfo))) < 0)
589 struct dirent * _dbus_readdir(DIR *dp)
591 if (!dp || dp->finished)
596 if (_findnext(dp->handle, &(dp->fileinfo)) < 0)
605 strncpy(dp->dent.d_name, dp->fileinfo.name, _MAX_FNAME);
607 dp->dent.d_reclen = strlen(dp->dent.d_name);
608 dp->dent.d_off = dp->offset;
614 int _dbus_closedir(DIR *dp)
618 _findclose(dp->handle);
627 #endif //#ifdef HAVE_DIRENT_H
630 * Internals of directory iterator
634 DIR *d; /**< The DIR* from opendir() */
639 * Open a directory to iterate over.
641 * @param filename the directory name
642 * @param error exception return object or #NULL
643 * @returns new iterator, or #NULL on error
646 _dbus_directory_open (const DBusString *filename,
651 const char *filename_c;
653 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
655 filename_c = _dbus_string_get_const_data (filename);
657 d = _dbus_opendir (filename_c);
660 dbus_set_error (error, _dbus_error_from_errno (errno),
661 "Failed to read directory \"%s\": %s",
663 _dbus_strerror (errno));
666 iter = dbus_new0 (DBusDirIter, 1);
670 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
671 "Could not allocate memory for directory iterator");
681 * Get next file in the directory. Will not return "." or ".." on
682 * UNIX. If an error occurs, the contents of "filename" are
683 * undefined. The error is never set if the function succeeds.
685 * @todo for thread safety, I think we have to use
686 * readdir_r(). (GLib has the same issue, should file a bug.)
688 * @param iter the iterator
689 * @param filename string to be set to the next file in the dir
690 * @param error return location for error
691 * @returns #TRUE if filename was filled in with a new filename
694 _dbus_directory_get_next_file (DBusDirIter *iter,
695 DBusString *filename,
700 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
704 ent = _dbus_readdir (iter->d);
708 dbus_set_error (error,
709 _dbus_error_from_errno (errno),
710 "%s", _dbus_strerror (errno));
713 else if (ent->d_name[0] == '.' &&
714 (ent->d_name[1] == '\0' ||
715 (ent->d_name[1] == '.' && ent->d_name[2] == '\0')))
719 _dbus_string_set_length (filename, 0);
720 if (!_dbus_string_append (filename, ent->d_name))
722 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
723 "No memory to read directory entry");
732 * Closes a directory iteration.
735 _dbus_directory_close (DBusDirIter *iter)
737 _dbus_closedir (iter->d);
742 * Checks whether the filename is an absolute path
744 * @param filename the filename
745 * @returns #TRUE if an absolute path
748 _dbus_path_is_absolute (const DBusString *filename)
750 if (_dbus_string_get_length (filename) > 0)
751 return _dbus_string_get_byte (filename, 1) == ':'
752 || _dbus_string_get_byte (filename, 0) == '\\'
753 || _dbus_string_get_byte (filename, 0) == '/';
760 fill_group_info(DBusGroupInfo *info,
762 const DBusString *groupname,
765 const char *group_c_str;
767 _dbus_assert (groupname != NULL || gid != DBUS_GID_UNSET);
768 _dbus_assert (groupname == NULL || gid == DBUS_GID_UNSET);
771 group_c_str = _dbus_string_get_const_data (groupname);
778 wchar_t *wgroupname = _dbus_win_utf8_to_utf16 (group_c_str, error);
783 if (!_dbus_win_account_to_sid (wgroupname, &group_sid, error))
785 dbus_free (wgroupname);
789 info->gid = _dbus_win_sid_to_uid_t (group_sid);
790 info->groupname = _dbus_strdup (group_c_str);
792 dbus_free (group_sid);
793 dbus_free (wgroupname);
799 dbus_bool_t retval = FALSE;
800 wchar_t *wname, *wdomain;
805 if (!_dbus_win_sid_to_name_and_domain (gid, &wname, &wdomain, error))
808 name = _dbus_win_utf16_to_utf8 (wname, error);
812 domain = _dbus_win_utf16_to_utf8 (wdomain, error);
816 info->groupname = dbus_malloc (strlen (domain) + 1 + strlen (name) + 1);
818 strcpy (info->groupname, domain);
819 strcat (info->groupname, "\\");
820 strcat (info->groupname, name);
836 * Initializes the given DBusGroupInfo struct
837 * with information about the given group ID.
839 * @param info the group info struct
840 * @param gid group ID
841 * @param error the error return
842 * @returns #FALSE if error is set
845 _dbus_group_info_fill_gid (DBusGroupInfo *info,
849 return fill_group_info (info, gid, NULL, error);
853 * Initializes the given DBusGroupInfo struct
854 * with information about the given group name.
856 * @param info the group info struct
857 * @param groupname name of group
858 * @param error the error return
859 * @returns #FALSE if error is set
862 _dbus_group_info_fill (DBusGroupInfo *info,
863 const DBusString *groupname,
866 return fill_group_info (info, DBUS_GID_UNSET,
870 /** @} */ /* End of DBusInternalsUtils functions */
873 * @addtogroup DBusString
878 * Get the directory name from a complete filename
879 * @param filename the filename
880 * @param dirname string to append directory name to
881 * @returns #FALSE if no memory
884 _dbus_string_get_dirname(const DBusString *filename,
889 _dbus_assert (filename != dirname);
890 _dbus_assert (filename != NULL);
891 _dbus_assert (dirname != NULL);
893 /* Ignore any separators on the end */
894 sep = _dbus_string_get_length (filename);
896 return _dbus_string_append (dirname, "."); /* empty string passed in */
899 (_dbus_string_get_byte (filename, sep - 1) == '/' ||
900 _dbus_string_get_byte (filename, sep - 1) == '\\'))
903 _dbus_assert (sep >= 0);
907 _dbus_string_get_byte (filename, 1) == ':' &&
908 isalpha (_dbus_string_get_byte (filename, 0))))
909 return _dbus_string_copy_len (filename, 0, sep + 1,
910 dirname, _dbus_string_get_length (dirname));
914 _dbus_string_find_byte_backward (filename, sep, '/', &sep1);
915 _dbus_string_find_byte_backward (filename, sep, '\\', &sep2);
917 sep = MAX (sep1, sep2);
920 return _dbus_string_append (dirname, ".");
923 (_dbus_string_get_byte (filename, sep - 1) == '/' ||
924 _dbus_string_get_byte (filename, sep - 1) == '\\'))
927 _dbus_assert (sep >= 0);
931 _dbus_string_get_byte (filename, 1) == ':' &&
932 isalpha (_dbus_string_get_byte (filename, 0))))
934 (_dbus_string_get_byte (filename, sep) == '/' ||
935 _dbus_string_get_byte (filename, sep) == '\\'))
936 return _dbus_string_copy_len (filename, 0, sep + 1,
937 dirname, _dbus_string_get_length (dirname));
939 return _dbus_string_copy_len (filename, 0, sep - 0,
940 dirname, _dbus_string_get_length (dirname));
943 /** @} */ /* DBusString stuff */