1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-sysdeps-util-unix.c Would be in dbus-sysdeps-unix.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
24 #include "dbus-sysdeps.h"
25 #include "dbus-internals.h"
26 #include "dbus-protocol.h"
27 #include "dbus-string.h"
28 #define DBUS_USERDB_INCLUDES_PRIVATE 1
29 #include "dbus-userdb.h"
30 #include "dbus-test.h"
32 #include <sys/types.h>
42 #include <sys/socket.h>
51 * @addtogroup DBusInternalsUtils
56 * Does the chdir, fork, setsid, etc. to become a daemon process.
58 * @param pidfile #NULL, or pidfile to create
59 * @param print_pid_fd file descriptor to print daemon's pid to, or -1 for none
60 * @param error return location for errors
61 * @returns #FALSE on failure
64 _dbus_become_daemon (const DBusString *pidfile,
72 _dbus_verbose ("Becoming a daemon...\n");
74 _dbus_verbose ("chdir to /\n");
77 dbus_set_error (error, DBUS_ERROR_FAILED,
78 "Could not chdir() to root directory");
82 _dbus_verbose ("forking...\n");
83 switch ((child_pid = fork ()))
86 _dbus_verbose ("fork failed\n");
87 dbus_set_error (error, _dbus_error_from_errno (errno),
88 "Failed to fork daemon: %s", _dbus_strerror (errno));
93 _dbus_verbose ("in child, closing std file descriptors\n");
95 /* silently ignore failures here, if someone
96 * doesn't have /dev/null we may as well try
100 dev_null_fd = open ("/dev/null", O_RDWR);
101 if (dev_null_fd >= 0)
103 dup2 (dev_null_fd, 0);
104 dup2 (dev_null_fd, 1);
106 s = _dbus_getenv ("DBUS_DEBUG_OUTPUT");
107 if (s == NULL || *s == '\0')
108 dup2 (dev_null_fd, 2);
110 _dbus_verbose ("keeping stderr open due to DBUS_DEBUG_OUTPUT\n");
113 /* Get a predictable umask */
114 _dbus_verbose ("setting umask\n");
121 _dbus_verbose ("parent writing pid file\n");
122 if (!_dbus_write_pid_file (pidfile,
126 _dbus_verbose ("pid file write failed, killing child\n");
127 kill (child_pid, SIGTERM);
132 /* Write PID if requested */
133 if (print_pid_fd >= 0)
138 if (!_dbus_string_init (&pid))
140 _DBUS_SET_OOM (error);
141 kill (child_pid, SIGTERM);
145 if (!_dbus_string_append_int (&pid, child_pid) ||
146 !_dbus_string_append (&pid, "\n"))
148 _dbus_string_free (&pid);
149 _DBUS_SET_OOM (error);
150 kill (child_pid, SIGTERM);
154 bytes = _dbus_string_get_length (&pid);
155 if (_dbus_write (print_pid_fd, &pid, 0, bytes) != bytes)
157 dbus_set_error (error, DBUS_ERROR_FAILED,
158 "Printing message bus PID: %s\n",
159 _dbus_strerror (errno));
160 _dbus_string_free (&pid);
161 kill (child_pid, SIGTERM);
165 _dbus_string_free (&pid);
167 _dbus_verbose ("parent exiting\n");
172 _dbus_verbose ("calling setsid()\n");
174 _dbus_assert_not_reached ("setsid() failed");
181 * Creates a file containing the process ID.
183 * @param filename the filename to write to
184 * @param pid our process ID
185 * @param error return location for errors
186 * @returns #FALSE on failure
189 _dbus_write_pid_file (const DBusString *filename,
193 const char *cfilename;
197 cfilename = _dbus_string_get_const_data (filename);
199 fd = open (cfilename, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644);
203 dbus_set_error (error, _dbus_error_from_errno (errno),
204 "Failed to open \"%s\": %s", cfilename,
205 _dbus_strerror (errno));
209 if ((f = fdopen (fd, "w")) == NULL)
211 dbus_set_error (error, _dbus_error_from_errno (errno),
212 "Failed to fdopen fd %d: %s", fd, _dbus_strerror (errno));
217 if (fprintf (f, "%lu\n", pid) < 0)
219 dbus_set_error (error, _dbus_error_from_errno (errno),
220 "Failed to write to \"%s\": %s", cfilename,
221 _dbus_strerror (errno));
227 if (fclose (f) == EOF)
229 dbus_set_error (error, _dbus_error_from_errno (errno),
230 "Failed to close \"%s\": %s", cfilename,
231 _dbus_strerror (errno));
240 * Changes the user and group the bus is running as.
242 * @param uid the new user ID
243 * @param gid the new group ID
244 * @param error return location for errors
245 * @returns #FALSE on failure
248 _dbus_change_identity (dbus_uid_t uid,
252 /* setgroups() only works if we are a privileged process,
253 * so we don't return error on failure; the only possible
254 * failure is that we don't have perms to do it.
256 * not sure this is right, maybe if setuid()
257 * is going to work then setgroups() should also work.
259 if (setgroups (0, NULL) < 0)
260 _dbus_warn ("Failed to drop supplementary groups: %s\n",
261 _dbus_strerror (errno));
263 /* Set GID first, or the setuid may remove our permission
266 if (setgid (gid) < 0)
268 dbus_set_error (error, _dbus_error_from_errno (errno),
269 "Failed to set GID to %lu: %s", gid,
270 _dbus_strerror (errno));
274 if (setuid (uid) < 0)
276 dbus_set_error (error, _dbus_error_from_errno (errno),
277 "Failed to set UID to %lu: %s", uid,
278 _dbus_strerror (errno));
285 /** Installs a UNIX signal handler
287 * @param sig the signal to handle
288 * @param handler the handler
291 _dbus_set_signal_handler (int sig,
292 DBusSignalHandler handler)
294 struct sigaction act;
297 sigemptyset (&empty_mask);
298 act.sa_handler = handler;
299 act.sa_mask = empty_mask;
301 sigaction (sig, &act, NULL);
306 * Removes a directory; Directory must be empty
308 * @param filename directory filename
309 * @param error initialized error object
310 * @returns #TRUE on success
313 _dbus_delete_directory (const DBusString *filename,
316 const char *filename_c;
318 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
320 filename_c = _dbus_string_get_const_data (filename);
322 if (rmdir (filename_c) != 0)
324 dbus_set_error (error, DBUS_ERROR_FAILED,
325 "Failed to remove directory %s: %s\n",
326 filename_c, _dbus_strerror (errno));
333 /** Checks if a file exists
335 * @param file full path to the file
336 * @returns #TRUE if file exists
339 _dbus_file_exists (const char *file)
341 return (access (file, F_OK) == 0);
344 /** Checks if user is at the console
346 * @param username user to check
347 * @param error return location for errors
348 * @returns #TRUE is the user is at the consolei and there are no errors
351 _dbus_user_at_console (const char *username,
359 if (!_dbus_string_init (&f))
361 _DBUS_SET_OOM (error);
365 if (!_dbus_string_append (&f, DBUS_CONSOLE_AUTH_DIR))
367 _DBUS_SET_OOM (error);
372 if (!_dbus_string_append (&f, username))
374 _DBUS_SET_OOM (error);
378 result = _dbus_file_exists (_dbus_string_get_const_data (&f));
381 _dbus_string_free (&f);
388 * Checks whether the filename is an absolute path
390 * @param filename the filename
391 * @returns #TRUE if an absolute path
394 _dbus_path_is_absolute (const DBusString *filename)
396 if (_dbus_string_get_length (filename) > 0)
397 return _dbus_string_get_byte (filename, 0) == '/';
405 * @param filename the filename to stat
406 * @param statbuf the stat info to fill in
407 * @param error return location for error
408 * @returns #FALSE if error was set
411 _dbus_stat (const DBusString *filename,
415 const char *filename_c;
418 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
420 filename_c = _dbus_string_get_const_data (filename);
422 if (stat (filename_c, &sb) < 0)
424 dbus_set_error (error, _dbus_error_from_errno (errno),
425 "%s", _dbus_strerror (errno));
429 statbuf->mode = sb.st_mode;
430 statbuf->nlink = sb.st_nlink;
431 statbuf->uid = sb.st_uid;
432 statbuf->gid = sb.st_gid;
433 statbuf->size = sb.st_size;
434 statbuf->atime = sb.st_atime;
435 statbuf->mtime = sb.st_mtime;
436 statbuf->ctime = sb.st_ctime;
443 * Internals of directory iterator
447 DIR *d; /**< The DIR* from opendir() */
452 * Open a directory to iterate over.
454 * @param filename the directory name
455 * @param error exception return object or #NULL
456 * @returns new iterator, or #NULL on error
459 _dbus_directory_open (const DBusString *filename,
464 const char *filename_c;
466 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
468 filename_c = _dbus_string_get_const_data (filename);
470 d = opendir (filename_c);
473 dbus_set_error (error, _dbus_error_from_errno (errno),
474 "Failed to read directory \"%s\": %s",
476 _dbus_strerror (errno));
479 iter = dbus_new0 (DBusDirIter, 1);
483 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
484 "Could not allocate memory for directory iterator");
494 * Get next file in the directory. Will not return "." or ".." on
495 * UNIX. If an error occurs, the contents of "filename" are
496 * undefined. The error is never set if the function succeeds.
498 * @todo 1.0 for thread safety, I think we have to use
499 * readdir_r(). (GLib has the same issue, should file a bug.)
501 * @param iter the iterator
502 * @param filename string to be set to the next file in the dir
503 * @param error return location for error
504 * @returns #TRUE if filename was filled in with a new filename
507 _dbus_directory_get_next_file (DBusDirIter *iter,
508 DBusString *filename,
513 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
517 ent = readdir (iter->d);
521 dbus_set_error (error,
522 _dbus_error_from_errno (errno),
523 "%s", _dbus_strerror (errno));
526 else if (ent->d_name[0] == '.' &&
527 (ent->d_name[1] == '\0' ||
528 (ent->d_name[1] == '.' && ent->d_name[2] == '\0')))
532 _dbus_string_set_length (filename, 0);
533 if (!_dbus_string_append (filename, ent->d_name))
535 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
536 "No memory to read directory entry");
545 * Closes a directory iteration.
548 _dbus_directory_close (DBusDirIter *iter)
555 fill_user_info_from_group (struct group *g,
559 _dbus_assert (g->gr_name != NULL);
561 info->gid = g->gr_gid;
562 info->groupname = _dbus_strdup (g->gr_name);
564 /* info->members = dbus_strdupv (g->gr_mem) */
566 if (info->groupname == NULL)
568 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
576 fill_group_info (DBusGroupInfo *info,
578 const DBusString *groupname,
581 const char *group_c_str;
583 _dbus_assert (groupname != NULL || gid != DBUS_GID_UNSET);
584 _dbus_assert (groupname == NULL || gid == DBUS_GID_UNSET);
587 group_c_str = _dbus_string_get_const_data (groupname);
591 /* For now assuming that the getgrnam() and getgrgid() flavors
592 * always correspond to the pwnam flavors, if not we have
593 * to add more configure checks.
596 #if defined (HAVE_POSIX_GETPWNAM_R) || defined (HAVE_NONPOSIX_GETPWNAM_R)
604 #ifdef HAVE_POSIX_GETPWNAM_R
607 result = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf),
610 result = getgrgid_r (gid, &g_str, buf, sizeof (buf),
613 g = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf));
615 #endif /* !HAVE_POSIX_GETPWNAM_R */
616 if (result == 0 && g == &g_str)
618 return fill_user_info_from_group (g, info, error);
622 dbus_set_error (error, _dbus_error_from_errno (errno),
623 "Group %s unknown or failed to look it up\n",
624 group_c_str ? group_c_str : "???");
628 #else /* ! HAVE_GETPWNAM_R */
630 /* I guess we're screwed on thread safety here */
633 g = getgrnam (group_c_str);
637 return fill_user_info_from_group (g, info, error);
641 dbus_set_error (error, _dbus_error_from_errno (errno),
642 "Group %s unknown or failed to look it up\n",
643 group_c_str ? group_c_str : "???");
647 #endif /* ! HAVE_GETPWNAM_R */
651 * Initializes the given DBusGroupInfo struct
652 * with information about the given group name.
654 * @param info the group info struct
655 * @param groupname name of group
656 * @param error the error return
657 * @returns #FALSE if error is set
660 _dbus_group_info_fill (DBusGroupInfo *info,
661 const DBusString *groupname,
664 return fill_group_info (info, DBUS_GID_UNSET,
670 * Initializes the given DBusGroupInfo struct
671 * with information about the given group ID.
673 * @param info the group info struct
674 * @param gid group ID
675 * @param error the error return
676 * @returns #FALSE if error is set
679 _dbus_group_info_fill_gid (DBusGroupInfo *info,
683 return fill_group_info (info, gid, NULL, error);
686 /** @} */ /* End of DBusInternalsUtils functions */
689 * @addtogroup DBusString
694 * Get the directory name from a complete filename
695 * @param filename the filename
696 * @param dirname string to append directory name to
697 * @returns #FALSE if no memory
700 _dbus_string_get_dirname (const DBusString *filename,
705 _dbus_assert (filename != dirname);
706 _dbus_assert (filename != NULL);
707 _dbus_assert (dirname != NULL);
709 /* Ignore any separators on the end */
710 sep = _dbus_string_get_length (filename);
712 return _dbus_string_append (dirname, "."); /* empty string passed in */
714 while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
717 _dbus_assert (sep >= 0);
720 return _dbus_string_append (dirname, "/");
722 /* Now find the previous separator */
723 _dbus_string_find_byte_backward (filename, sep, '/', &sep);
725 return _dbus_string_append (dirname, ".");
727 /* skip multiple separators */
728 while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
731 _dbus_assert (sep >= 0);
734 _dbus_string_get_byte (filename, 0) == '/')
735 return _dbus_string_append (dirname, "/");
737 return _dbus_string_copy_len (filename, 0, sep - 0,
738 dirname, _dbus_string_get_length (dirname));
740 /** @} */ /* DBusString stuff */