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
00046 #ifndef O_BINARY
00047 #define O_BINARY 0
00048 #endif
00049
00063 dbus_bool_t
00064 _dbus_become_daemon (const DBusString *pidfile,
00065 int print_pid_fd,
00066 DBusError *error)
00067 {
00068 const char *s;
00069 pid_t child_pid;
00070 int dev_null_fd;
00071
00072 _dbus_verbose ("Becoming a daemon...\n");
00073
00074 _dbus_verbose ("chdir to /\n");
00075 if (chdir ("/") < 0)
00076 {
00077 dbus_set_error (error, DBUS_ERROR_FAILED,
00078 "Could not chdir() to root directory");
00079 return FALSE;
00080 }
00081
00082 _dbus_verbose ("forking...\n");
00083 switch ((child_pid = fork ()))
00084 {
00085 case -1:
00086 _dbus_verbose ("fork failed\n");
00087 dbus_set_error (error, _dbus_error_from_errno (errno),
00088 "Failed to fork daemon: %s", _dbus_strerror (errno));
00089 return FALSE;
00090 break;
00091
00092 case 0:
00093 _dbus_verbose ("in child, closing std file descriptors\n");
00094
00095
00096
00097
00098
00099
00100 dev_null_fd = open ("/dev/null", O_RDWR);
00101 if (dev_null_fd >= 0)
00102 {
00103 dup2 (dev_null_fd, 0);
00104 dup2 (dev_null_fd, 1);
00105
00106 s = _dbus_getenv ("DBUS_DEBUG_OUTPUT");
00107 if (s == NULL || *s == '\0')
00108 dup2 (dev_null_fd, 2);
00109 else
00110 _dbus_verbose ("keeping stderr open due to DBUS_DEBUG_OUTPUT\n");
00111 }
00112
00113
00114 _dbus_verbose ("setting umask\n");
00115 umask (022);
00116 break;
00117
00118 default:
00119 if (pidfile)
00120 {
00121 _dbus_verbose ("parent writing pid file\n");
00122 if (!_dbus_write_pid_file (pidfile,
00123 child_pid,
00124 error))
00125 {
00126 _dbus_verbose ("pid file write failed, killing child\n");
00127 kill (child_pid, SIGTERM);
00128 return FALSE;
00129 }
00130 }
00131
00132
00133 if (print_pid_fd >= 0)
00134 {
00135 DBusString pid;
00136 int bytes;
00137
00138 if (!_dbus_string_init (&pid))
00139 {
00140 _DBUS_SET_OOM (error);
00141 kill (child_pid, SIGTERM);
00142 return FALSE;
00143 }
00144
00145 if (!_dbus_string_append_int (&pid, child_pid) ||
00146 !_dbus_string_append (&pid, "\n"))
00147 {
00148 _dbus_string_free (&pid);
00149 _DBUS_SET_OOM (error);
00150 kill (child_pid, SIGTERM);
00151 return FALSE;
00152 }
00153
00154 bytes = _dbus_string_get_length (&pid);
00155 if (_dbus_write (print_pid_fd, &pid, 0, bytes) != bytes)
00156 {
00157 dbus_set_error (error, DBUS_ERROR_FAILED,
00158 "Printing message bus PID: %s\n",
00159 _dbus_strerror (errno));
00160 _dbus_string_free (&pid);
00161 kill (child_pid, SIGTERM);
00162 return FALSE;
00163 }
00164
00165 _dbus_string_free (&pid);
00166 }
00167 _dbus_verbose ("parent exiting\n");
00168 _exit (0);
00169 break;
00170 }
00171
00172 _dbus_verbose ("calling setsid()\n");
00173 if (setsid () == -1)
00174 _dbus_assert_not_reached ("setsid() failed");
00175
00176 return TRUE;
00177 }
00178
00179
00188 dbus_bool_t
00189 _dbus_write_pid_file (const DBusString *filename,
00190 unsigned long pid,
00191 DBusError *error)
00192 {
00193 const char *cfilename;
00194 int fd;
00195 FILE *f;
00196
00197 cfilename = _dbus_string_get_const_data (filename);
00198
00199 fd = open (cfilename, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644);
00200
00201 if (fd < 0)
00202 {
00203 dbus_set_error (error, _dbus_error_from_errno (errno),
00204 "Failed to open \"%s\": %s", cfilename,
00205 _dbus_strerror (errno));
00206 return FALSE;
00207 }
00208
00209 if ((f = fdopen (fd, "w")) == NULL)
00210 {
00211 dbus_set_error (error, _dbus_error_from_errno (errno),
00212 "Failed to fdopen fd %d: %s", fd, _dbus_strerror (errno));
00213 close (fd);
00214 return FALSE;
00215 }
00216
00217 if (fprintf (f, "%lu\n", pid) < 0)
00218 {
00219 dbus_set_error (error, _dbus_error_from_errno (errno),
00220 "Failed to write to \"%s\": %s", cfilename,
00221 _dbus_strerror (errno));
00222 return FALSE;
00223 }
00224
00225 if (fclose (f) == EOF)
00226 {
00227 dbus_set_error (error, _dbus_error_from_errno (errno),
00228 "Failed to close \"%s\": %s", cfilename,
00229 _dbus_strerror (errno));
00230 return FALSE;
00231 }
00232
00233 return TRUE;
00234 }
00235
00236
00245 dbus_bool_t
00246 _dbus_change_identity (dbus_uid_t uid,
00247 dbus_gid_t gid,
00248 DBusError *error)
00249 {
00250
00251
00252
00253
00254
00255
00256 if (setgroups (0, NULL) < 0)
00257 _dbus_warn ("Failed to drop supplementary groups: %s\n",
00258 _dbus_strerror (errno));
00259
00260
00261
00262
00263 if (setgid (gid) < 0)
00264 {
00265 dbus_set_error (error, _dbus_error_from_errno (errno),
00266 "Failed to set GID to %lu: %s", gid,
00267 _dbus_strerror (errno));
00268 return FALSE;
00269 }
00270
00271 if (setuid (uid) < 0)
00272 {
00273 dbus_set_error (error, _dbus_error_from_errno (errno),
00274 "Failed to set UID to %lu: %s", uid,
00275 _dbus_strerror (errno));
00276 return FALSE;
00277 }
00278
00279 return TRUE;
00280 }
00281
00287 void
00288 _dbus_set_signal_handler (int sig,
00289 DBusSignalHandler handler)
00290 {
00291 struct sigaction act;
00292 sigset_t empty_mask;
00293
00294 sigemptyset (&empty_mask);
00295 act.sa_handler = handler;
00296 act.sa_mask = empty_mask;
00297 act.sa_flags = 0;
00298 sigaction (sig, &act, 0);
00299 }
00300
00301
00309 dbus_bool_t
00310 _dbus_delete_directory (const DBusString *filename,
00311 DBusError *error)
00312 {
00313 const char *filename_c;
00314
00315 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00316
00317 filename_c = _dbus_string_get_const_data (filename);
00318
00319 if (rmdir (filename_c) != 0)
00320 {
00321 dbus_set_error (error, DBUS_ERROR_FAILED,
00322 "Failed to remove directory %s: %s\n",
00323 filename_c, _dbus_strerror (errno));
00324 return FALSE;
00325 }
00326
00327 return TRUE;
00328 }
00329
00335 dbus_bool_t
00336 _dbus_file_exists (const char *file)
00337 {
00338 return (access (file, F_OK) == 0);
00339 }
00340
00347 dbus_bool_t
00348 _dbus_user_at_console (const char *username,
00349 DBusError *error)
00350 {
00351
00352 DBusString f;
00353 dbus_bool_t result;
00354
00355 result = FALSE;
00356 if (!_dbus_string_init (&f))
00357 {
00358 _DBUS_SET_OOM (error);
00359 return FALSE;
00360 }
00361
00362 if (!_dbus_string_append (&f, DBUS_CONSOLE_AUTH_DIR))
00363 {
00364 _DBUS_SET_OOM (error);
00365 goto out;
00366 }
00367
00368
00369 if (!_dbus_string_append (&f, username))
00370 {
00371 _DBUS_SET_OOM (error);
00372 goto out;
00373 }
00374
00375 result = _dbus_file_exists (_dbus_string_get_const_data (&f));
00376
00377 out:
00378 _dbus_string_free (&f);
00379
00380 return result;
00381 }
00382
00383
00390 dbus_bool_t
00391 _dbus_path_is_absolute (const DBusString *filename)
00392 {
00393 if (_dbus_string_get_length (filename) > 0)
00394 return _dbus_string_get_byte (filename, 0) == '/';
00395 else
00396 return FALSE;
00397 }
00398
00407 dbus_bool_t
00408 _dbus_stat (const DBusString *filename,
00409 DBusStat *statbuf,
00410 DBusError *error)
00411 {
00412 const char *filename_c;
00413 struct stat sb;
00414
00415 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00416
00417 filename_c = _dbus_string_get_const_data (filename);
00418
00419 if (stat (filename_c, &sb) < 0)
00420 {
00421 dbus_set_error (error, _dbus_error_from_errno (errno),
00422 "%s", _dbus_strerror (errno));
00423 return FALSE;
00424 }
00425
00426 statbuf->mode = sb.st_mode;
00427 statbuf->nlink = sb.st_nlink;
00428 statbuf->uid = sb.st_uid;
00429 statbuf->gid = sb.st_gid;
00430 statbuf->size = sb.st_size;
00431 statbuf->atime = sb.st_atime;
00432 statbuf->mtime = sb.st_mtime;
00433 statbuf->ctime = sb.st_ctime;
00434
00435 return TRUE;
00436 }
00437
00438
00442 struct DBusDirIter
00443 {
00444 DIR *d;
00446 };
00447
00455 DBusDirIter*
00456 _dbus_directory_open (const DBusString *filename,
00457 DBusError *error)
00458 {
00459 DIR *d;
00460 DBusDirIter *iter;
00461 const char *filename_c;
00462
00463 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00464
00465 filename_c = _dbus_string_get_const_data (filename);
00466
00467 d = opendir (filename_c);
00468 if (d == NULL)
00469 {
00470 dbus_set_error (error, _dbus_error_from_errno (errno),
00471 "Failed to read directory \"%s\": %s",
00472 filename_c,
00473 _dbus_strerror (errno));
00474 return NULL;
00475 }
00476 iter = dbus_new0 (DBusDirIter, 1);
00477 if (iter == NULL)
00478 {
00479 closedir (d);
00480 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00481 "Could not allocate memory for directory iterator");
00482 return NULL;
00483 }
00484
00485 iter->d = d;
00486
00487 return iter;
00488 }
00489
00503 dbus_bool_t
00504 _dbus_directory_get_next_file (DBusDirIter *iter,
00505 DBusString *filename,
00506 DBusError *error)
00507 {
00508 struct dirent *ent;
00509
00510 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00511
00512 again:
00513 errno = 0;
00514 ent = readdir (iter->d);
00515 if (ent == NULL)
00516 {
00517 if (errno != 0)
00518 dbus_set_error (error,
00519 _dbus_error_from_errno (errno),
00520 "%s", _dbus_strerror (errno));
00521 return FALSE;
00522 }
00523 else if (ent->d_name[0] == '.' &&
00524 (ent->d_name[1] == '\0' ||
00525 (ent->d_name[1] == '.' && ent->d_name[2] == '\0')))
00526 goto again;
00527 else
00528 {
00529 _dbus_string_set_length (filename, 0);
00530 if (!_dbus_string_append (filename, ent->d_name))
00531 {
00532 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00533 "No memory to read directory entry");
00534 return FALSE;
00535 }
00536 else
00537 return TRUE;
00538 }
00539 }
00540
00544 void
00545 _dbus_directory_close (DBusDirIter *iter)
00546 {
00547 closedir (iter->d);
00548 dbus_free (iter);
00549 }
00550
00551 static dbus_bool_t
00552 fill_user_info_from_group (struct group *g,
00553 DBusGroupInfo *info,
00554 DBusError *error)
00555 {
00556 _dbus_assert (g->gr_name != NULL);
00557
00558 info->gid = g->gr_gid;
00559 info->groupname = _dbus_strdup (g->gr_name);
00560
00561
00562
00563 if (info->groupname == NULL)
00564 {
00565 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00566 return FALSE;
00567 }
00568
00569 return TRUE;
00570 }
00571
00572 static dbus_bool_t
00573 fill_group_info (DBusGroupInfo *info,
00574 dbus_gid_t gid,
00575 const DBusString *groupname,
00576 DBusError *error)
00577 {
00578 const char *group_c_str;
00579
00580 _dbus_assert (groupname != NULL || gid != DBUS_GID_UNSET);
00581 _dbus_assert (groupname == NULL || gid == DBUS_GID_UNSET);
00582
00583 if (groupname)
00584 group_c_str = _dbus_string_get_const_data (groupname);
00585 else
00586 group_c_str = NULL;
00587
00588
00589
00590
00591
00592
00593 #if defined (HAVE_POSIX_GETPWNAM_R) || defined (HAVE_NONPOSIX_GETPWNAM_R)
00594 {
00595 struct group *g;
00596 int result;
00597 char buf[1024];
00598 struct group g_str;
00599
00600 g = NULL;
00601 #ifdef HAVE_POSIX_GETPWNAM_R
00602
00603 if (group_c_str)
00604 result = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf),
00605 &g);
00606 else
00607 result = getgrgid_r (gid, &g_str, buf, sizeof (buf),
00608 &g);
00609 #else
00610 g = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf));
00611 result = 0;
00612 #endif
00613 if (result == 0 && g == &g_str)
00614 {
00615 return fill_user_info_from_group (g, info, error);
00616 }
00617 else
00618 {
00619 dbus_set_error (error, _dbus_error_from_errno (errno),
00620 "Group %s unknown or failed to look it up\n",
00621 group_c_str ? group_c_str : "???");
00622 return FALSE;
00623 }
00624 }
00625 #else
00626 {
00627
00628 struct group *g;
00629
00630 g = getgrnam (group_c_str);
00631
00632 if (g != NULL)
00633 {
00634 return fill_user_info_from_group (g, info, error);
00635 }
00636 else
00637 {
00638 dbus_set_error (error, _dbus_error_from_errno (errno),
00639 "Group %s unknown or failed to look it up\n",
00640 group_c_str ? group_c_str : "???");
00641 return FALSE;
00642 }
00643 }
00644 #endif
00645 }
00646
00656 dbus_bool_t
00657 _dbus_group_info_fill (DBusGroupInfo *info,
00658 const DBusString *groupname,
00659 DBusError *error)
00660 {
00661 return fill_group_info (info, DBUS_GID_UNSET,
00662 groupname, error);
00663
00664 }
00665
00675 dbus_bool_t
00676 _dbus_group_info_fill_gid (DBusGroupInfo *info,
00677 dbus_gid_t gid,
00678 DBusError *error)
00679 {
00680 return fill_group_info (info, gid, NULL, error);
00681 }
00682
00688 void
00689 _dbus_group_info_free (DBusGroupInfo *info)
00690 {
00691 dbus_free (info->groupname);
00692 }
00693
00695
00707 dbus_bool_t
00708 _dbus_string_get_dirname (const DBusString *filename,
00709 DBusString *dirname)
00710 {
00711 int sep;
00712
00713 _dbus_assert (filename != dirname);
00714 _dbus_assert (filename != NULL);
00715 _dbus_assert (dirname != NULL);
00716
00717
00718 sep = _dbus_string_get_length (filename);
00719 if (sep == 0)
00720 return _dbus_string_append (dirname, ".");
00721
00722 while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
00723 --sep;
00724
00725 _dbus_assert (sep >= 0);
00726
00727 if (sep == 0)
00728 return _dbus_string_append (dirname, "/");
00729
00730
00731 _dbus_string_find_byte_backward (filename, sep, '/', &sep);
00732 if (sep < 0)
00733 return _dbus_string_append (dirname, ".");
00734
00735
00736 while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
00737 --sep;
00738
00739 _dbus_assert (sep >= 0);
00740
00741 if (sep == 0 &&
00742 _dbus_string_get_byte (filename, 0) == '/')
00743 return _dbus_string_append (dirname, "/");
00744 else
00745 return _dbus_string_copy_len (filename, 0, sep - 0,
00746 dirname, _dbus_string_get_length (dirname));
00747 }
00749
00750
00751 #ifdef DBUS_BUILD_TESTS
00752 #include <stdlib.h>
00753 static void
00754 check_dirname (const char *filename,
00755 const char *dirname)
00756 {
00757 DBusString f, d;
00758
00759 _dbus_string_init_const (&f, filename);
00760
00761 if (!_dbus_string_init (&d))
00762 _dbus_assert_not_reached ("no memory");
00763
00764 if (!_dbus_string_get_dirname (&f, &d))
00765 _dbus_assert_not_reached ("no memory");
00766
00767 if (!_dbus_string_equal_c_str (&d, dirname))
00768 {
00769 _dbus_warn ("For filename \"%s\" got dirname \"%s\" and expected \"%s\"\n",
00770 filename,
00771 _dbus_string_get_const_data (&d),
00772 dirname);
00773 exit (1);
00774 }
00775
00776 _dbus_string_free (&d);
00777 }
00778
00779 static void
00780 check_path_absolute (const char *path,
00781 dbus_bool_t expected)
00782 {
00783 DBusString p;
00784
00785 _dbus_string_init_const (&p, path);
00786
00787 if (_dbus_path_is_absolute (&p) != expected)
00788 {
00789 _dbus_warn ("For path \"%s\" expected absolute = %d got %d\n",
00790 path, expected, _dbus_path_is_absolute (&p));
00791 exit (1);
00792 }
00793 }
00794
00800 dbus_bool_t
00801 _dbus_sysdeps_test (void)
00802 {
00803 DBusString str;
00804 double val;
00805 int pos;
00806
00807 check_dirname ("foo", ".");
00808 check_dirname ("foo/bar", "foo");
00809 check_dirname ("foo//bar", "foo");
00810 check_dirname ("foo///bar", "foo");
00811 check_dirname ("foo/bar/", "foo");
00812 check_dirname ("foo//bar/", "foo");
00813 check_dirname ("foo///bar/", "foo");
00814 check_dirname ("foo/bar//", "foo");
00815 check_dirname ("foo//bar////", "foo");
00816 check_dirname ("foo///bar///////", "foo");
00817 check_dirname ("/foo", "/");
00818 check_dirname ("////foo", "/");
00819 check_dirname ("/foo/bar", "/foo");
00820 check_dirname ("/foo//bar", "/foo");
00821 check_dirname ("/foo///bar", "/foo");
00822 check_dirname ("/", "/");
00823 check_dirname ("///", "/");
00824 check_dirname ("", ".");
00825
00826
00827 _dbus_string_init_const (&str, "3.5");
00828 if (!_dbus_string_parse_double (&str,
00829 0, &val, &pos))
00830 {
00831 _dbus_warn ("Failed to parse double");
00832 exit (1);
00833 }
00834 if (ABS(3.5 - val) > 1e-6)
00835 {
00836 _dbus_warn ("Failed to parse 3.5 correctly, got: %f", val);
00837 exit (1);
00838 }
00839 if (pos != 3)
00840 {
00841 _dbus_warn ("_dbus_string_parse_double of \"3.5\" returned wrong position %d", pos);
00842 exit (1);
00843 }
00844
00845 _dbus_string_init_const (&str, "0xff");
00846 if (!_dbus_string_parse_double (&str,
00847 0, &val, &pos))
00848 {
00849 _dbus_warn ("Failed to parse double");
00850 exit (1);
00851 }
00852 if (ABS (0xff - val) > 1e-6)
00853 {
00854 _dbus_warn ("Failed to parse 0xff correctly, got: %f\n", val);
00855 exit (1);
00856 }
00857 if (pos != 4)
00858 {
00859 _dbus_warn ("_dbus_string_parse_double of \"0xff\" returned wrong position %d", pos);
00860 exit (1);
00861 }
00862
00863 check_path_absolute ("/", TRUE);
00864 check_path_absolute ("/foo", TRUE);
00865 check_path_absolute ("", FALSE);
00866 check_path_absolute ("foo", FALSE);
00867 check_path_absolute ("foo/bar", FALSE);
00868
00869 return TRUE;
00870 }
00871 #endif