00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "dbus-sysdeps.h"
00025 #include "dbus-internals.h"
00026 #include "dbus-protocol.h"
00027 #include "dbus-string.h"
00028 #define DBUS_USERDB_INCLUDES_PRIVATE 1
00029 #include "dbus-userdb.h"
00030 #include "dbus-test.h"
00031
00032 #include <sys/types.h>
00033 #include <stdlib.h>
00034 #include <string.h>
00035 #include <signal.h>
00036 #include <unistd.h>
00037 #include <stdio.h>
00038 #include <errno.h>
00039 #include <fcntl.h>
00040 #include <sys/stat.h>
00041 #include <grp.h>
00042 #include <sys/socket.h>
00043 #include <dirent.h>
00044 #include <sys/un.h>
00045 #include <sys/wait.h>
00046
00047 #ifndef O_BINARY
00048 #define O_BINARY 0
00049 #endif
00050
00064 dbus_bool_t
00065 _dbus_become_daemon (const DBusString *pidfile,
00066 int print_pid_fd,
00067 DBusError *error)
00068 {
00069 const char *s;
00070 pid_t child_pid;
00071 int dev_null_fd;
00072
00073 _dbus_verbose ("Becoming a daemon...\n");
00074
00075 _dbus_verbose ("chdir to /\n");
00076 if (chdir ("/") < 0)
00077 {
00078 dbus_set_error (error, DBUS_ERROR_FAILED,
00079 "Could not chdir() to root directory");
00080 return FALSE;
00081 }
00082
00083 _dbus_verbose ("forking...\n");
00084 switch ((child_pid = fork ()))
00085 {
00086 case -1:
00087 _dbus_verbose ("fork failed\n");
00088 dbus_set_error (error, _dbus_error_from_errno (errno),
00089 "Failed to fork daemon: %s", _dbus_strerror (errno));
00090 return FALSE;
00091 break;
00092
00093 case 0:
00094 _dbus_verbose ("in child, closing std file descriptors\n");
00095
00096
00097
00098
00099
00100
00101 dev_null_fd = open ("/dev/null", O_RDWR);
00102 if (dev_null_fd >= 0)
00103 {
00104 dup2 (dev_null_fd, 0);
00105 dup2 (dev_null_fd, 1);
00106
00107 s = _dbus_getenv ("DBUS_DEBUG_OUTPUT");
00108 if (s == NULL || *s == '\0')
00109 dup2 (dev_null_fd, 2);
00110 else
00111 _dbus_verbose ("keeping stderr open due to DBUS_DEBUG_OUTPUT\n");
00112 }
00113
00114
00115 _dbus_verbose ("setting umask\n");
00116 umask (022);
00117 break;
00118
00119 default:
00120 if (pidfile)
00121 {
00122 _dbus_verbose ("parent writing pid file\n");
00123 if (!_dbus_write_pid_file (pidfile,
00124 child_pid,
00125 error))
00126 {
00127 _dbus_verbose ("pid file write failed, killing child\n");
00128 kill (child_pid, SIGTERM);
00129 return FALSE;
00130 }
00131 }
00132
00133
00134 if (print_pid_fd >= 0)
00135 {
00136 DBusString pid;
00137 int bytes;
00138
00139 if (!_dbus_string_init (&pid))
00140 {
00141 _DBUS_SET_OOM (error);
00142 kill (child_pid, SIGTERM);
00143 return FALSE;
00144 }
00145
00146 if (!_dbus_string_append_int (&pid, child_pid) ||
00147 !_dbus_string_append (&pid, "\n"))
00148 {
00149 _dbus_string_free (&pid);
00150 _DBUS_SET_OOM (error);
00151 kill (child_pid, SIGTERM);
00152 return FALSE;
00153 }
00154
00155 bytes = _dbus_string_get_length (&pid);
00156 if (_dbus_write (print_pid_fd, &pid, 0, bytes) != bytes)
00157 {
00158 dbus_set_error (error, DBUS_ERROR_FAILED,
00159 "Printing message bus PID: %s\n",
00160 _dbus_strerror (errno));
00161 _dbus_string_free (&pid);
00162 kill (child_pid, SIGTERM);
00163 return FALSE;
00164 }
00165
00166 _dbus_string_free (&pid);
00167 }
00168 _dbus_verbose ("parent exiting\n");
00169 _exit (0);
00170 break;
00171 }
00172
00173 _dbus_verbose ("calling setsid()\n");
00174 if (setsid () == -1)
00175 _dbus_assert_not_reached ("setsid() failed");
00176
00177 return TRUE;
00178 }
00179
00180
00189 dbus_bool_t
00190 _dbus_write_pid_file (const DBusString *filename,
00191 unsigned long pid,
00192 DBusError *error)
00193 {
00194 const char *cfilename;
00195 int fd;
00196 FILE *f;
00197
00198 cfilename = _dbus_string_get_const_data (filename);
00199
00200 fd = open (cfilename, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644);
00201
00202 if (fd < 0)
00203 {
00204 dbus_set_error (error, _dbus_error_from_errno (errno),
00205 "Failed to open \"%s\": %s", cfilename,
00206 _dbus_strerror (errno));
00207 return FALSE;
00208 }
00209
00210 if ((f = fdopen (fd, "w")) == NULL)
00211 {
00212 dbus_set_error (error, _dbus_error_from_errno (errno),
00213 "Failed to fdopen fd %d: %s", fd, _dbus_strerror (errno));
00214 close (fd);
00215 return FALSE;
00216 }
00217
00218 if (fprintf (f, "%lu\n", pid) < 0)
00219 {
00220 dbus_set_error (error, _dbus_error_from_errno (errno),
00221 "Failed to write to \"%s\": %s", cfilename,
00222 _dbus_strerror (errno));
00223 return FALSE;
00224 }
00225
00226 if (fclose (f) == EOF)
00227 {
00228 dbus_set_error (error, _dbus_error_from_errno (errno),
00229 "Failed to close \"%s\": %s", cfilename,
00230 _dbus_strerror (errno));
00231 return FALSE;
00232 }
00233
00234 return TRUE;
00235 }
00236
00237
00246 dbus_bool_t
00247 _dbus_change_identity (dbus_uid_t uid,
00248 dbus_gid_t gid,
00249 DBusError *error)
00250 {
00251
00252
00253
00254
00255
00256
00257 if (setgroups (0, NULL) < 0)
00258 _dbus_warn ("Failed to drop supplementary groups: %s\n",
00259 _dbus_strerror (errno));
00260
00261
00262
00263
00264 if (setgid (gid) < 0)
00265 {
00266 dbus_set_error (error, _dbus_error_from_errno (errno),
00267 "Failed to set GID to %lu: %s", gid,
00268 _dbus_strerror (errno));
00269 return FALSE;
00270 }
00271
00272 if (setuid (uid) < 0)
00273 {
00274 dbus_set_error (error, _dbus_error_from_errno (errno),
00275 "Failed to set UID to %lu: %s", uid,
00276 _dbus_strerror (errno));
00277 return FALSE;
00278 }
00279
00280 return TRUE;
00281 }
00282
00288 void
00289 _dbus_set_signal_handler (int sig,
00290 DBusSignalHandler handler)
00291 {
00292 struct sigaction act;
00293 sigset_t empty_mask;
00294
00295 sigemptyset (&empty_mask);
00296 act.sa_handler = handler;
00297 act.sa_mask = empty_mask;
00298 act.sa_flags = 0;
00299 sigaction (sig, &act, 0);
00300 }
00301
00302
00310 dbus_bool_t
00311 _dbus_delete_directory (const DBusString *filename,
00312 DBusError *error)
00313 {
00314 const char *filename_c;
00315
00316 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00317
00318 filename_c = _dbus_string_get_const_data (filename);
00319
00320 if (rmdir (filename_c) != 0)
00321 {
00322 dbus_set_error (error, DBUS_ERROR_FAILED,
00323 "Failed to remove directory %s: %s\n",
00324 filename_c, _dbus_strerror (errno));
00325 return FALSE;
00326 }
00327
00328 return TRUE;
00329 }
00330
00336 dbus_bool_t
00337 _dbus_file_exists (const char *file)
00338 {
00339 return (access (file, F_OK) == 0);
00340 }
00341
00348 dbus_bool_t
00349 _dbus_user_at_console (const char *username,
00350 DBusError *error)
00351 {
00352
00353 DBusString f;
00354 dbus_bool_t result;
00355 int console;
00356 pid_t fgconsole;
00357
00358 result = FALSE;
00359
00360 fgconsole = fork();
00361 if (fgconsole == 0)
00362 {
00363 execl (DBUS_FOREGROUND_CONSOLE_COMMAND, DBUS_FOREGROUND_CONSOLE_COMMAND, NULL);
00364 exit (0);
00365 } else if (fgconsole < 0)
00366 {
00367 dbus_set_error (error, DBUS_ERROR_FAILED,
00368 "Failed to fork(): %s\n", _dbus_strerror (errno));
00369 return FALSE;
00370 }
00371
00372 if (wait (&console) < 0 || !WIFEXITED (console))
00373 {
00374 dbus_set_error (error, DBUS_ERROR_FAILED,
00375 "Failed to execute %s: %s\n",
00376 DBUS_FOREGROUND_CONSOLE_COMMAND, _dbus_strerror (errno));
00377 return FALSE;
00378 }
00379
00380 console = WEXITSTATUS(console);
00381
00382
00383 if (console == 0)
00384 {
00385 return FALSE;
00386 }
00387
00388
00389 if (!_dbus_string_init (&f))
00390 {
00391 _DBUS_SET_OOM (error);
00392 return FALSE;
00393 }
00394
00395 if (!_dbus_string_append (&f, DBUS_CONSOLE_AUTH_DIR))
00396 {
00397 _DBUS_SET_OOM (error);
00398 goto out;
00399 }
00400
00401 if (!_dbus_string_append (&f, username))
00402 {
00403 _DBUS_SET_OOM (error);
00404 goto out;
00405 }
00406
00407
00408 if (!_dbus_string_append (&f, ":"))
00409 {
00410 _DBUS_SET_OOM (error);
00411 goto out;
00412 }
00413
00414 if (!_dbus_string_append_int (&f, console))
00415 {
00416 _DBUS_SET_OOM (error);
00417 goto out;
00418 }
00419
00420 result = _dbus_file_exists (_dbus_string_get_const_data (&f));
00421
00422 out:
00423 _dbus_string_free (&f);
00424
00425 return result;
00426 }
00427
00428
00435 dbus_bool_t
00436 _dbus_path_is_absolute (const DBusString *filename)
00437 {
00438 if (_dbus_string_get_length (filename) > 0)
00439 return _dbus_string_get_byte (filename, 0) == '/';
00440 else
00441 return FALSE;
00442 }
00443
00452 dbus_bool_t
00453 _dbus_stat (const DBusString *filename,
00454 DBusStat *statbuf,
00455 DBusError *error)
00456 {
00457 const char *filename_c;
00458 struct stat sb;
00459
00460 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00461
00462 filename_c = _dbus_string_get_const_data (filename);
00463
00464 if (stat (filename_c, &sb) < 0)
00465 {
00466 dbus_set_error (error, _dbus_error_from_errno (errno),
00467 "%s", _dbus_strerror (errno));
00468 return FALSE;
00469 }
00470
00471 statbuf->mode = sb.st_mode;
00472 statbuf->nlink = sb.st_nlink;
00473 statbuf->uid = sb.st_uid;
00474 statbuf->gid = sb.st_gid;
00475 statbuf->size = sb.st_size;
00476 statbuf->atime = sb.st_atime;
00477 statbuf->mtime = sb.st_mtime;
00478 statbuf->ctime = sb.st_ctime;
00479
00480 return TRUE;
00481 }
00482
00483
00487 struct DBusDirIter
00488 {
00489 DIR *d;
00491 };
00492
00500 DBusDirIter*
00501 _dbus_directory_open (const DBusString *filename,
00502 DBusError *error)
00503 {
00504 DIR *d;
00505 DBusDirIter *iter;
00506 const char *filename_c;
00507
00508 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00509
00510 filename_c = _dbus_string_get_const_data (filename);
00511
00512 d = opendir (filename_c);
00513 if (d == NULL)
00514 {
00515 dbus_set_error (error, _dbus_error_from_errno (errno),
00516 "Failed to read directory \"%s\": %s",
00517 filename_c,
00518 _dbus_strerror (errno));
00519 return NULL;
00520 }
00521 iter = dbus_new0 (DBusDirIter, 1);
00522 if (iter == NULL)
00523 {
00524 closedir (d);
00525 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00526 "Could not allocate memory for directory iterator");
00527 return NULL;
00528 }
00529
00530 iter->d = d;
00531
00532 return iter;
00533 }
00534
00548 dbus_bool_t
00549 _dbus_directory_get_next_file (DBusDirIter *iter,
00550 DBusString *filename,
00551 DBusError *error)
00552 {
00553 struct dirent *ent;
00554
00555 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00556
00557 again:
00558 errno = 0;
00559 ent = readdir (iter->d);
00560 if (ent == NULL)
00561 {
00562 if (errno != 0)
00563 dbus_set_error (error,
00564 _dbus_error_from_errno (errno),
00565 "%s", _dbus_strerror (errno));
00566 return FALSE;
00567 }
00568 else if (ent->d_name[0] == '.' &&
00569 (ent->d_name[1] == '\0' ||
00570 (ent->d_name[1] == '.' && ent->d_name[2] == '\0')))
00571 goto again;
00572 else
00573 {
00574 _dbus_string_set_length (filename, 0);
00575 if (!_dbus_string_append (filename, ent->d_name))
00576 {
00577 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00578 "No memory to read directory entry");
00579 return FALSE;
00580 }
00581 else
00582 return TRUE;
00583 }
00584 }
00585
00589 void
00590 _dbus_directory_close (DBusDirIter *iter)
00591 {
00592 closedir (iter->d);
00593 dbus_free (iter);
00594 }
00595
00596 static dbus_bool_t
00597 fill_user_info_from_group (struct group *g,
00598 DBusGroupInfo *info,
00599 DBusError *error)
00600 {
00601 _dbus_assert (g->gr_name != NULL);
00602
00603 info->gid = g->gr_gid;
00604 info->groupname = _dbus_strdup (g->gr_name);
00605
00606
00607
00608 if (info->groupname == NULL)
00609 {
00610 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00611 return FALSE;
00612 }
00613
00614 return TRUE;
00615 }
00616
00617 static dbus_bool_t
00618 fill_group_info (DBusGroupInfo *info,
00619 dbus_gid_t gid,
00620 const DBusString *groupname,
00621 DBusError *error)
00622 {
00623 const char *group_c_str;
00624
00625 _dbus_assert (groupname != NULL || gid != DBUS_GID_UNSET);
00626 _dbus_assert (groupname == NULL || gid == DBUS_GID_UNSET);
00627
00628 if (groupname)
00629 group_c_str = _dbus_string_get_const_data (groupname);
00630 else
00631 group_c_str = NULL;
00632
00633
00634
00635
00636
00637
00638 #if defined (HAVE_POSIX_GETPWNAM_R) || defined (HAVE_NONPOSIX_GETPWNAM_R)
00639 {
00640 struct group *g;
00641 int result;
00642 char buf[1024];
00643 struct group g_str;
00644
00645 g = NULL;
00646 #ifdef HAVE_POSIX_GETPWNAM_R
00647
00648 if (group_c_str)
00649 result = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf),
00650 &g);
00651 else
00652 result = getgrgid_r (gid, &g_str, buf, sizeof (buf),
00653 &g);
00654 #else
00655 g = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf));
00656 result = 0;
00657 #endif
00658 if (result == 0 && g == &g_str)
00659 {
00660 return fill_user_info_from_group (g, info, error);
00661 }
00662 else
00663 {
00664 dbus_set_error (error, _dbus_error_from_errno (errno),
00665 "Group %s unknown or failed to look it up\n",
00666 group_c_str ? group_c_str : "???");
00667 return FALSE;
00668 }
00669 }
00670 #else
00671 {
00672
00673 struct group *g;
00674
00675 g = getgrnam (group_c_str);
00676
00677 if (g != NULL)
00678 {
00679 return fill_user_info_from_group (g, info, error);
00680 }
00681 else
00682 {
00683 dbus_set_error (error, _dbus_error_from_errno (errno),
00684 "Group %s unknown or failed to look it up\n",
00685 group_c_str ? group_c_str : "???");
00686 return FALSE;
00687 }
00688 }
00689 #endif
00690 }
00691
00701 dbus_bool_t
00702 _dbus_group_info_fill (DBusGroupInfo *info,
00703 const DBusString *groupname,
00704 DBusError *error)
00705 {
00706 return fill_group_info (info, DBUS_GID_UNSET,
00707 groupname, error);
00708
00709 }
00710
00720 dbus_bool_t
00721 _dbus_group_info_fill_gid (DBusGroupInfo *info,
00722 dbus_gid_t gid,
00723 DBusError *error)
00724 {
00725 return fill_group_info (info, gid, NULL, error);
00726 }
00727
00733 void
00734 _dbus_group_info_free (DBusGroupInfo *info)
00735 {
00736 dbus_free (info->groupname);
00737 }
00738
00740
00752 dbus_bool_t
00753 _dbus_string_get_dirname (const DBusString *filename,
00754 DBusString *dirname)
00755 {
00756 int sep;
00757
00758 _dbus_assert (filename != dirname);
00759 _dbus_assert (filename != NULL);
00760 _dbus_assert (dirname != NULL);
00761
00762
00763 sep = _dbus_string_get_length (filename);
00764 if (sep == 0)
00765 return _dbus_string_append (dirname, ".");
00766
00767 while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
00768 --sep;
00769
00770 _dbus_assert (sep >= 0);
00771
00772 if (sep == 0)
00773 return _dbus_string_append (dirname, "/");
00774
00775
00776 _dbus_string_find_byte_backward (filename, sep, '/', &sep);
00777 if (sep < 0)
00778 return _dbus_string_append (dirname, ".");
00779
00780
00781 while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
00782 --sep;
00783
00784 _dbus_assert (sep >= 0);
00785
00786 if (sep == 0 &&
00787 _dbus_string_get_byte (filename, 0) == '/')
00788 return _dbus_string_append (dirname, "/");
00789 else
00790 return _dbus_string_copy_len (filename, 0, sep - 0,
00791 dirname, _dbus_string_get_length (dirname));
00792 }
00794
00795
00796 #ifdef DBUS_BUILD_TESTS
00797 #include <stdlib.h>
00798 static void
00799 check_dirname (const char *filename,
00800 const char *dirname)
00801 {
00802 DBusString f, d;
00803
00804 _dbus_string_init_const (&f, filename);
00805
00806 if (!_dbus_string_init (&d))
00807 _dbus_assert_not_reached ("no memory");
00808
00809 if (!_dbus_string_get_dirname (&f, &d))
00810 _dbus_assert_not_reached ("no memory");
00811
00812 if (!_dbus_string_equal_c_str (&d, dirname))
00813 {
00814 _dbus_warn ("For filename \"%s\" got dirname \"%s\" and expected \"%s\"\n",
00815 filename,
00816 _dbus_string_get_const_data (&d),
00817 dirname);
00818 exit (1);
00819 }
00820
00821 _dbus_string_free (&d);
00822 }
00823
00824 static void
00825 check_path_absolute (const char *path,
00826 dbus_bool_t expected)
00827 {
00828 DBusString p;
00829
00830 _dbus_string_init_const (&p, path);
00831
00832 if (_dbus_path_is_absolute (&p) != expected)
00833 {
00834 _dbus_warn ("For path \"%s\" expected absolute = %d got %d\n",
00835 path, expected, _dbus_path_is_absolute (&p));
00836 exit (1);
00837 }
00838 }
00839
00845 dbus_bool_t
00846 _dbus_sysdeps_test (void)
00847 {
00848 DBusString str;
00849 double val;
00850 int pos;
00851
00852 check_dirname ("foo", ".");
00853 check_dirname ("foo/bar", "foo");
00854 check_dirname ("foo//bar", "foo");
00855 check_dirname ("foo///bar", "foo");
00856 check_dirname ("foo/bar/", "foo");
00857 check_dirname ("foo//bar/", "foo");
00858 check_dirname ("foo///bar/", "foo");
00859 check_dirname ("foo/bar//", "foo");
00860 check_dirname ("foo//bar////", "foo");
00861 check_dirname ("foo///bar///////", "foo");
00862 check_dirname ("/foo", "/");
00863 check_dirname ("////foo", "/");
00864 check_dirname ("/foo/bar", "/foo");
00865 check_dirname ("/foo//bar", "/foo");
00866 check_dirname ("/foo///bar", "/foo");
00867 check_dirname ("/", "/");
00868 check_dirname ("///", "/");
00869 check_dirname ("", ".");
00870
00871
00872 _dbus_string_init_const (&str, "3.5");
00873 if (!_dbus_string_parse_double (&str,
00874 0, &val, &pos))
00875 {
00876 _dbus_warn ("Failed to parse double");
00877 exit (1);
00878 }
00879 if (ABS(3.5 - val) > 1e-6)
00880 {
00881 _dbus_warn ("Failed to parse 3.5 correctly, got: %f", val);
00882 exit (1);
00883 }
00884 if (pos != 3)
00885 {
00886 _dbus_warn ("_dbus_string_parse_double of \"3.5\" returned wrong position %d", pos);
00887 exit (1);
00888 }
00889
00890 _dbus_string_init_const (&str, "0xff");
00891 if (!_dbus_string_parse_double (&str,
00892 0, &val, &pos))
00893 {
00894 _dbus_warn ("Failed to parse double");
00895 exit (1);
00896 }
00897 if (ABS (0xff - val) > 1e-6)
00898 {
00899 _dbus_warn ("Failed to parse 0xff correctly, got: %f\n", val);
00900 exit (1);
00901 }
00902 if (pos != 4)
00903 {
00904 _dbus_warn ("_dbus_string_parse_double of \"0xff\" returned wrong position %d", pos);
00905 exit (1);
00906 }
00907
00908 check_path_absolute ("/", TRUE);
00909 check_path_absolute ("/foo", TRUE);
00910 check_path_absolute ("", FALSE);
00911 check_path_absolute ("foo", FALSE);
00912 check_path_absolute ("foo/bar", FALSE);
00913
00914 return TRUE;
00915 }
00916 #endif