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"
56 /* save string functions version
57 using DBusString needs to much time because of uncommon api
61 errno_t strcat_s(char *dest, int size, char *src)
63 _dbus_assert(strlen(dest) + strlen(src) +1 <= size);
68 errno_t strcpy_s(char *dest, int size, char *src)
70 _dbus_assert(strlen(src) +1 <= size);
77 * Does the chdir, fork, setsid, etc. to become a daemon process.
79 * @param pidfile #NULL, or pidfile to create
80 * @param print_pid_fd file descriptor to print daemon's pid to, or -1 for none
81 * @param error return location for errors
82 * @returns #FALSE on failure
85 _dbus_become_daemon (const DBusString *pidfile,
86 DBusPipe *print_pid_pipe,
93 * Creates a file containing the process ID.
95 * @param filename the filename to write to
96 * @param pid our process ID
97 * @param error return location for errors
98 * @returns #FALSE on failure
101 _dbus_write_pid_file (const DBusString *filename,
105 const char *cfilename;
109 cfilename = _dbus_string_get_const_data (filename);
111 if (!_dbus_file_open(&file, cfilename, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644))
113 dbus_set_error (error, _dbus_error_from_errno (errno),
114 "Failed to open \"%s\": %s", cfilename,
115 _dbus_strerror (errno));
119 if ((f = fdopen (file.FDATA, "w")) == NULL)
121 dbus_set_error (error, _dbus_error_from_errno (errno),
122 "Failed to fdopen fd %d: %s", file.FDATA, _dbus_strerror (errno));
123 _dbus_file_close (&file, NULL);
127 if (fprintf (f, "%lu\n", pid) < 0)
129 dbus_set_error (error, _dbus_error_from_errno (errno),
130 "Failed to write to \"%s\": %s", cfilename,
131 _dbus_strerror (errno));
137 if (fclose (f) == EOF)
139 dbus_set_error (error, _dbus_error_from_errno (errno),
140 "Failed to close \"%s\": %s", cfilename,
141 _dbus_strerror (errno));
149 * Verify that after the fork we can successfully change to this user.
151 * @param user the username given in the daemon configuration
152 * @returns #TRUE if username is valid
155 _dbus_verify_daemon_user (const char *user)
161 * Changes the user and group the bus is running as.
163 * @param user the user to become
164 * @param error return location for errors
165 * @returns #FALSE on failure
168 _dbus_change_to_daemon_user (const char *user,
175 * Changes the user and group the bus is running as.
177 * @param uid the new user ID
178 * @param gid the new group ID
179 * @param error return location for errors
180 * @returns #FALSE on failure
183 _dbus_change_identity (dbus_uid_t uid,
190 /** Checks if user is at the console
192 * @param username user to check
193 * @param error return location for errors
194 * @returns #TRUE is the user is at the consolei and there are no errors
197 _dbus_user_at_console(const char *username,
203 dbus_bool_t retval = FALSE;
206 PSID user_sid, console_user_sid;
209 wusername = _dbus_win_utf8_to_utf16 (username, error);
213 if (!_dbus_win_account_to_sid (wusername, &user_sid, error))
216 /* Now we have the SID for username. Get the SID of the
217 * user at the "console" (window station WinSta0)
219 if (!(winsta = OpenWindowStation ("WinSta0", FALSE, READ_CONTROL)))
221 _dbus_win_set_error_from_win_error (error, GetLastError ());
226 GetUserObjectInformation (winsta, UOI_USER_SID,
227 NULL, 0, &sid_length);
230 /* Nobody is logged on */
234 if (sid_length < 0 || sid_length > 1000)
236 dbus_set_error_const (error, DBUS_ERROR_FAILED, "Invalid SID length");
240 console_user_sid = dbus_malloc (sid_length);
241 if (!console_user_sid)
243 _DBUS_SET_OOM (error);
247 if (!GetUserObjectInformation (winsta, UOI_USER_SID,
248 console_user_sid, sid_length, &sid_length))
250 _dbus_win_set_error_from_win_error (error, GetLastError ());
254 if (!IsValidSid (console_user_sid))
256 dbus_set_error_const (error, DBUS_ERROR_FAILED, "Invalid SID");
260 retval = EqualSid (user_sid, console_user_sid);
263 dbus_free (console_user_sid);
265 CloseWindowStation (winsta);
267 dbus_free (user_sid);
269 dbus_free (wusername);
276 * Removes a directory; Directory must be empty
278 * @param filename directory filename
279 * @param error initialized error object
280 * @returns #TRUE on success
283 _dbus_delete_directory (const DBusString *filename,
286 const char *filename_c;
288 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
290 filename_c = _dbus_string_get_const_data (filename);
292 if (rmdir (filename_c) != 0)
294 dbus_set_error (error, DBUS_ERROR_FAILED,
295 "Failed to remove directory %s: %s\n",
296 filename_c, _dbus_strerror (errno));
303 /** Installs a signal handler
305 * @param sig the signal to handle
306 * @param handler the handler
309 _dbus_set_signal_handler (int sig,
310 DBusSignalHandler handler)
312 _dbus_verbose ("_dbus_set_signal_handler() has to be implemented\n");
315 /** Checks if a file exists
317 * @param file full path to the file
318 * @returns #TRUE if file exists
321 _dbus_file_exists (const char *file)
323 HANDLE h = CreateFile(
324 file, /* LPCTSTR lpFileName*/
325 0, /* DWORD dwDesiredAccess */
326 0, /* DWORD dwShareMode*/
327 NULL, /* LPSECURITY_ATTRIBUTES lpSecurityAttributes */
328 OPEN_EXISTING, /* DWORD dwCreationDisposition */
329 FILE_ATTRIBUTE_NORMAL, /* DWORD dwFlagsAndAttributes */
330 NULL /* HANDLE hTemplateFile */
333 /* file not found, use local copy of session.conf */
334 if (h != INVALID_HANDLE_VALUE && GetLastError() != ERROR_PATH_NOT_FOUND)
346 * @param filename the filename to stat
347 * @param statbuf the stat info to fill in
348 * @param error return location for error
349 * @returns #FALSE if error was set
352 _dbus_stat(const DBusString *filename,
360 const char *filename_c;
361 #if !defined(DBUS_WIN) && !defined(DBUS_WINCE)
366 WIN32_FILE_ATTRIBUTE_DATA wfad;
369 PSID owner_sid, group_sid;
370 PSECURITY_DESCRIPTOR sd;
373 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
375 filename_c = _dbus_string_get_const_data (filename);
377 if (!GetFileAttributesEx (filename_c, GetFileExInfoStandard, &wfad))
379 _dbus_win_set_error_from_win_error (error, GetLastError ());
383 if (wfad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
384 statbuf->mode = _S_IFDIR;
386 statbuf->mode = _S_IFREG;
388 statbuf->mode |= _S_IREAD;
389 if (wfad.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
390 statbuf->mode |= _S_IWRITE;
392 lastdot = strrchr (filename_c, '.');
393 if (lastdot && stricmp (lastdot, ".exe") == 0)
394 statbuf->mode |= _S_IEXEC;
396 statbuf->mode |= (statbuf->mode & 0700) >> 3;
397 statbuf->mode |= (statbuf->mode & 0700) >> 6;
402 rc = GetNamedSecurityInfo ((char *) filename_c, SE_FILE_OBJECT,
403 OWNER_SECURITY_INFORMATION |
404 GROUP_SECURITY_INFORMATION,
405 &owner_sid, &group_sid,
408 if (rc != ERROR_SUCCESS)
410 _dbus_win_set_error_from_win_error (error, rc);
416 statbuf->uid = _dbus_win_sid_to_uid_t (owner_sid);
417 statbuf->gid = _dbus_win_sid_to_uid_t (group_sid);
421 statbuf->size = ((dbus_int64_t) wfad.nFileSizeHigh << 32) + wfad.nFileSizeLow;
424 (((dbus_int64_t) wfad.ftLastAccessTime.dwHighDateTime << 32) +
425 wfad.ftLastAccessTime.dwLowDateTime) / 10000000 - DBUS_INT64_CONSTANT (116444736000000000);
428 (((dbus_int64_t) wfad.ftLastWriteTime.dwHighDateTime << 32) +
429 wfad.ftLastWriteTime.dwLowDateTime) / 10000000 - DBUS_INT64_CONSTANT (116444736000000000);
432 (((dbus_int64_t) wfad.ftCreationTime.dwHighDateTime << 32) +
433 wfad.ftCreationTime.dwLowDateTime) / 10000000 - DBUS_INT64_CONSTANT (116444736000000000);
442 // mingw ships with dirent.h
444 #define _dbus_opendir opendir
445 #define _dbus_readdir readdir
446 #define _dbus_closedir closedir
451 #include <io.h> // win32 file functions
454 #include <sys/types.h>
457 /* This file is part of the KDE project
458 Copyright (C) 2000 Werner Almesberger
460 libc/sys/linux/sys/dirent.h - Directory entry as returned by readdir
462 This program is free software; you can redistribute it and/or
463 modify it under the terms of the GNU Library General Public
464 License as published by the Free Software Foundation; either
465 version 2 of the License, or (at your option) any later version.
467 This program is distributed in the hope that it will be useful,
468 but WITHOUT ANY WARRANTY; without even the implied warranty of
469 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
470 Library General Public License for more details.
472 You should have received a copy of the GNU Library General Public License
473 along with this program; see the file COPYING. If not, write to
474 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
475 Boston, MA 02110-1301, USA.
477 #define HAVE_NO_D_NAMLEN /* no struct dirent->d_namlen */
478 #define HAVE_DD_LOCK /* have locking mechanism */
480 #define MAXNAMLEN 255 /* sizeof(struct dirent.d_name)-1 */
482 #define __dirfd(dir) (dir)->dd_fd
484 /* struct dirent - same as Unix */
487 long d_ino; /* inode (always 1 in WIN32) */
488 off_t d_off; /* offset to this dirent */
489 unsigned short d_reclen; /* length of d_name */
490 char d_name[_MAX_FNAME+1]; /* filename (null terminated) */
493 /* typedef DIR - not the same as Unix */
496 long handle; /* _findfirst/_findnext handle */
497 short offset; /* offset into directory */
498 short finished; /* 1 if there are not more files */
499 struct _finddata_t fileinfo; /* from _findfirst/_findnext */
500 char *dir; /* the dir we are reading */
501 struct dirent dent; /* the dirent to return */
505 /**********************************************************************
506 * Implement dirent-style opendir/readdir/closedir on Window 95/NT
508 * Functions defined are opendir(), readdir() and closedir() with the
509 * same prototypes as the normal dirent.h implementation.
511 * Does not implement telldir(), seekdir(), rewinddir() or scandir().
512 * The dirent struct is compatible with Unix, except that d_ino is
513 * always 1 and d_off is made up as we go along.
515 * The DIR typedef is not compatible with Unix.
516 **********************************************************************/
518 DIR * _dbus_opendir(const char *dir)
525 filespec = malloc(strlen(dir) + 2 + 1);
526 strcpy(filespec, dir);
527 index = strlen(filespec) - 1;
528 if (index >= 0 && (filespec[index] == '/' || filespec[index] == '\\'))
529 filespec[index] = '\0';
530 strcat(filespec, "\\*");
532 dp = (DIR *)malloc(sizeof(DIR));
535 dp->dir = strdup(dir);
537 if ((handle = _findfirst(filespec, &(dp->fileinfo))) < 0)
551 struct dirent * _dbus_readdir(DIR *dp)
553 if (!dp || dp->finished)
558 if (_findnext(dp->handle, &(dp->fileinfo)) < 0)
567 strncpy(dp->dent.d_name, dp->fileinfo.name, _MAX_FNAME);
569 dp->dent.d_reclen = strlen(dp->dent.d_name);
570 dp->dent.d_off = dp->offset;
576 int _dbus_closedir(DIR *dp)
580 _findclose(dp->handle);
589 #endif //#ifdef HAVE_DIRENT_H
592 * Internals of directory iterator
596 DIR *d; /**< The DIR* from opendir() */
601 * Open a directory to iterate over.
603 * @param filename the directory name
604 * @param error exception return object or #NULL
605 * @returns new iterator, or #NULL on error
608 _dbus_directory_open (const DBusString *filename,
613 const char *filename_c;
615 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
617 filename_c = _dbus_string_get_const_data (filename);
619 d = _dbus_opendir (filename_c);
622 dbus_set_error (error, _dbus_error_from_errno (errno),
623 "Failed to read directory \"%s\": %s",
625 _dbus_strerror (errno));
628 iter = dbus_new0 (DBusDirIter, 1);
632 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
633 "Could not allocate memory for directory iterator");
643 * Get next file in the directory. Will not return "." or ".." on
644 * UNIX. If an error occurs, the contents of "filename" are
645 * undefined. The error is never set if the function succeeds.
647 * @todo for thread safety, I think we have to use
648 * readdir_r(). (GLib has the same issue, should file a bug.)
650 * @param iter the iterator
651 * @param filename string to be set to the next file in the dir
652 * @param error return location for error
653 * @returns #TRUE if filename was filled in with a new filename
656 _dbus_directory_get_next_file (DBusDirIter *iter,
657 DBusString *filename,
662 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
666 ent = _dbus_readdir (iter->d);
670 dbus_set_error (error,
671 _dbus_error_from_errno (errno),
672 "%s", _dbus_strerror (errno));
675 else if (ent->d_name[0] == '.' &&
676 (ent->d_name[1] == '\0' ||
677 (ent->d_name[1] == '.' && ent->d_name[2] == '\0')))
681 _dbus_string_set_length (filename, 0);
682 if (!_dbus_string_append (filename, ent->d_name))
684 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
685 "No memory to read directory entry");
694 * Closes a directory iteration.
697 _dbus_directory_close (DBusDirIter *iter)
699 _dbus_closedir (iter->d);
704 * Checks whether the filename is an absolute path
706 * @param filename the filename
707 * @returns #TRUE if an absolute path
710 _dbus_path_is_absolute (const DBusString *filename)
712 if (_dbus_string_get_length (filename) > 0)
713 return _dbus_string_get_byte (filename, 1) == ':'
714 || _dbus_string_get_byte (filename, 0) == '\\'
715 || _dbus_string_get_byte (filename, 0) == '/';
720 #ifdef ENABLE_DBUSGROPINFO
722 fill_group_info(DBusGroupInfo *info,
724 const DBusString *groupname,
727 const char *group_c_str;
729 _dbus_assert (groupname != NULL || gid != DBUS_GID_UNSET);
730 _dbus_assert (groupname == NULL || gid == DBUS_GID_UNSET);
733 group_c_str = _dbus_string_get_const_data (groupname);
740 wchar_t *wgroupname = _dbus_win_utf8_to_utf16 (group_c_str, error);
745 if (!_dbus_win_account_to_sid (wgroupname, &group_sid, error))
747 dbus_free (wgroupname);
751 info->gid = _dbus_win_sid_to_uid_t (group_sid);
752 info->groupname = _dbus_strdup (group_c_str);
754 dbus_free (group_sid);
755 dbus_free (wgroupname);
761 dbus_bool_t retval = FALSE;
762 wchar_t *wname, *wdomain;
767 if (!_dbus_win_sid_to_name_and_domain (gid, &wname, &wdomain, error))
770 name = _dbus_win_utf16_to_utf8 (wname, error);
774 domain = _dbus_win_utf16_to_utf8 (wdomain, error);
778 info->groupname = dbus_malloc (strlen (domain) + 1 + strlen (name) + 1);
780 strcpy (info->groupname, domain);
781 strcat (info->groupname, "\\");
782 strcat (info->groupname, name);
798 * Initializes the given DBusGroupInfo struct
799 * with information about the given group ID.
801 * @param info the group info struct
802 * @param gid group ID
803 * @param error the error return
804 * @returns #FALSE if error is set
807 _dbus_group_info_fill_gid (DBusGroupInfo *info,
811 return fill_group_info (info, gid, NULL, error);
815 * Initializes the given DBusGroupInfo struct
816 * with information about the given group name.
818 * @param info the group info struct
819 * @param groupname name of group
820 * @param error the error return
821 * @returns #FALSE if error is set
824 _dbus_group_info_fill (DBusGroupInfo *info,
825 const DBusString *groupname,
828 return fill_group_info (info, DBUS_GID_UNSET,
833 /** @} */ /* End of DBusInternalsUtils functions */
836 * @addtogroup DBusString
841 * Get the directory name from a complete filename
842 * @param filename the filename
843 * @param dirname string to append directory name to
844 * @returns #FALSE if no memory
847 _dbus_string_get_dirname(const DBusString *filename,
852 _dbus_assert (filename != dirname);
853 _dbus_assert (filename != NULL);
854 _dbus_assert (dirname != NULL);
856 /* Ignore any separators on the end */
857 sep = _dbus_string_get_length (filename);
859 return _dbus_string_append (dirname, "."); /* empty string passed in */
862 (_dbus_string_get_byte (filename, sep - 1) == '/' ||
863 _dbus_string_get_byte (filename, sep - 1) == '\\'))
866 _dbus_assert (sep >= 0);
870 _dbus_string_get_byte (filename, 1) == ':' &&
871 isalpha (_dbus_string_get_byte (filename, 0))))
872 return _dbus_string_copy_len (filename, 0, sep + 1,
873 dirname, _dbus_string_get_length (dirname));
877 _dbus_string_find_byte_backward (filename, sep, '/', &sep1);
878 _dbus_string_find_byte_backward (filename, sep, '\\', &sep2);
880 sep = MAX (sep1, sep2);
883 return _dbus_string_append (dirname, ".");
886 (_dbus_string_get_byte (filename, sep - 1) == '/' ||
887 _dbus_string_get_byte (filename, sep - 1) == '\\'))
890 _dbus_assert (sep >= 0);
894 _dbus_string_get_byte (filename, 1) == ':' &&
895 isalpha (_dbus_string_get_byte (filename, 0))))
897 (_dbus_string_get_byte (filename, sep) == '/' ||
898 _dbus_string_get_byte (filename, sep) == '\\'))
899 return _dbus_string_copy_len (filename, 0, sep + 1,
900 dirname, _dbus_string_get_length (dirname));
902 return _dbus_string_copy_len (filename, 0, sep - 0,
903 dirname, _dbus_string_get_length (dirname));
908 * Checks to see if the UNIX user ID matches the UID of
909 * the process. Should always return #FALSE on Windows.
911 * @param uid the UNIX user ID
912 * @returns #TRUE if this uid owns the process.
915 _dbus_unix_user_is_process_owner (dbus_uid_t uid)
920 /*=====================================================================
921 unix emulation functions - should be removed sometime in the future
922 =====================================================================*/
925 * Checks to see if the UNIX user ID is at the console.
926 * Should always fail on Windows (set the error to
927 * #DBUS_ERROR_NOT_SUPPORTED).
929 * @param uid UID of person to check
930 * @param error return location for errors
931 * @returns #TRUE if the UID is the same as the console user and there are no errors
934 _dbus_unix_user_is_at_console (dbus_uid_t uid,
942 * Parse a UNIX group from the bus config file. On Windows, this should
943 * simply always fail (just return #FALSE).
945 * @param groupname the groupname text
946 * @param gid_p place to return the gid
947 * @returns #TRUE on success
950 _dbus_parse_unix_group_from_config (const DBusString *groupname,
957 * Parse a UNIX user from the bus config file. On Windows, this should
958 * simply always fail (just return #FALSE).
960 * @param username the username text
961 * @param uid_p place to return the uid
962 * @returns #TRUE on success
965 _dbus_parse_unix_user_from_config (const DBusString *username,
973 * Gets all groups corresponding to the given UNIX user ID. On UNIX,
974 * just calls _dbus_groups_from_uid(). On Windows, should always
975 * fail since we don't know any UNIX groups.
978 * @param group_ids return location for array of group IDs
979 * @param n_group_ids return location for length of returned array
980 * @returns #TRUE if the UID existed and we got some credentials
983 _dbus_unix_groups_from_uid (dbus_uid_t uid,
984 dbus_gid_t **group_ids,
992 /** @} */ /* DBusString stuff */