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-sysdeps-unix.h"
00026 #include "dbus-internals.h"
00027 #include "dbus-protocol.h"
00028 #include "dbus-string.h"
00029 #define DBUS_USERDB_INCLUDES_PRIVATE 1
00030 #include "dbus-userdb.h"
00031 #include "dbus-test.h"
00032
00033 #include <sys/types.h>
00034 #include <stdlib.h>
00035 #include <string.h>
00036 #include <signal.h>
00037 #include <unistd.h>
00038 #include <stdio.h>
00039 #include <syslog.h>
00040 #include <errno.h>
00041 #include <fcntl.h>
00042 #include <sys/stat.h>
00043 #include <grp.h>
00044 #include <sys/socket.h>
00045 #include <dirent.h>
00046 #include <sys/un.h>
00047
00048 #ifdef HAVE_SYS_SYSLIMITS_H
00049 #include <sys/syslimits.h>
00050 #endif
00051
00052 #ifndef O_BINARY
00053 #define O_BINARY 0
00054 #endif
00055
00069 dbus_bool_t
00070 _dbus_become_daemon (const DBusString *pidfile,
00071 int print_pid_fd,
00072 DBusError *error)
00073 {
00074 const char *s;
00075 pid_t child_pid;
00076 int dev_null_fd;
00077
00078 _dbus_verbose ("Becoming a daemon...\n");
00079
00080 _dbus_verbose ("chdir to /\n");
00081 if (chdir ("/") < 0)
00082 {
00083 dbus_set_error (error, DBUS_ERROR_FAILED,
00084 "Could not chdir() to root directory");
00085 return FALSE;
00086 }
00087
00088 _dbus_verbose ("forking...\n");
00089 switch ((child_pid = fork ()))
00090 {
00091 case -1:
00092 _dbus_verbose ("fork failed\n");
00093 dbus_set_error (error, _dbus_error_from_errno (errno),
00094 "Failed to fork daemon: %s", _dbus_strerror (errno));
00095 return FALSE;
00096 break;
00097
00098 case 0:
00099 _dbus_verbose ("in child, closing std file descriptors\n");
00100
00101
00102
00103
00104
00105
00106 dev_null_fd = open ("/dev/null", O_RDWR);
00107 if (dev_null_fd >= 0)
00108 {
00109 dup2 (dev_null_fd, 0);
00110 dup2 (dev_null_fd, 1);
00111
00112 s = _dbus_getenv ("DBUS_DEBUG_OUTPUT");
00113 if (s == NULL || *s == '\0')
00114 dup2 (dev_null_fd, 2);
00115 else
00116 _dbus_verbose ("keeping stderr open due to DBUS_DEBUG_OUTPUT\n");
00117 }
00118
00119
00120 _dbus_verbose ("setting umask\n");
00121 umask (022);
00122 break;
00123
00124 default:
00125 if (pidfile)
00126 {
00127 _dbus_verbose ("parent writing pid file\n");
00128 if (!_dbus_write_pid_file (pidfile,
00129 child_pid,
00130 error))
00131 {
00132 _dbus_verbose ("pid file write failed, killing child\n");
00133 kill (child_pid, SIGTERM);
00134 return FALSE;
00135 }
00136 }
00137
00138
00139 if (print_pid_fd >= 0)
00140 {
00141 DBusString pid;
00142 int bytes;
00143
00144 if (!_dbus_string_init (&pid))
00145 {
00146 _DBUS_SET_OOM (error);
00147 kill (child_pid, SIGTERM);
00148 return FALSE;
00149 }
00150
00151 if (!_dbus_string_append_int (&pid, child_pid) ||
00152 !_dbus_string_append (&pid, "\n"))
00153 {
00154 _dbus_string_free (&pid);
00155 _DBUS_SET_OOM (error);
00156 kill (child_pid, SIGTERM);
00157 return FALSE;
00158 }
00159
00160 bytes = _dbus_string_get_length (&pid);
00161 if (_dbus_write_socket (print_pid_fd, &pid, 0, bytes) != bytes)
00162 {
00163 dbus_set_error (error, DBUS_ERROR_FAILED,
00164 "Printing message bus PID: %s\n",
00165 _dbus_strerror (errno));
00166 _dbus_string_free (&pid);
00167 kill (child_pid, SIGTERM);
00168 return FALSE;
00169 }
00170
00171 _dbus_string_free (&pid);
00172 }
00173 _dbus_verbose ("parent exiting\n");
00174 _exit (0);
00175 break;
00176 }
00177
00178 _dbus_verbose ("calling setsid()\n");
00179 if (setsid () == -1)
00180 _dbus_assert_not_reached ("setsid() failed");
00181
00182 return TRUE;
00183 }
00184
00185
00194 dbus_bool_t
00195 _dbus_write_pid_file (const DBusString *filename,
00196 unsigned long pid,
00197 DBusError *error)
00198 {
00199 const char *cfilename;
00200 int fd;
00201 FILE *f;
00202
00203 cfilename = _dbus_string_get_const_data (filename);
00204
00205 fd = open (cfilename, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644);
00206
00207 if (fd < 0)
00208 {
00209 dbus_set_error (error, _dbus_error_from_errno (errno),
00210 "Failed to open \"%s\": %s", cfilename,
00211 _dbus_strerror (errno));
00212 return FALSE;
00213 }
00214
00215 if ((f = fdopen (fd, "w")) == NULL)
00216 {
00217 dbus_set_error (error, _dbus_error_from_errno (errno),
00218 "Failed to fdopen fd %d: %s", fd, _dbus_strerror (errno));
00219 _dbus_close (fd, NULL);
00220 return FALSE;
00221 }
00222
00223 if (fprintf (f, "%lu\n", pid) < 0)
00224 {
00225 dbus_set_error (error, _dbus_error_from_errno (errno),
00226 "Failed to write to \"%s\": %s", cfilename,
00227 _dbus_strerror (errno));
00228
00229 fclose (f);
00230 return FALSE;
00231 }
00232
00233 if (fclose (f) == EOF)
00234 {
00235 dbus_set_error (error, _dbus_error_from_errno (errno),
00236 "Failed to close \"%s\": %s", cfilename,
00237 _dbus_strerror (errno));
00238 return FALSE;
00239 }
00240
00241 return TRUE;
00242 }
00243
00244
00253 dbus_bool_t
00254 _dbus_change_identity (dbus_uid_t uid,
00255 dbus_gid_t gid,
00256 DBusError *error)
00257 {
00258
00259
00260
00261
00262
00263
00264
00265 if (setgroups (0, NULL) < 0)
00266 _dbus_warn ("Failed to drop supplementary groups: %s\n",
00267 _dbus_strerror (errno));
00268
00269
00270
00271
00272 if (setgid (gid) < 0)
00273 {
00274 dbus_set_error (error, _dbus_error_from_errno (errno),
00275 "Failed to set GID to %lu: %s", gid,
00276 _dbus_strerror (errno));
00277 return FALSE;
00278 }
00279
00280 if (setuid (uid) < 0)
00281 {
00282 dbus_set_error (error, _dbus_error_from_errno (errno),
00283 "Failed to set UID to %lu: %s", uid,
00284 _dbus_strerror (errno));
00285 return FALSE;
00286 }
00287
00288 return TRUE;
00289 }
00290
00291 void
00292 _dbus_init_system_log (void)
00293 {
00294 openlog ("dbus", LOG_PID, LOG_DAEMON);
00295 }
00296
00304 void
00305 _dbus_log_info (const char *msg, va_list args)
00306 {
00307 vsyslog (LOG_DAEMON|LOG_NOTICE, msg, args);
00308 }
00309
00317 void
00318 _dbus_log_security (const char *msg, va_list args)
00319 {
00320 vsyslog (LOG_AUTH|LOG_NOTICE, msg, args);
00321 }
00322
00328 void
00329 _dbus_set_signal_handler (int sig,
00330 DBusSignalHandler handler)
00331 {
00332 struct sigaction act;
00333 sigset_t empty_mask;
00334
00335 sigemptyset (&empty_mask);
00336 act.sa_handler = handler;
00337 act.sa_mask = empty_mask;
00338 act.sa_flags = 0;
00339 sigaction (sig, &act, NULL);
00340 }
00341
00342
00350 dbus_bool_t
00351 _dbus_delete_directory (const DBusString *filename,
00352 DBusError *error)
00353 {
00354 const char *filename_c;
00355
00356 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00357
00358 filename_c = _dbus_string_get_const_data (filename);
00359
00360 if (rmdir (filename_c) != 0)
00361 {
00362 dbus_set_error (error, DBUS_ERROR_FAILED,
00363 "Failed to remove directory %s: %s\n",
00364 filename_c, _dbus_strerror (errno));
00365 return FALSE;
00366 }
00367
00368 return TRUE;
00369 }
00370
00376 dbus_bool_t
00377 _dbus_file_exists (const char *file)
00378 {
00379 return (access (file, F_OK) == 0);
00380 }
00381
00388 dbus_bool_t
00389 _dbus_user_at_console (const char *username,
00390 DBusError *error)
00391 {
00392
00393 DBusString f;
00394 dbus_bool_t result;
00395
00396 result = FALSE;
00397 if (!_dbus_string_init (&f))
00398 {
00399 _DBUS_SET_OOM (error);
00400 return FALSE;
00401 }
00402
00403 if (!_dbus_string_append (&f, DBUS_CONSOLE_AUTH_DIR))
00404 {
00405 _DBUS_SET_OOM (error);
00406 goto out;
00407 }
00408
00409
00410 if (!_dbus_string_append (&f, username))
00411 {
00412 _DBUS_SET_OOM (error);
00413 goto out;
00414 }
00415
00416 result = _dbus_file_exists (_dbus_string_get_const_data (&f));
00417
00418 out:
00419 _dbus_string_free (&f);
00420
00421 return result;
00422 }
00423
00424
00431 dbus_bool_t
00432 _dbus_path_is_absolute (const DBusString *filename)
00433 {
00434 if (_dbus_string_get_length (filename) > 0)
00435 return _dbus_string_get_byte (filename, 0) == '/';
00436 else
00437 return FALSE;
00438 }
00439
00448 dbus_bool_t
00449 _dbus_stat (const DBusString *filename,
00450 DBusStat *statbuf,
00451 DBusError *error)
00452 {
00453 const char *filename_c;
00454 struct stat sb;
00455
00456 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00457
00458 filename_c = _dbus_string_get_const_data (filename);
00459
00460 if (stat (filename_c, &sb) < 0)
00461 {
00462 dbus_set_error (error, _dbus_error_from_errno (errno),
00463 "%s", _dbus_strerror (errno));
00464 return FALSE;
00465 }
00466
00467 statbuf->mode = sb.st_mode;
00468 statbuf->nlink = sb.st_nlink;
00469 statbuf->uid = sb.st_uid;
00470 statbuf->gid = sb.st_gid;
00471 statbuf->size = sb.st_size;
00472 statbuf->atime = sb.st_atime;
00473 statbuf->mtime = sb.st_mtime;
00474 statbuf->ctime = sb.st_ctime;
00475
00476 return TRUE;
00477 }
00478
00479
00483 struct DBusDirIter
00484 {
00485 DIR *d;
00487 };
00488
00496 DBusDirIter*
00497 _dbus_directory_open (const DBusString *filename,
00498 DBusError *error)
00499 {
00500 DIR *d;
00501 DBusDirIter *iter;
00502 const char *filename_c;
00503
00504 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00505
00506 filename_c = _dbus_string_get_const_data (filename);
00507
00508 d = opendir (filename_c);
00509 if (d == NULL)
00510 {
00511 dbus_set_error (error, _dbus_error_from_errno (errno),
00512 "Failed to read directory \"%s\": %s",
00513 filename_c,
00514 _dbus_strerror (errno));
00515 return NULL;
00516 }
00517 iter = dbus_new0 (DBusDirIter, 1);
00518 if (iter == NULL)
00519 {
00520 closedir (d);
00521 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00522 "Could not allocate memory for directory iterator");
00523 return NULL;
00524 }
00525
00526 iter->d = d;
00527
00528 return iter;
00529 }
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539 static dbus_bool_t
00540 dirent_buf_size(DIR * dirp, size_t *size)
00541 {
00542 long name_max;
00543 # if defined(HAVE_FPATHCONF) && defined(_PC_NAME_MAX)
00544 # if defined(HAVE_DIRFD)
00545 name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
00546 # elif defined(HAVE_DDFD)
00547 name_max = fpathconf(dirp->dd_fd, _PC_NAME_MAX);
00548 # else
00549 name_max = fpathconf(dirp->__dd_fd, _PC_NAME_MAX);
00550 # endif
00551 if (name_max == -1)
00552 # if defined(NAME_MAX)
00553 name_max = NAME_MAX;
00554 # else
00555 return FALSE;
00556 # endif
00557 # elif defined(MAXNAMELEN)
00558 name_max = MAXNAMELEN;
00559 # else
00560 # if defined(NAME_MAX)
00561 name_max = NAME_MAX;
00562 # else
00563 # error "buffer size for readdir_r cannot be determined"
00564 # endif
00565 # endif
00566 if (size)
00567 *size = (size_t)offsetof(struct dirent, d_name) + name_max + 1;
00568 else
00569 return FALSE;
00570
00571 return TRUE;
00572 }
00573
00584 dbus_bool_t
00585 _dbus_directory_get_next_file (DBusDirIter *iter,
00586 DBusString *filename,
00587 DBusError *error)
00588 {
00589 struct dirent *d, *ent;
00590 size_t buf_size;
00591 int err;
00592
00593 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00594
00595 if (!dirent_buf_size (iter->d, &buf_size))
00596 {
00597 dbus_set_error (error, DBUS_ERROR_FAILED,
00598 "Can't calculate buffer size when reading directory");
00599 return FALSE;
00600 }
00601
00602 d = (struct dirent *)dbus_malloc (buf_size);
00603 if (!d)
00604 {
00605 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00606 "No memory to read directory entry");
00607 return FALSE;
00608 }
00609
00610 again:
00611 err = readdir_r (iter->d, d, &ent);
00612 if (err || !ent)
00613 {
00614 if (err != 0)
00615 dbus_set_error (error,
00616 _dbus_error_from_errno (err),
00617 "%s", _dbus_strerror (err));
00618
00619 dbus_free (d);
00620 return FALSE;
00621 }
00622 else if (ent->d_name[0] == '.' &&
00623 (ent->d_name[1] == '\0' ||
00624 (ent->d_name[1] == '.' && ent->d_name[2] == '\0')))
00625 goto again;
00626 else
00627 {
00628 _dbus_string_set_length (filename, 0);
00629 if (!_dbus_string_append (filename, ent->d_name))
00630 {
00631 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00632 "No memory to read directory entry");
00633 dbus_free (d);
00634 return FALSE;
00635 }
00636 else
00637 {
00638 dbus_free (d);
00639 return TRUE;
00640 }
00641 }
00642 }
00643
00647 void
00648 _dbus_directory_close (DBusDirIter *iter)
00649 {
00650 closedir (iter->d);
00651 dbus_free (iter);
00652 }
00653
00654 static dbus_bool_t
00655 fill_user_info_from_group (struct group *g,
00656 DBusGroupInfo *info,
00657 DBusError *error)
00658 {
00659 _dbus_assert (g->gr_name != NULL);
00660
00661 info->gid = g->gr_gid;
00662 info->groupname = _dbus_strdup (g->gr_name);
00663
00664
00665
00666 if (info->groupname == NULL)
00667 {
00668 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00669 return FALSE;
00670 }
00671
00672 return TRUE;
00673 }
00674
00675 static dbus_bool_t
00676 fill_group_info (DBusGroupInfo *info,
00677 dbus_gid_t gid,
00678 const DBusString *groupname,
00679 DBusError *error)
00680 {
00681 const char *group_c_str;
00682
00683 _dbus_assert (groupname != NULL || gid != DBUS_GID_UNSET);
00684 _dbus_assert (groupname == NULL || gid == DBUS_GID_UNSET);
00685
00686 if (groupname)
00687 group_c_str = _dbus_string_get_const_data (groupname);
00688 else
00689 group_c_str = NULL;
00690
00691
00692
00693
00694
00695
00696 #if defined (HAVE_POSIX_GETPWNAM_R) || defined (HAVE_NONPOSIX_GETPWNAM_R)
00697 {
00698 struct group *g;
00699 int result;
00700 char buf[1024];
00701 struct group g_str;
00702
00703 g = NULL;
00704 #ifdef HAVE_POSIX_GETPWNAM_R
00705
00706 if (group_c_str)
00707 result = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf),
00708 &g);
00709 else
00710 result = getgrgid_r (gid, &g_str, buf, sizeof (buf),
00711 &g);
00712 #else
00713 g = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf));
00714 result = 0;
00715 #endif
00716 if (result == 0 && g == &g_str)
00717 {
00718 return fill_user_info_from_group (g, info, error);
00719 }
00720 else
00721 {
00722 dbus_set_error (error, _dbus_error_from_errno (errno),
00723 "Group %s unknown or failed to look it up\n",
00724 group_c_str ? group_c_str : "???");
00725 return FALSE;
00726 }
00727 }
00728 #else
00729 {
00730
00731 struct group *g;
00732
00733 g = getgrnam (group_c_str);
00734
00735 if (g != NULL)
00736 {
00737 return fill_user_info_from_group (g, info, error);
00738 }
00739 else
00740 {
00741 dbus_set_error (error, _dbus_error_from_errno (errno),
00742 "Group %s unknown or failed to look it up\n",
00743 group_c_str ? group_c_str : "???");
00744 return FALSE;
00745 }
00746 }
00747 #endif
00748 }
00749
00759 dbus_bool_t
00760 _dbus_group_info_fill (DBusGroupInfo *info,
00761 const DBusString *groupname,
00762 DBusError *error)
00763 {
00764 return fill_group_info (info, DBUS_GID_UNSET,
00765 groupname, error);
00766
00767 }
00768
00778 dbus_bool_t
00779 _dbus_group_info_fill_gid (DBusGroupInfo *info,
00780 dbus_gid_t gid,
00781 DBusError *error)
00782 {
00783 return fill_group_info (info, gid, NULL, error);
00784 }
00785
00787
00799 dbus_bool_t
00800 _dbus_string_get_dirname (const DBusString *filename,
00801 DBusString *dirname)
00802 {
00803 int sep;
00804
00805 _dbus_assert (filename != dirname);
00806 _dbus_assert (filename != NULL);
00807 _dbus_assert (dirname != NULL);
00808
00809
00810 sep = _dbus_string_get_length (filename);
00811 if (sep == 0)
00812 return _dbus_string_append (dirname, ".");
00813
00814 while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
00815 --sep;
00816
00817 _dbus_assert (sep >= 0);
00818
00819 if (sep == 0)
00820 return _dbus_string_append (dirname, "/");
00821
00822
00823 _dbus_string_find_byte_backward (filename, sep, '/', &sep);
00824 if (sep < 0)
00825 return _dbus_string_append (dirname, ".");
00826
00827
00828 while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
00829 --sep;
00830
00831 _dbus_assert (sep >= 0);
00832
00833 if (sep == 0 &&
00834 _dbus_string_get_byte (filename, 0) == '/')
00835 return _dbus_string_append (dirname, "/");
00836 else
00837 return _dbus_string_copy_len (filename, 0, sep - 0,
00838 dirname, _dbus_string_get_length (dirname));
00839 }
00841
00842 static void
00843 string_squash_nonprintable (DBusString *str)
00844 {
00845 char *buf;
00846 int i, len;
00847
00848 buf = _dbus_string_get_data (str);
00849 len = _dbus_string_get_length (str);
00850
00851 for (i = 0; i < len; i++)
00852 if (buf[i] == '\0')
00853 buf[i] = ' ';
00854 else if (buf[i] < 0x20 || buf[i] > 127)
00855 buf[i] = '?';
00856 }
00857
00872 dbus_bool_t
00873 _dbus_command_for_pid (unsigned long pid,
00874 DBusString *str,
00875 int max_len,
00876 DBusError *error)
00877 {
00878
00879 DBusString path;
00880 DBusString cmdline;
00881 int fd;
00882
00883 if (!_dbus_string_init (&path))
00884 {
00885 _DBUS_SET_OOM (error);
00886 return FALSE;
00887 }
00888
00889 if (!_dbus_string_init (&cmdline))
00890 {
00891 _DBUS_SET_OOM (error);
00892 _dbus_string_free (&path);
00893 return FALSE;
00894 }
00895
00896 if (!_dbus_string_append_printf (&path, "/proc/%ld/cmdline", pid))
00897 goto oom;
00898
00899 fd = open (_dbus_string_get_const_data (&path), O_RDONLY);
00900 if (fd < 0)
00901 {
00902 dbus_set_error (error,
00903 _dbus_error_from_errno (errno),
00904 "Failed to open \"%s\": %s",
00905 _dbus_string_get_const_data (&path),
00906 _dbus_strerror (errno));
00907 goto fail;
00908 }
00909
00910 if (!_dbus_read (fd, &cmdline, max_len))
00911 {
00912 dbus_set_error (error,
00913 _dbus_error_from_errno (errno),
00914 "Failed to read from \"%s\": %s",
00915 _dbus_string_get_const_data (&path),
00916 _dbus_strerror (errno));
00917 goto fail;
00918 }
00919
00920 if (!_dbus_close (fd, error))
00921 goto fail;
00922
00923 string_squash_nonprintable (&cmdline);
00924
00925 if (!_dbus_string_copy (&cmdline, 0, str, _dbus_string_get_length (str)))
00926 goto oom;
00927
00928 _dbus_string_free (&cmdline);
00929 _dbus_string_free (&path);
00930 return TRUE;
00931 oom:
00932 _DBUS_SET_OOM (error);
00933 fail:
00934 _dbus_string_free (&cmdline);
00935 _dbus_string_free (&path);
00936 return FALSE;
00937 }