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
25 /* #define ENABLE_DBUSGROUPINFO */
27 #ifdef ENABLE_DBUSGROUPINFO
36 #define STRSAFE_NO_DEPRECATE
38 #include "dbus-sysdeps.h"
39 #include "dbus-internals.h"
40 #include "dbus-protocol.h"
41 #include "dbus-string.h"
42 #include "dbus-sysdeps.h"
43 #include "dbus-sysdeps-win.h"
44 #include "dbus-memory.h"
55 /* save string functions version
56 using DBusString needs to much time because of uncommon api
60 errno_t strcat_s(char *dest, int size, char *src)
62 _dbus_assert(strlen(dest) + strlen(src) +1 <= size);
67 errno_t strcpy_s(char *dest, int size, char *src)
69 _dbus_assert(strlen(src) +1 <= size);
76 * return the absolute path of the dbus installation
78 * @param s buffer for installation path
79 * @param len length of buffer
80 * @returns #FALSE on failure
83 _dbus_get_install_root(char *s, int len)
86 int ret = GetModuleFileName(NULL,s,len);
88 || ret == len && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
93 else if ((p = strstr(s,"\\bin\\")))
106 find session.conf either from installation or build root according to
107 the following path layout
109 bin/dbus-daemon[d].exe
113 bin/dbus-daemon[d].exe
117 _dbus_get_config_file_name(DBusString *config_file, char *s)
119 char path[MAX_PATH*2];
120 int path_size = sizeof(path);
122 if (!_dbus_get_install_root(path,path_size))
125 strcat_s(path,path_size,"etc\\");
126 strcat_s(path,path_size,s);
127 if (_dbus_file_exists(path))
129 // find path from executable
130 if (!_dbus_string_append (config_file, path))
135 if (!_dbus_get_install_root(path,path_size))
137 strcat_s(path,path_size,"bus\\");
138 strcat_s(path,path_size,s);
140 if (_dbus_file_exists(path))
142 if (!_dbus_string_append (config_file, path))
150 * Does the chdir, fork, setsid, etc. to become a daemon process.
152 * @param pidfile #NULL, or pidfile to create
153 * @param print_pid_fd file descriptor to print daemon's pid to, or -1 for none
154 * @param error return location for errors
155 * @returns #FALSE on failure
158 _dbus_become_daemon (const DBusString *pidfile,
159 DBusPipe *print_pid_pipe,
166 * Creates a file containing the process ID.
168 * @param filename the filename to write to
169 * @param pid our process ID
170 * @param error return location for errors
171 * @returns #FALSE on failure
174 _dbus_write_pid_file (const DBusString *filename,
178 const char *cfilename;
182 cfilename = _dbus_string_get_const_data (filename);
184 if (!_dbus_file_open(&file, cfilename, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644))
186 dbus_set_error (error, _dbus_error_from_errno (errno),
187 "Failed to open \"%s\": %s", cfilename,
188 _dbus_strerror (errno));
192 if ((f = fdopen (file.FDATA, "w")) == NULL)
194 dbus_set_error (error, _dbus_error_from_errno (errno),
195 "Failed to fdopen fd %d: %s", file.FDATA, _dbus_strerror (errno));
196 _dbus_file_close (&file, NULL);
200 if (fprintf (f, "%lu\n", pid) < 0)
202 dbus_set_error (error, _dbus_error_from_errno (errno),
203 "Failed to write to \"%s\": %s", cfilename,
204 _dbus_strerror (errno));
210 if (fclose (f) == EOF)
212 dbus_set_error (error, _dbus_error_from_errno (errno),
213 "Failed to close \"%s\": %s", cfilename,
214 _dbus_strerror (errno));
222 * Verify that after the fork we can successfully change to this user.
224 * @param user the username given in the daemon configuration
225 * @returns #TRUE if username is valid
228 _dbus_verify_daemon_user (const char *user)
234 * Changes the user and group the bus is running as.
236 * @param user the user to become
237 * @param error return location for errors
238 * @returns #FALSE on failure
241 _dbus_change_to_daemon_user (const char *user,
248 * Changes the user and group the bus is running as.
250 * @param uid the new user ID
251 * @param gid the new group ID
252 * @param error return location for errors
253 * @returns #FALSE on failure
256 _dbus_change_identity (dbus_uid_t uid,
263 /** Checks if user is at the console
265 * @param username user to check
266 * @param error return location for errors
267 * @returns #TRUE is the user is at the consolei and there are no errors
270 _dbus_user_at_console(const char *username,
276 dbus_bool_t retval = FALSE;
279 PSID user_sid, console_user_sid;
282 wusername = _dbus_win_utf8_to_utf16 (username, error);
286 if (!_dbus_win_account_to_sid (wusername, &user_sid, error))
289 /* Now we have the SID for username. Get the SID of the
290 * user at the "console" (window station WinSta0)
292 if (!(winsta = OpenWindowStation ("WinSta0", FALSE, READ_CONTROL)))
294 _dbus_win_set_error_from_win_error (error, GetLastError ());
299 GetUserObjectInformation (winsta, UOI_USER_SID,
300 NULL, 0, &sid_length);
303 /* Nobody is logged on */
307 if (sid_length < 0 || sid_length > 1000)
309 dbus_set_error_const (error, DBUS_ERROR_FAILED, "Invalid SID length");
313 console_user_sid = dbus_malloc (sid_length);
314 if (!console_user_sid)
316 _DBUS_SET_OOM (error);
320 if (!GetUserObjectInformation (winsta, UOI_USER_SID,
321 console_user_sid, sid_length, &sid_length))
323 _dbus_win_set_error_from_win_error (error, GetLastError ());
327 if (!IsValidSid (console_user_sid))
329 dbus_set_error_const (error, DBUS_ERROR_FAILED, "Invalid SID");
333 retval = EqualSid (user_sid, console_user_sid);
336 dbus_free (console_user_sid);
338 CloseWindowStation (winsta);
340 dbus_free (user_sid);
342 dbus_free (wusername);
349 * Removes a directory; Directory must be empty
351 * @param filename directory filename
352 * @param error initialized error object
353 * @returns #TRUE on success
356 _dbus_delete_directory (const DBusString *filename,
359 const char *filename_c;
361 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
363 filename_c = _dbus_string_get_const_data (filename);
365 if (rmdir (filename_c) != 0)
367 dbus_set_error (error, DBUS_ERROR_FAILED,
368 "Failed to remove directory %s: %s\n",
369 filename_c, _dbus_strerror (errno));
376 /** Installs a signal handler
378 * @param sig the signal to handle
379 * @param handler the handler
382 _dbus_set_signal_handler (int sig,
383 DBusSignalHandler handler)
385 _dbus_verbose ("_dbus_set_signal_handler() has to be implemented\n");
388 /** Checks if a file exists
390 * @param file full path to the file
391 * @returns #TRUE if file exists
394 _dbus_file_exists (const char *file)
396 HANDLE h = CreateFile(
397 file, /* LPCTSTR lpFileName*/
398 0, /* DWORD dwDesiredAccess */
399 0, /* DWORD dwShareMode*/
400 NULL, /* LPSECURITY_ATTRIBUTES lpSecurityAttributes */
401 OPEN_EXISTING, /* DWORD dwCreationDisposition */
402 FILE_ATTRIBUTE_NORMAL, /* DWORD dwFlagsAndAttributes */
403 NULL /* HANDLE hTemplateFile */
406 /* file not found, use local copy of session.conf */
407 if (h != INVALID_HANDLE_VALUE && GetLastError() != ERROR_PATH_NOT_FOUND)
419 * @param filename the filename to stat
420 * @param statbuf the stat info to fill in
421 * @param error return location for error
422 * @returns #FALSE if error was set
425 _dbus_stat(const DBusString *filename,
433 const char *filename_c;
434 #if !defined(DBUS_WIN) && !defined(DBUS_WINCE)
439 WIN32_FILE_ATTRIBUTE_DATA wfad;
442 PSID owner_sid, group_sid;
443 PSECURITY_DESCRIPTOR sd;
446 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
448 filename_c = _dbus_string_get_const_data (filename);
450 if (!GetFileAttributesEx (filename_c, GetFileExInfoStandard, &wfad))
452 _dbus_win_set_error_from_win_error (error, GetLastError ());
456 if (wfad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
457 statbuf->mode = _S_IFDIR;
459 statbuf->mode = _S_IFREG;
461 statbuf->mode |= _S_IREAD;
462 if (wfad.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
463 statbuf->mode |= _S_IWRITE;
465 lastdot = strrchr (filename_c, '.');
466 if (lastdot && stricmp (lastdot, ".exe") == 0)
467 statbuf->mode |= _S_IEXEC;
469 statbuf->mode |= (statbuf->mode & 0700) >> 3;
470 statbuf->mode |= (statbuf->mode & 0700) >> 6;
475 rc = GetNamedSecurityInfo ((char *) filename_c, SE_FILE_OBJECT,
476 OWNER_SECURITY_INFORMATION |
477 GROUP_SECURITY_INFORMATION,
478 &owner_sid, &group_sid,
481 if (rc != ERROR_SUCCESS)
483 _dbus_win_set_error_from_win_error (error, rc);
489 statbuf->uid = _dbus_win_sid_to_uid_t (owner_sid);
490 statbuf->gid = _dbus_win_sid_to_uid_t (group_sid);
494 statbuf->size = ((dbus_int64_t) wfad.nFileSizeHigh << 32) + wfad.nFileSizeLow;
497 (((dbus_int64_t) wfad.ftLastAccessTime.dwHighDateTime << 32) +
498 wfad.ftLastAccessTime.dwLowDateTime) / 10000000 - DBUS_INT64_CONSTANT (116444736000000000);
501 (((dbus_int64_t) wfad.ftLastWriteTime.dwHighDateTime << 32) +
502 wfad.ftLastWriteTime.dwLowDateTime) / 10000000 - DBUS_INT64_CONSTANT (116444736000000000);
505 (((dbus_int64_t) wfad.ftCreationTime.dwHighDateTime << 32) +
506 wfad.ftCreationTime.dwLowDateTime) / 10000000 - DBUS_INT64_CONSTANT (116444736000000000);
515 // mingw ships with dirent.h
517 #define _dbus_opendir opendir
518 #define _dbus_readdir readdir
519 #define _dbus_closedir closedir
524 #include <io.h> // win32 file functions
527 #include <sys/types.h>
530 /* This file is part of the KDE project
531 Copyright (C) 2000 Werner Almesberger
533 libc/sys/linux/sys/dirent.h - Directory entry as returned by readdir
535 This program is free software; you can redistribute it and/or
536 modify it under the terms of the GNU Library General Public
537 License as published by the Free Software Foundation; either
538 version 2 of the License, or (at your option) any later version.
540 This program is distributed in the hope that it will be useful,
541 but WITHOUT ANY WARRANTY; without even the implied warranty of
542 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
543 Library General Public License for more details.
545 You should have received a copy of the GNU Library General Public License
546 along with this program; see the file COPYING. If not, write to
547 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
548 Boston, MA 02110-1301, USA.
550 #define HAVE_NO_D_NAMLEN /* no struct dirent->d_namlen */
551 #define HAVE_DD_LOCK /* have locking mechanism */
553 #define MAXNAMLEN 255 /* sizeof(struct dirent.d_name)-1 */
555 #define __dirfd(dir) (dir)->dd_fd
557 /* struct dirent - same as Unix */
560 long d_ino; /* inode (always 1 in WIN32) */
561 off_t d_off; /* offset to this dirent */
562 unsigned short d_reclen; /* length of d_name */
563 char d_name[_MAX_FNAME+1]; /* filename (null terminated) */
566 /* typedef DIR - not the same as Unix */
569 long handle; /* _findfirst/_findnext handle */
570 short offset; /* offset into directory */
571 short finished; /* 1 if there are not more files */
572 struct _finddata_t fileinfo; /* from _findfirst/_findnext */
573 char *dir; /* the dir we are reading */
574 struct dirent dent; /* the dirent to return */
578 /**********************************************************************
579 * Implement dirent-style opendir/readdir/closedir on Window 95/NT
581 * Functions defined are opendir(), readdir() and closedir() with the
582 * same prototypes as the normal dirent.h implementation.
584 * Does not implement telldir(), seekdir(), rewinddir() or scandir().
585 * The dirent struct is compatible with Unix, except that d_ino is
586 * always 1 and d_off is made up as we go along.
588 * The DIR typedef is not compatible with Unix.
589 **********************************************************************/
591 DIR * _dbus_opendir(const char *dir)
598 filespec = malloc(strlen(dir) + 2 + 1);
599 strcpy(filespec, dir);
600 index = strlen(filespec) - 1;
601 if (index >= 0 && (filespec[index] == '/' || filespec[index] == '\\'))
602 filespec[index] = '\0';
603 strcat(filespec, "\\*");
605 dp = (DIR *)malloc(sizeof(DIR));
608 dp->dir = strdup(dir);
610 if ((handle = _findfirst(filespec, &(dp->fileinfo))) < 0)
624 struct dirent * _dbus_readdir(DIR *dp)
626 if (!dp || dp->finished)
631 if (_findnext(dp->handle, &(dp->fileinfo)) < 0)
640 strncpy(dp->dent.d_name, dp->fileinfo.name, _MAX_FNAME);
642 dp->dent.d_reclen = strlen(dp->dent.d_name);
643 dp->dent.d_off = dp->offset;
649 int _dbus_closedir(DIR *dp)
653 _findclose(dp->handle);
662 #endif //#ifdef HAVE_DIRENT_H
665 * Internals of directory iterator
669 DIR *d; /**< The DIR* from opendir() */
674 * Open a directory to iterate over.
676 * @param filename the directory name
677 * @param error exception return object or #NULL
678 * @returns new iterator, or #NULL on error
681 _dbus_directory_open (const DBusString *filename,
686 const char *filename_c;
688 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
690 filename_c = _dbus_string_get_const_data (filename);
692 d = _dbus_opendir (filename_c);
695 dbus_set_error (error, _dbus_error_from_errno (errno),
696 "Failed to read directory \"%s\": %s",
698 _dbus_strerror (errno));
701 iter = dbus_new0 (DBusDirIter, 1);
705 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
706 "Could not allocate memory for directory iterator");
716 * Get next file in the directory. Will not return "." or ".." on
717 * UNIX. If an error occurs, the contents of "filename" are
718 * undefined. The error is never set if the function succeeds.
720 * @todo for thread safety, I think we have to use
721 * readdir_r(). (GLib has the same issue, should file a bug.)
723 * @param iter the iterator
724 * @param filename string to be set to the next file in the dir
725 * @param error return location for error
726 * @returns #TRUE if filename was filled in with a new filename
729 _dbus_directory_get_next_file (DBusDirIter *iter,
730 DBusString *filename,
735 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
739 ent = _dbus_readdir (iter->d);
743 dbus_set_error (error,
744 _dbus_error_from_errno (errno),
745 "%s", _dbus_strerror (errno));
748 else if (ent->d_name[0] == '.' &&
749 (ent->d_name[1] == '\0' ||
750 (ent->d_name[1] == '.' && ent->d_name[2] == '\0')))
754 _dbus_string_set_length (filename, 0);
755 if (!_dbus_string_append (filename, ent->d_name))
757 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
758 "No memory to read directory entry");
767 * Closes a directory iteration.
770 _dbus_directory_close (DBusDirIter *iter)
772 _dbus_closedir (iter->d);
777 * Checks whether the filename is an absolute path
779 * @param filename the filename
780 * @returns #TRUE if an absolute path
783 _dbus_path_is_absolute (const DBusString *filename)
785 if (_dbus_string_get_length (filename) > 0)
786 return _dbus_string_get_byte (filename, 1) == ':'
787 || _dbus_string_get_byte (filename, 0) == '\\'
788 || _dbus_string_get_byte (filename, 0) == '/';
793 #ifdef ENABLE_DBUSGROPINFO
795 fill_group_info(DBusGroupInfo *info,
797 const DBusString *groupname,
800 const char *group_c_str;
802 _dbus_assert (groupname != NULL || gid != DBUS_GID_UNSET);
803 _dbus_assert (groupname == NULL || gid == DBUS_GID_UNSET);
806 group_c_str = _dbus_string_get_const_data (groupname);
813 wchar_t *wgroupname = _dbus_win_utf8_to_utf16 (group_c_str, error);
818 if (!_dbus_win_account_to_sid (wgroupname, &group_sid, error))
820 dbus_free (wgroupname);
824 info->gid = _dbus_win_sid_to_uid_t (group_sid);
825 info->groupname = _dbus_strdup (group_c_str);
827 dbus_free (group_sid);
828 dbus_free (wgroupname);
834 dbus_bool_t retval = FALSE;
835 wchar_t *wname, *wdomain;
840 if (!_dbus_win_sid_to_name_and_domain (gid, &wname, &wdomain, error))
843 name = _dbus_win_utf16_to_utf8 (wname, error);
847 domain = _dbus_win_utf16_to_utf8 (wdomain, error);
851 info->groupname = dbus_malloc (strlen (domain) + 1 + strlen (name) + 1);
853 strcpy (info->groupname, domain);
854 strcat (info->groupname, "\\");
855 strcat (info->groupname, name);
871 * Initializes the given DBusGroupInfo struct
872 * with information about the given group ID.
874 * @param info the group info struct
875 * @param gid group ID
876 * @param error the error return
877 * @returns #FALSE if error is set
880 _dbus_group_info_fill_gid (DBusGroupInfo *info,
884 return fill_group_info (info, gid, NULL, error);
888 * Initializes the given DBusGroupInfo struct
889 * with information about the given group name.
891 * @param info the group info struct
892 * @param groupname name of group
893 * @param error the error return
894 * @returns #FALSE if error is set
897 _dbus_group_info_fill (DBusGroupInfo *info,
898 const DBusString *groupname,
901 return fill_group_info (info, DBUS_GID_UNSET,
906 /** @} */ /* End of DBusInternalsUtils functions */
909 * @addtogroup DBusString
914 * Get the directory name from a complete filename
915 * @param filename the filename
916 * @param dirname string to append directory name to
917 * @returns #FALSE if no memory
920 _dbus_string_get_dirname(const DBusString *filename,
925 _dbus_assert (filename != dirname);
926 _dbus_assert (filename != NULL);
927 _dbus_assert (dirname != NULL);
929 /* Ignore any separators on the end */
930 sep = _dbus_string_get_length (filename);
932 return _dbus_string_append (dirname, "."); /* empty string passed in */
935 (_dbus_string_get_byte (filename, sep - 1) == '/' ||
936 _dbus_string_get_byte (filename, sep - 1) == '\\'))
939 _dbus_assert (sep >= 0);
943 _dbus_string_get_byte (filename, 1) == ':' &&
944 isalpha (_dbus_string_get_byte (filename, 0))))
945 return _dbus_string_copy_len (filename, 0, sep + 1,
946 dirname, _dbus_string_get_length (dirname));
950 _dbus_string_find_byte_backward (filename, sep, '/', &sep1);
951 _dbus_string_find_byte_backward (filename, sep, '\\', &sep2);
953 sep = MAX (sep1, sep2);
956 return _dbus_string_append (dirname, ".");
959 (_dbus_string_get_byte (filename, sep - 1) == '/' ||
960 _dbus_string_get_byte (filename, sep - 1) == '\\'))
963 _dbus_assert (sep >= 0);
967 _dbus_string_get_byte (filename, 1) == ':' &&
968 isalpha (_dbus_string_get_byte (filename, 0))))
970 (_dbus_string_get_byte (filename, sep) == '/' ||
971 _dbus_string_get_byte (filename, sep) == '\\'))
972 return _dbus_string_copy_len (filename, 0, sep + 1,
973 dirname, _dbus_string_get_length (dirname));
975 return _dbus_string_copy_len (filename, 0, sep - 0,
976 dirname, _dbus_string_get_length (dirname));
979 /** @} */ /* DBusString stuff */