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 * Does the chdir, fork, setsid, etc. to become a daemon process.
48 * @param pidfile #NULL, or pidfile to create
49 * @param print_pid_fd file descriptor to print daemon's pid to, or -1 for none
50 * @param error return location for errors
51 * @returns #FALSE on failure
54 _dbus_become_daemon (const DBusString *pidfile,
55 DBusPipe print_pid_fd,
62 * Creates a file containing the process ID.
64 * @param filename the filename to write to
65 * @param pid our process ID
66 * @param error return location for errors
67 * @returns #FALSE on failure
70 _dbus_write_pid_file (const DBusString *filename,
74 const char *cfilename;
78 cfilename = _dbus_string_get_const_data (filename);
80 if (!_dbus_file_open(&file, cfilename, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644))
82 dbus_set_error (error, _dbus_error_from_errno (errno),
83 "Failed to open \"%s\": %s", cfilename,
84 _dbus_strerror (errno));
88 if ((f = fdopen (file.FDATA, "w")) == NULL)
90 dbus_set_error (error, _dbus_error_from_errno (errno),
91 "Failed to fdopen fd %d: %s", file.FDATA, _dbus_strerror (errno));
92 _dbus_file_close (&file, NULL);
96 if (fprintf (f, "%lu\n", pid) < 0)
98 dbus_set_error (error, _dbus_error_from_errno (errno),
99 "Failed to write to \"%s\": %s", cfilename,
100 _dbus_strerror (errno));
106 if (fclose (f) == EOF)
108 dbus_set_error (error, _dbus_error_from_errno (errno),
109 "Failed to close \"%s\": %s", cfilename,
110 _dbus_strerror (errno));
118 * Changes the user and group the bus is running as.
120 * @param uid the new user ID
121 * @param gid the new group ID
122 * @param error return location for errors
123 * @returns #FALSE on failure
126 _dbus_change_identity (dbus_uid_t uid,
133 /** Checks if user is at the console
135 * @param username user to check
136 * @param error return location for errors
137 * @returns #TRUE is the user is at the consolei and there are no errors
140 _dbus_user_at_console(const char *username,
146 dbus_bool_t retval = FALSE;
149 PSID user_sid, console_user_sid;
152 wusername = _dbus_win_utf8_to_utf16 (username, error);
156 if (!_dbus_win_account_to_sid (wusername, &user_sid, error))
159 /* Now we have the SID for username. Get the SID of the
160 * user at the "console" (window station WinSta0)
162 if (!(winsta = OpenWindowStation ("WinSta0", FALSE, READ_CONTROL)))
164 _dbus_win_set_error_from_win_error (error, GetLastError ());
169 GetUserObjectInformation (winsta, UOI_USER_SID,
170 NULL, 0, &sid_length);
173 /* Nobody is logged on */
177 if (sid_length < 0 || sid_length > 1000)
179 dbus_set_error_const (error, DBUS_ERROR_FAILED, "Invalid SID length");
183 console_user_sid = dbus_malloc (sid_length);
184 if (!console_user_sid)
186 _DBUS_SET_OOM (error);
190 if (!GetUserObjectInformation (winsta, UOI_USER_SID,
191 console_user_sid, sid_length, &sid_length))
193 _dbus_win_set_error_from_win_error (error, GetLastError ());
197 if (!IsValidSid (console_user_sid))
199 dbus_set_error_const (error, DBUS_ERROR_FAILED, "Invalid SID");
203 retval = EqualSid (user_sid, console_user_sid);
206 dbus_free (console_user_sid);
208 CloseWindowStation (winsta);
210 dbus_free (user_sid);
212 dbus_free (wusername);
219 * Removes a directory; Directory must be empty
221 * @param filename directory filename
222 * @param error initialized error object
223 * @returns #TRUE on success
226 _dbus_delete_directory (const DBusString *filename,
229 const char *filename_c;
231 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
233 filename_c = _dbus_string_get_const_data (filename);
235 if (rmdir (filename_c) != 0)
237 dbus_set_error (error, DBUS_ERROR_FAILED,
238 "Failed to remove directory %s: %s\n",
239 filename_c, _dbus_strerror (errno));
246 /** Installs a signal handler
248 * @param sig the signal to handle
249 * @param handler the handler
252 _dbus_set_signal_handler (int sig,
253 DBusSignalHandler handler)
255 _dbus_verbose ("_dbus_set_signal_handler() has to be implemented\n");
261 * @param filename the filename to stat
262 * @param statbuf the stat info to fill in
263 * @param error return location for error
264 * @returns #FALSE if error was set
267 _dbus_stat(const DBusString *filename,
275 const char *filename_c;
276 #if !defined(DBUS_WIN) && !defined(DBUS_WINCE)
281 WIN32_FILE_ATTRIBUTE_DATA wfad;
284 PSID owner_sid, group_sid;
285 PSECURITY_DESCRIPTOR sd;
288 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
290 filename_c = _dbus_string_get_const_data (filename);
292 if (!GetFileAttributesEx (filename_c, GetFileExInfoStandard, &wfad))
294 _dbus_win_set_error_from_win_error (error, GetLastError ());
298 if (wfad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
299 statbuf->mode = _S_IFDIR;
301 statbuf->mode = _S_IFREG;
303 statbuf->mode |= _S_IREAD;
304 if (wfad.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
305 statbuf->mode |= _S_IWRITE;
307 lastdot = strrchr (filename_c, '.');
308 if (lastdot && stricmp (lastdot, ".exe") == 0)
309 statbuf->mode |= _S_IEXEC;
311 statbuf->mode |= (statbuf->mode & 0700) >> 3;
312 statbuf->mode |= (statbuf->mode & 0700) >> 6;
317 rc = GetNamedSecurityInfo ((char *) filename_c, SE_FILE_OBJECT,
318 OWNER_SECURITY_INFORMATION |
319 GROUP_SECURITY_INFORMATION,
320 &owner_sid, &group_sid,
323 if (rc != ERROR_SUCCESS)
325 _dbus_win_set_error_from_win_error (error, rc);
331 statbuf->uid = _dbus_win_sid_to_uid_t (owner_sid);
332 statbuf->gid = _dbus_win_sid_to_uid_t (group_sid);
336 statbuf->size = ((dbus_int64_t) wfad.nFileSizeHigh << 32) + wfad.nFileSizeLow;
339 (((dbus_int64_t) wfad.ftLastAccessTime.dwHighDateTime << 32) +
340 wfad.ftLastAccessTime.dwLowDateTime) / 10000000 - DBUS_INT64_CONSTANT (116444736000000000);
343 (((dbus_int64_t) wfad.ftLastWriteTime.dwHighDateTime << 32) +
344 wfad.ftLastWriteTime.dwLowDateTime) / 10000000 - DBUS_INT64_CONSTANT (116444736000000000);
347 (((dbus_int64_t) wfad.ftCreationTime.dwHighDateTime << 32) +
348 wfad.ftCreationTime.dwLowDateTime) / 10000000 - DBUS_INT64_CONSTANT (116444736000000000);
357 // mingw ships with dirent.h
359 #define _dbus_opendir opendir
360 #define _dbus_readdir readdir
361 #define _dbus_closedir closedir
366 #include <io.h> // win32 file functions
369 #include <sys/types.h>
372 /* This file is part of the KDE project
373 Copyright (C) 2000 Werner Almesberger
375 libc/sys/linux/sys/dirent.h - Directory entry as returned by readdir
377 This program is free software; you can redistribute it and/or
378 modify it under the terms of the GNU Library General Public
379 License as published by the Free Software Foundation; either
380 version 2 of the License, or (at your option) any later version.
382 This program is distributed in the hope that it will be useful,
383 but WITHOUT ANY WARRANTY; without even the implied warranty of
384 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
385 Library General Public License for more details.
387 You should have received a copy of the GNU Library General Public License
388 along with this program; see the file COPYING. If not, write to
389 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
390 Boston, MA 02110-1301, USA.
392 #define HAVE_NO_D_NAMLEN /* no struct dirent->d_namlen */
393 #define HAVE_DD_LOCK /* have locking mechanism */
395 #define MAXNAMLEN 255 /* sizeof(struct dirent.d_name)-1 */
397 #define __dirfd(dir) (dir)->dd_fd
399 /* struct dirent - same as Unix */
402 long d_ino; /* inode (always 1 in WIN32) */
403 off_t d_off; /* offset to this dirent */
404 unsigned short d_reclen; /* length of d_name */
405 char d_name[_MAX_FNAME+1]; /* filename (null terminated) */
408 /* typedef DIR - not the same as Unix */
411 long handle; /* _findfirst/_findnext handle */
412 short offset; /* offset into directory */
413 short finished; /* 1 if there are not more files */
414 struct _finddata_t fileinfo; /* from _findfirst/_findnext */
415 char *dir; /* the dir we are reading */
416 struct dirent dent; /* the dirent to return */
420 /**********************************************************************
421 * Implement dirent-style opendir/readdir/closedir on Window 95/NT
423 * Functions defined are opendir(), readdir() and closedir() with the
424 * same prototypes as the normal dirent.h implementation.
426 * Does not implement telldir(), seekdir(), rewinddir() or scandir().
427 * The dirent struct is compatible with Unix, except that d_ino is
428 * always 1 and d_off is made up as we go along.
430 * The DIR typedef is not compatible with Unix.
431 **********************************************************************/
433 DIR * _dbus_opendir(const char *dir)
440 filespec = malloc(strlen(dir) + 2 + 1);
441 strcpy(filespec, dir);
442 index = strlen(filespec) - 1;
443 if (index >= 0 && (filespec[index] == '/' || filespec[index] == '\\'))
444 filespec[index] = '\0';
445 strcat(filespec, "\\*");
447 dp = (DIR *)malloc(sizeof(DIR));
450 dp->dir = strdup(dir);
452 if ((handle = _findfirst(filespec, &(dp->fileinfo))) < 0)
466 struct dirent * _dbus_readdir(DIR *dp)
468 if (!dp || dp->finished)
473 if (_findnext(dp->handle, &(dp->fileinfo)) < 0)
482 strncpy(dp->dent.d_name, dp->fileinfo.name, _MAX_FNAME);
484 dp->dent.d_reclen = strlen(dp->dent.d_name);
485 dp->dent.d_off = dp->offset;
491 int _dbus_closedir(DIR *dp)
495 _findclose(dp->handle);
504 #endif //#ifdef HAVE_DIRENT_H
507 * Internals of directory iterator
511 DIR *d; /**< The DIR* from opendir() */
516 * Open a directory to iterate over.
518 * @param filename the directory name
519 * @param error exception return object or #NULL
520 * @returns new iterator, or #NULL on error
523 _dbus_directory_open (const DBusString *filename,
528 const char *filename_c;
530 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
532 filename_c = _dbus_string_get_const_data (filename);
534 d = _dbus_opendir (filename_c);
537 dbus_set_error (error, _dbus_error_from_errno (errno),
538 "Failed to read directory \"%s\": %s",
540 _dbus_strerror (errno));
543 iter = dbus_new0 (DBusDirIter, 1);
547 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
548 "Could not allocate memory for directory iterator");
558 * Get next file in the directory. Will not return "." or ".." on
559 * UNIX. If an error occurs, the contents of "filename" are
560 * undefined. The error is never set if the function succeeds.
562 * @todo for thread safety, I think we have to use
563 * readdir_r(). (GLib has the same issue, should file a bug.)
565 * @param iter the iterator
566 * @param filename string to be set to the next file in the dir
567 * @param error return location for error
568 * @returns #TRUE if filename was filled in with a new filename
571 _dbus_directory_get_next_file (DBusDirIter *iter,
572 DBusString *filename,
577 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
581 ent = _dbus_readdir (iter->d);
585 dbus_set_error (error,
586 _dbus_error_from_errno (errno),
587 "%s", _dbus_strerror (errno));
590 else if (ent->d_name[0] == '.' &&
591 (ent->d_name[1] == '\0' ||
592 (ent->d_name[1] == '.' && ent->d_name[2] == '\0')))
596 _dbus_string_set_length (filename, 0);
597 if (!_dbus_string_append (filename, ent->d_name))
599 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
600 "No memory to read directory entry");
609 * Closes a directory iteration.
612 _dbus_directory_close (DBusDirIter *iter)
614 _dbus_closedir (iter->d);
619 * Checks whether the filename is an absolute path
621 * @param filename the filename
622 * @returns #TRUE if an absolute path
625 _dbus_path_is_absolute (const DBusString *filename)
627 if (_dbus_string_get_length (filename) > 0)
628 return _dbus_string_get_byte (filename, 1) == ':'
629 || _dbus_string_get_byte (filename, 0) == '\\'
630 || _dbus_string_get_byte (filename, 0) == '/';
637 fill_group_info(DBusGroupInfo *info,
639 const DBusString *groupname,
642 const char *group_c_str;
644 _dbus_assert (groupname != NULL || gid != DBUS_GID_UNSET);
645 _dbus_assert (groupname == NULL || gid == DBUS_GID_UNSET);
648 group_c_str = _dbus_string_get_const_data (groupname);
655 wchar_t *wgroupname = _dbus_win_utf8_to_utf16 (group_c_str, error);
660 if (!_dbus_win_account_to_sid (wgroupname, &group_sid, error))
662 dbus_free (wgroupname);
666 info->gid = _dbus_win_sid_to_uid_t (group_sid);
667 info->groupname = _dbus_strdup (group_c_str);
669 dbus_free (group_sid);
670 dbus_free (wgroupname);
676 dbus_bool_t retval = FALSE;
677 wchar_t *wname, *wdomain;
682 if (!_dbus_win_sid_to_name_and_domain (gid, &wname, &wdomain, error))
685 name = _dbus_win_utf16_to_utf8 (wname, error);
689 domain = _dbus_win_utf16_to_utf8 (wdomain, error);
693 info->groupname = dbus_malloc (strlen (domain) + 1 + strlen (name) + 1);
695 strcpy (info->groupname, domain);
696 strcat (info->groupname, "\\");
697 strcat (info->groupname, name);
713 * Initializes the given DBusGroupInfo struct
714 * with information about the given group ID.
716 * @param info the group info struct
717 * @param gid group ID
718 * @param error the error return
719 * @returns #FALSE if error is set
722 _dbus_group_info_fill_gid (DBusGroupInfo *info,
726 return fill_group_info (info, gid, NULL, error);
730 * Initializes the given DBusGroupInfo struct
731 * with information about the given group name.
733 * @param info the group info struct
734 * @param groupname name of group
735 * @param error the error return
736 * @returns #FALSE if error is set
739 _dbus_group_info_fill (DBusGroupInfo *info,
740 const DBusString *groupname,
743 return fill_group_info (info, DBUS_GID_UNSET,
747 /** @} */ /* End of DBusInternalsUtils functions */
750 * @addtogroup DBusString
755 * Get the directory name from a complete filename
756 * @param filename the filename
757 * @param dirname string to append directory name to
758 * @returns #FALSE if no memory
761 _dbus_string_get_dirname(const DBusString *filename,
766 _dbus_assert (filename != dirname);
767 _dbus_assert (filename != NULL);
768 _dbus_assert (dirname != NULL);
770 /* Ignore any separators on the end */
771 sep = _dbus_string_get_length (filename);
773 return _dbus_string_append (dirname, "."); /* empty string passed in */
776 (_dbus_string_get_byte (filename, sep - 1) == '/' ||
777 _dbus_string_get_byte (filename, sep - 1) == '\\'))
780 _dbus_assert (sep >= 0);
784 _dbus_string_get_byte (filename, 1) == ':' &&
785 isalpha (_dbus_string_get_byte (filename, 0))))
786 return _dbus_string_copy_len (filename, 0, sep + 1,
787 dirname, _dbus_string_get_length (dirname));
791 _dbus_string_find_byte_backward (filename, sep, '/', &sep1);
792 _dbus_string_find_byte_backward (filename, sep, '\\', &sep2);
794 sep = MAX (sep1, sep2);
797 return _dbus_string_append (dirname, ".");
800 (_dbus_string_get_byte (filename, sep - 1) == '/' ||
801 _dbus_string_get_byte (filename, sep - 1) == '\\'))
804 _dbus_assert (sep >= 0);
808 _dbus_string_get_byte (filename, 1) == ':' &&
809 isalpha (_dbus_string_get_byte (filename, 0))))
811 (_dbus_string_get_byte (filename, sep) == '/' ||
812 _dbus_string_get_byte (filename, sep) == '\\'))
813 return _dbus_string_copy_len (filename, 0, sep + 1,
814 dirname, _dbus_string_get_length (dirname));
816 return _dbus_string_copy_len (filename, 0, sep - 0,
817 dirname, _dbus_string_get_length (dirname));
820 /** @} */ /* DBusString stuff */