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 <errno.h>
00040 #include <fcntl.h>
00041 #include <sys/stat.h>
00042 #include <grp.h>
00043 #include <sys/socket.h>
00044 #include <dirent.h>
00045 #include <sys/un.h>
00046 #include <glob.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
00296 void
00297 _dbus_set_signal_handler (int sig,
00298 DBusSignalHandler handler)
00299 {
00300 struct sigaction act;
00301 sigset_t empty_mask;
00302
00303 sigemptyset (&empty_mask);
00304 act.sa_handler = handler;
00305 act.sa_mask = empty_mask;
00306 act.sa_flags = 0;
00307 sigaction (sig, &act, NULL);
00308 }
00309
00310
00318 dbus_bool_t
00319 _dbus_delete_directory (const DBusString *filename,
00320 DBusError *error)
00321 {
00322 const char *filename_c;
00323
00324 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00325
00326 filename_c = _dbus_string_get_const_data (filename);
00327
00328 if (rmdir (filename_c) != 0)
00329 {
00330 dbus_set_error (error, DBUS_ERROR_FAILED,
00331 "Failed to remove directory %s: %s\n",
00332 filename_c, _dbus_strerror (errno));
00333 return FALSE;
00334 }
00335
00336 return TRUE;
00337 }
00338
00344 dbus_bool_t
00345 _dbus_file_exists (const char *file)
00346 {
00347 return (access (file, F_OK) == 0);
00348 }
00349
00356 dbus_bool_t
00357 _dbus_user_at_console (const char *username,
00358 DBusError *error)
00359 {
00360
00361 DBusString f;
00362 dbus_bool_t result;
00363 glob_t gl;
00364
00365 result = FALSE;
00366 if (!_dbus_string_init (&f))
00367 {
00368 _DBUS_SET_OOM (error);
00369 return FALSE;
00370 }
00371
00372 if (!_dbus_string_append (&f, DBUS_CONSOLE_AUTH_DIR))
00373 {
00374 _DBUS_SET_OOM (error);
00375 goto out;
00376 }
00377
00378
00379 if (!_dbus_string_append (&f, username))
00380 {
00381 _DBUS_SET_OOM (error);
00382 goto out;
00383 }
00384
00385
00386 if (!_dbus_string_append (&f, ":*"))
00387 {
00388 _DBUS_SET_OOM (error);
00389 goto out;
00390 }
00391
00392 if (glob (_dbus_string_get_const_data (&f), 0, NULL, &gl))
00393 goto out;
00394
00395 result = gl.gl_pathc > 0;
00396 globfree (&gl);
00397
00398 out:
00399 _dbus_string_free (&f);
00400
00401 return result;
00402 }
00403
00404
00411 dbus_bool_t
00412 _dbus_path_is_absolute (const DBusString *filename)
00413 {
00414 if (_dbus_string_get_length (filename) > 0)
00415 return _dbus_string_get_byte (filename, 0) == '/';
00416 else
00417 return FALSE;
00418 }
00419
00428 dbus_bool_t
00429 _dbus_stat (const DBusString *filename,
00430 DBusStat *statbuf,
00431 DBusError *error)
00432 {
00433 const char *filename_c;
00434 struct stat sb;
00435
00436 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00437
00438 filename_c = _dbus_string_get_const_data (filename);
00439
00440 if (stat (filename_c, &sb) < 0)
00441 {
00442 dbus_set_error (error, _dbus_error_from_errno (errno),
00443 "%s", _dbus_strerror (errno));
00444 return FALSE;
00445 }
00446
00447 statbuf->mode = sb.st_mode;
00448 statbuf->nlink = sb.st_nlink;
00449 statbuf->uid = sb.st_uid;
00450 statbuf->gid = sb.st_gid;
00451 statbuf->size = sb.st_size;
00452 statbuf->atime = sb.st_atime;
00453 statbuf->mtime = sb.st_mtime;
00454 statbuf->ctime = sb.st_ctime;
00455
00456 return TRUE;
00457 }
00458
00459
00463 struct DBusDirIter
00464 {
00465 DIR *d;
00467 };
00468
00476 DBusDirIter*
00477 _dbus_directory_open (const DBusString *filename,
00478 DBusError *error)
00479 {
00480 DIR *d;
00481 DBusDirIter *iter;
00482 const char *filename_c;
00483
00484 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00485
00486 filename_c = _dbus_string_get_const_data (filename);
00487
00488 d = opendir (filename_c);
00489 if (d == NULL)
00490 {
00491 dbus_set_error (error, _dbus_error_from_errno (errno),
00492 "Failed to read directory \"%s\": %s",
00493 filename_c,
00494 _dbus_strerror (errno));
00495 return NULL;
00496 }
00497 iter = dbus_new0 (DBusDirIter, 1);
00498 if (iter == NULL)
00499 {
00500 closedir (d);
00501 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00502 "Could not allocate memory for directory iterator");
00503 return NULL;
00504 }
00505
00506 iter->d = d;
00507
00508 return iter;
00509 }
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519 static dbus_bool_t
00520 dirent_buf_size(DIR * dirp, size_t *size)
00521 {
00522 long name_max;
00523 # if defined(HAVE_FPATHCONF) && defined(_PC_NAME_MAX)
00524 # if defined(HAVE_DIRFD)
00525 name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
00526 # elif defined(HAVE_DDFD)
00527 name_max = fpathconf(dirp->dd_fd, _PC_NAME_MAX);
00528 # else
00529 name_max = fpathconf(dirp->__dd_fd, _PC_NAME_MAX);
00530 # endif
00531 if (name_max == -1)
00532 # if defined(NAME_MAX)
00533 name_max = NAME_MAX;
00534 # else
00535 return FALSE;
00536 # endif
00537 # elif defined(MAXNAMELEN)
00538 name_max = MAXNAMELEN;
00539 # else
00540 # if defined(NAME_MAX)
00541 name_max = NAME_MAX;
00542 # else
00543 # error "buffer size for readdir_r cannot be determined"
00544 # endif
00545 # endif
00546 if (size)
00547 *size = (size_t)offsetof(struct dirent, d_name) + name_max + 1;
00548 else
00549 return FALSE;
00550
00551 return TRUE;
00552 }
00553
00564 dbus_bool_t
00565 _dbus_directory_get_next_file (DBusDirIter *iter,
00566 DBusString *filename,
00567 DBusError *error)
00568 {
00569 struct dirent *d, *ent;
00570 size_t buf_size;
00571 int err;
00572
00573 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00574
00575 if (!dirent_buf_size (iter->d, &buf_size))
00576 {
00577 dbus_set_error (error, DBUS_ERROR_FAILED,
00578 "Can't calculate buffer size when reading directory");
00579 return FALSE;
00580 }
00581
00582 d = (struct dirent *)dbus_malloc (buf_size);
00583 if (!d)
00584 {
00585 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00586 "No memory to read directory entry");
00587 return FALSE;
00588 }
00589
00590 again:
00591 err = readdir_r (iter->d, d, &ent);
00592 if (err || !ent)
00593 {
00594 if (err != 0)
00595 dbus_set_error (error,
00596 _dbus_error_from_errno (err),
00597 "%s", _dbus_strerror (err));
00598
00599 dbus_free (d);
00600 return FALSE;
00601 }
00602 else if (ent->d_name[0] == '.' &&
00603 (ent->d_name[1] == '\0' ||
00604 (ent->d_name[1] == '.' && ent->d_name[2] == '\0')))
00605 goto again;
00606 else
00607 {
00608 _dbus_string_set_length (filename, 0);
00609 if (!_dbus_string_append (filename, ent->d_name))
00610 {
00611 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00612 "No memory to read directory entry");
00613 dbus_free (d);
00614 return FALSE;
00615 }
00616 else
00617 {
00618 dbus_free (d);
00619 return TRUE;
00620 }
00621 }
00622 }
00623
00627 void
00628 _dbus_directory_close (DBusDirIter *iter)
00629 {
00630 closedir (iter->d);
00631 dbus_free (iter);
00632 }
00633
00634 static dbus_bool_t
00635 fill_user_info_from_group (struct group *g,
00636 DBusGroupInfo *info,
00637 DBusError *error)
00638 {
00639 _dbus_assert (g->gr_name != NULL);
00640
00641 info->gid = g->gr_gid;
00642 info->groupname = _dbus_strdup (g->gr_name);
00643
00644
00645
00646 if (info->groupname == NULL)
00647 {
00648 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00649 return FALSE;
00650 }
00651
00652 return TRUE;
00653 }
00654
00655 static dbus_bool_t
00656 fill_group_info (DBusGroupInfo *info,
00657 dbus_gid_t gid,
00658 const DBusString *groupname,
00659 DBusError *error)
00660 {
00661 const char *group_c_str;
00662
00663 _dbus_assert (groupname != NULL || gid != DBUS_GID_UNSET);
00664 _dbus_assert (groupname == NULL || gid == DBUS_GID_UNSET);
00665
00666 if (groupname)
00667 group_c_str = _dbus_string_get_const_data (groupname);
00668 else
00669 group_c_str = NULL;
00670
00671
00672
00673
00674
00675
00676 #if defined (HAVE_POSIX_GETPWNAM_R) || defined (HAVE_NONPOSIX_GETPWNAM_R)
00677 {
00678 struct group *g;
00679 int result;
00680 char buf[1024];
00681 struct group g_str;
00682
00683 g = NULL;
00684 #ifdef HAVE_POSIX_GETPWNAM_R
00685
00686 if (group_c_str)
00687 result = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf),
00688 &g);
00689 else
00690 result = getgrgid_r (gid, &g_str, buf, sizeof (buf),
00691 &g);
00692 #else
00693 g = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf));
00694 result = 0;
00695 #endif
00696 if (result == 0 && g == &g_str)
00697 {
00698 return fill_user_info_from_group (g, info, error);
00699 }
00700 else
00701 {
00702 dbus_set_error (error, _dbus_error_from_errno (errno),
00703 "Group %s unknown or failed to look it up\n",
00704 group_c_str ? group_c_str : "???");
00705 return FALSE;
00706 }
00707 }
00708 #else
00709 {
00710
00711 struct group *g;
00712
00713 g = getgrnam (group_c_str);
00714
00715 if (g != NULL)
00716 {
00717 return fill_user_info_from_group (g, info, error);
00718 }
00719 else
00720 {
00721 dbus_set_error (error, _dbus_error_from_errno (errno),
00722 "Group %s unknown or failed to look it up\n",
00723 group_c_str ? group_c_str : "???");
00724 return FALSE;
00725 }
00726 }
00727 #endif
00728 }
00729
00739 dbus_bool_t
00740 _dbus_group_info_fill (DBusGroupInfo *info,
00741 const DBusString *groupname,
00742 DBusError *error)
00743 {
00744 return fill_group_info (info, DBUS_GID_UNSET,
00745 groupname, error);
00746
00747 }
00748
00758 dbus_bool_t
00759 _dbus_group_info_fill_gid (DBusGroupInfo *info,
00760 dbus_gid_t gid,
00761 DBusError *error)
00762 {
00763 return fill_group_info (info, gid, NULL, error);
00764 }
00765
00767
00779 dbus_bool_t
00780 _dbus_string_get_dirname (const DBusString *filename,
00781 DBusString *dirname)
00782 {
00783 int sep;
00784
00785 _dbus_assert (filename != dirname);
00786 _dbus_assert (filename != NULL);
00787 _dbus_assert (dirname != NULL);
00788
00789
00790 sep = _dbus_string_get_length (filename);
00791 if (sep == 0)
00792 return _dbus_string_append (dirname, ".");
00793
00794 while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
00795 --sep;
00796
00797 _dbus_assert (sep >= 0);
00798
00799 if (sep == 0)
00800 return _dbus_string_append (dirname, "/");
00801
00802
00803 _dbus_string_find_byte_backward (filename, sep, '/', &sep);
00804 if (sep < 0)
00805 return _dbus_string_append (dirname, ".");
00806
00807
00808 while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
00809 --sep;
00810
00811 _dbus_assert (sep >= 0);
00812
00813 if (sep == 0 &&
00814 _dbus_string_get_byte (filename, 0) == '/')
00815 return _dbus_string_append (dirname, "/");
00816 else
00817 return _dbus_string_copy_len (filename, 0, sep - 0,
00818 dirname, _dbus_string_get_length (dirname));
00819 }
00821