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 3 * 4 * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. 5 * Copyright (C) 2003 CodeFactory AB 6 * 7 * Licensed under the Academic Free License version 2.1 8 * 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. 13 * 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. 18 * 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 22 * 23 */ 24 #include "dbus-sysdeps.h" 25 #include "dbus-sysdeps-unix.h" 26 #include "dbus-internals.h" 27 #include "dbus-protocol.h" 28 #include "dbus-string.h" 29 #define DBUS_USERDB_INCLUDES_PRIVATE 1 30 #include "dbus-userdb.h" 31 #include "dbus-test.h" 32 33 #include <sys/types.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <signal.h> 37 #include <unistd.h> 38 #include <stdio.h> 39 #include <errno.h> 40 #include <fcntl.h> 41 #include <sys/stat.h> 42 #include <grp.h> 43 #include <sys/socket.h> 44 #include <dirent.h> 45 #include <sys/un.h> 46 47 #ifdef HAVE_SYS_SYSLIMITS_H 48 #include <sys/syslimits.h> 49 #endif 50 51 #ifndef O_BINARY 52 #define O_BINARY 0 53 #endif 54 55 /** 56 * @addtogroup DBusInternalsUtils 57 * @{ 58 */ 59 60 /** 61 * Does the chdir, fork, setsid, etc. to become a daemon process. 62 * 63 * @param pidfile #NULL, or pidfile to create 64 * @param print_pid_fd file descriptor to print daemon's pid to, or -1 for none 65 * @param error return location for errors 66 * @returns #FALSE on failure 67 */ 68 dbus_bool_t 69 _dbus_become_daemon (const DBusString *pidfile, 70 int print_pid_fd, 71 DBusError *error) 72 { 73 const char *s; 74 pid_t child_pid; 75 int dev_null_fd; 76 77 _dbus_verbose ("Becoming a daemon...\n"); 78 79 _dbus_verbose ("chdir to /\n"); 80 if (chdir ("/") < 0) 81 { 82 dbus_set_error (error, DBUS_ERROR_FAILED, 83 "Could not chdir() to root directory"); 84 return FALSE; 85 } 86 87 _dbus_verbose ("forking...\n"); 88 switch ((child_pid = fork ())) 89 { 90 case -1: 91 _dbus_verbose ("fork failed\n"); 92 dbus_set_error (error, _dbus_error_from_errno (errno), 93 "Failed to fork daemon: %s", _dbus_strerror (errno)); 94 return FALSE; 95 break; 96 97 case 0: 98 _dbus_verbose ("in child, closing std file descriptors\n"); 99 100 /* silently ignore failures here, if someone 101 * doesn't have /dev/null we may as well try 102 * to continue anyhow 103 */ 104 105 dev_null_fd = open ("/dev/null", O_RDWR); 106 if (dev_null_fd >= 0) 107 { 108 dup2 (dev_null_fd, 0); 109 dup2 (dev_null_fd, 1); 110 111 s = _dbus_getenv ("DBUS_DEBUG_OUTPUT"); 112 if (s == NULL || *s == '\0') 113 dup2 (dev_null_fd, 2); 114 else 115 _dbus_verbose ("keeping stderr open due to DBUS_DEBUG_OUTPUT\n"); 116 } 117 118 /* Get a predictable umask */ 119 _dbus_verbose ("setting umask\n"); 120 umask (022); 121 break; 122 123 default: 124 if (pidfile) 125 { 126 _dbus_verbose ("parent writing pid file\n"); 127 if (!_dbus_write_pid_file (pidfile, 128 child_pid, 129 error)) 130 { 131 _dbus_verbose ("pid file write failed, killing child\n"); 132 kill (child_pid, SIGTERM); 133 return FALSE; 134 } 135 } 136 137 /* Write PID if requested */ 138 if (print_pid_fd >= 0) 139 { 140 DBusString pid; 141 int bytes; 142 143 if (!_dbus_string_init (&pid)) 144 { 145 _DBUS_SET_OOM (error); 146 kill (child_pid, SIGTERM); 147 return FALSE; 148 } 149 150 if (!_dbus_string_append_int (&pid, child_pid) || 151 !_dbus_string_append (&pid, "\n")) 152 { 153 _dbus_string_free (&pid); 154 _DBUS_SET_OOM (error); 155 kill (child_pid, SIGTERM); 156 return FALSE; 157 } 158 159 bytes = _dbus_string_get_length (&pid); 160 if (_dbus_write_socket (print_pid_fd, &pid, 0, bytes) != bytes) 161 { 162 dbus_set_error (error, DBUS_ERROR_FAILED, 163 "Printing message bus PID: %s\n", 164 _dbus_strerror (errno)); 165 _dbus_string_free (&pid); 166 kill (child_pid, SIGTERM); 167 return FALSE; 168 } 169 170 _dbus_string_free (&pid); 171 } 172 _dbus_verbose ("parent exiting\n"); 173 _exit (0); 174 break; 175 } 176 177 _dbus_verbose ("calling setsid()\n"); 178 if (setsid () == -1) 179 _dbus_assert_not_reached ("setsid() failed"); 180 181 return TRUE; 182 } 183 184 185 /** 186 * Creates a file containing the process ID. 187 * 188 * @param filename the filename to write to 189 * @param pid our process ID 190 * @param error return location for errors 191 * @returns #FALSE on failure 192 */ 193 dbus_bool_t 194 _dbus_write_pid_file (const DBusString *filename, 195 unsigned long pid, 196 DBusError *error) 197 { 198 const char *cfilename; 199 int fd; 200 FILE *f; 201 202 cfilename = _dbus_string_get_const_data (filename); 203 204 fd = open (cfilename, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644); 205 206 if (fd < 0) 207 { 208 dbus_set_error (error, _dbus_error_from_errno (errno), 209 "Failed to open \"%s\": %s", cfilename, 210 _dbus_strerror (errno)); 211 return FALSE; 212 } 213 214 if ((f = fdopen (fd, "w")) == NULL) 215 { 216 dbus_set_error (error, _dbus_error_from_errno (errno), 217 "Failed to fdopen fd %d: %s", fd, _dbus_strerror (errno)); 218 _dbus_close (fd, NULL); 219 return FALSE; 220 } 221 222 if (fprintf (f, "%lu\n", pid) < 0) 223 { 224 dbus_set_error (error, _dbus_error_from_errno (errno), 225 "Failed to write to \"%s\": %s", cfilename, 226 _dbus_strerror (errno)); 227 228 fclose (f); 229 return FALSE; 230 } 231 232 if (fclose (f) == EOF) 233 { 234 dbus_set_error (error, _dbus_error_from_errno (errno), 235 "Failed to close \"%s\": %s", cfilename, 236 _dbus_strerror (errno)); 237 return FALSE; 238 } 239 240 return TRUE; 241 } 242 243 244 /** 245 * Changes the user and group the bus is running as. 246 * 247 * @param uid the new user ID 248 * @param gid the new group ID 249 * @param error return location for errors 250 * @returns #FALSE on failure 251 */ 252 dbus_bool_t 253 _dbus_change_identity (dbus_uid_t uid, 254 dbus_gid_t gid, 255 DBusError *error) 256 { 257 /* setgroups() only works if we are a privileged process, 258 * so we don't return error on failure; the only possible 259 * failure is that we don't have perms to do it. 260 * 261 * not sure this is right, maybe if setuid() 262 * is going to work then setgroups() should also work. 263 */ 264 if (setgroups (0, NULL) < 0) 265 _dbus_warn ("Failed to drop supplementary groups: %s\n", 266 _dbus_strerror (errno)); 267 268 /* Set GID first, or the setuid may remove our permission 269 * to change the GID 270 */ 271 if (setgid (gid) < 0) 272 { 273 dbus_set_error (error, _dbus_error_from_errno (errno), 274 "Failed to set GID to %lu: %s", gid, 275 _dbus_strerror (errno)); 276 return FALSE; 277 } 278 279 if (setuid (uid) < 0) 280 { 281 dbus_set_error (error, _dbus_error_from_errno (errno), 282 "Failed to set UID to %lu: %s", uid, 283 _dbus_strerror (errno)); 284 return FALSE; 285 } 286 287 return TRUE; 288 } 289 290 /** Installs a UNIX signal handler 291 * 292 * @param sig the signal to handle 293 * @param handler the handler 294 */ 295 void 296 _dbus_set_signal_handler (int sig, 297 DBusSignalHandler handler) 298 { 299 struct sigaction act; 300 sigset_t empty_mask; 301 302 sigemptyset (&empty_mask); 303 act.sa_handler = handler; 304 act.sa_mask = empty_mask; 305 act.sa_flags = 0; 306 sigaction (sig, &act, NULL); 307 } 308 309 310 /** 311 * Removes a directory; Directory must be empty 312 * 313 * @param filename directory filename 314 * @param error initialized error object 315 * @returns #TRUE on success 316 */ 317 dbus_bool_t 318 _dbus_delete_directory (const DBusString *filename, 319 DBusError *error) 320 { 321 const char *filename_c; 322 323 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 324 325 filename_c = _dbus_string_get_const_data (filename); 326 327 if (rmdir (filename_c) != 0) 328 { 329 dbus_set_error (error, DBUS_ERROR_FAILED, 330 "Failed to remove directory %s: %s\n", 331 filename_c, _dbus_strerror (errno)); 332 return FALSE; 333 } 334 335 return TRUE; 336 } 337 338 /** Checks if a file exists 339 * 340 * @param file full path to the file 341 * @returns #TRUE if file exists 342 */ 343 dbus_bool_t 344 _dbus_file_exists (const char *file) 345 { 346 return (access (file, F_OK) == 0); 347 } 348 349 /** Checks if user is at the console 350 * 351 * @param username user to check 352 * @param error return location for errors 353 * @returns #TRUE is the user is at the consolei and there are no errors 354 */ 355 dbus_bool_t 356 _dbus_user_at_console (const char *username, 357 DBusError *error) 358 { 359 360 DBusString f; 361 dbus_bool_t result; 362 363 result = FALSE; 364 if (!_dbus_string_init (&f)) 365 { 366 _DBUS_SET_OOM (error); 367 return FALSE; 368 } 369 370 if (!_dbus_string_append (&f, DBUS_CONSOLE_AUTH_DIR)) 371 { 372 _DBUS_SET_OOM (error); 373 goto out; 374 } 375 376 377 if (!_dbus_string_append (&f, username)) 378 { 379 _DBUS_SET_OOM (error); 380 goto out; 381 } 382 383 result = _dbus_file_exists (_dbus_string_get_const_data (&f)); 384 385 out: 386 _dbus_string_free (&f); 387 388 return result; 389 } 390 391 392 /** 393 * Checks whether the filename is an absolute path 394 * 395 * @param filename the filename 396 * @returns #TRUE if an absolute path 397 */ 398 dbus_bool_t 399 _dbus_path_is_absolute (const DBusString *filename) 400 { 401 if (_dbus_string_get_length (filename) > 0) 402 return _dbus_string_get_byte (filename, 0) == '/'; 403 else 404 return FALSE; 405 } 406 407 /** 408 * stat() wrapper. 409 * 410 * @param filename the filename to stat 411 * @param statbuf the stat info to fill in 412 * @param error return location for error 413 * @returns #FALSE if error was set 414 */ 415 dbus_bool_t 416 _dbus_stat (const DBusString *filename, 417 DBusStat *statbuf, 418 DBusError *error) 419 { 420 const char *filename_c; 421 struct stat sb; 422 423 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 424 425 filename_c = _dbus_string_get_const_data (filename); 426 427 if (stat (filename_c, &sb) < 0) 428 { 429 dbus_set_error (error, _dbus_error_from_errno (errno), 430 "%s", _dbus_strerror (errno)); 431 return FALSE; 432 } 433 434 statbuf->mode = sb.st_mode; 435 statbuf->nlink = sb.st_nlink; 436 statbuf->uid = sb.st_uid; 437 statbuf->gid = sb.st_gid; 438 statbuf->size = sb.st_size; 439 statbuf->atime = sb.st_atime; 440 statbuf->mtime = sb.st_mtime; 441 statbuf->ctime = sb.st_ctime; 442 443 return TRUE; 444 } 445 446 447 /** 448 * Internals of directory iterator 449 */ 450 struct DBusDirIter 451 { 452 DIR *d; /**< The DIR* from opendir() */ 453 454 }; 455 456 /** 457 * Open a directory to iterate over. 458 * 459 * @param filename the directory name 460 * @param error exception return object or #NULL 461 * @returns new iterator, or #NULL on error 462 */ 463 DBusDirIter* 464 _dbus_directory_open (const DBusString *filename, 465 DBusError *error) 466 { 467 DIR *d; 468 DBusDirIter *iter; 469 const char *filename_c; 470 471 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 472 473 filename_c = _dbus_string_get_const_data (filename); 474 475 d = opendir (filename_c); 476 if (d == NULL) 477 { 478 dbus_set_error (error, _dbus_error_from_errno (errno), 479 "Failed to read directory \"%s\": %s", 480 filename_c, 481 _dbus_strerror (errno)); 482 return NULL; 483 } 484 iter = dbus_new0 (DBusDirIter, 1); 485 if (iter == NULL) 486 { 487 closedir (d); 488 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, 489 "Could not allocate memory for directory iterator"); 490 return NULL; 491 } 492 493 iter->d = d; 494 495 return iter; 496 } 497 498 /* it is never safe to retrun a size smaller than sizeof(struct dirent) 499 * because the libc *could* try to access the whole structure 500 * (for instance it could try to memset it). 501 * it is also incorrect to return a size bigger than that, because 502 * the libc would never use it. 503 * The only correct and safe value this function can ever return is 504 * sizeof(struct dirent). 505 */ 506 static dbus_bool_t 507 dirent_buf_size(DIR * dirp, size_t *size) 508 { 509 *size = sizeof(struct dirent); 510 return TRUE; 511 } 512 513 /** 514 * Get next file in the directory. Will not return "." or ".." on 515 * UNIX. If an error occurs, the contents of "filename" are 516 * undefined. The error is never set if the function succeeds. 517 * 518 * @param iter the iterator 519 * @param filename string to be set to the next file in the dir 520 * @param error return location for error 521 * @returns #TRUE if filename was filled in with a new filename 522 */ 523 dbus_bool_t 524 _dbus_directory_get_next_file (DBusDirIter *iter, 525 DBusString *filename, 526 DBusError *error) 527 { 528 struct dirent *d, *ent; 529 size_t buf_size; 530 int err; 531 532 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 533 534 if (!dirent_buf_size (iter->d, &buf_size)) 535 { 536 dbus_set_error (error, DBUS_ERROR_FAILED, 537 "Can't calculate buffer size when reading directory"); 538 return FALSE; 539 } 540 541 d = (struct dirent *)dbus_malloc (buf_size); 542 if (!d) 543 { 544 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, 545 "No memory to read directory entry"); 546 return FALSE; 547 } 548 549 again: 550 err = readdir_r (iter->d, d, &ent); 551 if (err || !ent) 552 { 553 if (err != 0) 554 dbus_set_error (error, 555 _dbus_error_from_errno (err), 556 "%s", _dbus_strerror (err)); 557 558 dbus_free (d); 559 return FALSE; 560 } 561 else if (ent->d_name[0] == '.' && 562 (ent->d_name[1] == '\0' || 563 (ent->d_name[1] == '.' && ent->d_name[2] == '\0'))) 564 goto again; 565 else 566 { 567 _dbus_string_set_length (filename, 0); 568 if (!_dbus_string_append (filename, ent->d_name)) 569 { 570 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, 571 "No memory to read directory entry"); 572 dbus_free (d); 573 return FALSE; 574 } 575 else 576 { 577 dbus_free (d); 578 return TRUE; 579 } 580 } 581 } 582 583 /** 584 * Closes a directory iteration. 585 */ 586 void 587 _dbus_directory_close (DBusDirIter *iter) 588 { 589 closedir (iter->d); 590 dbus_free (iter); 591 } 592 593 static dbus_bool_t 594 fill_user_info_from_group (struct group *g, 595 DBusGroupInfo *info, 596 DBusError *error) 597 { 598 _dbus_assert (g->gr_name != NULL); 599 600 info->gid = g->gr_gid; 601 info->groupname = _dbus_strdup (g->gr_name); 602 603 /* info->members = dbus_strdupv (g->gr_mem) */ 604 605 if (info->groupname == NULL) 606 { 607 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 608 return FALSE; 609 } 610 611 return TRUE; 612 } 613 614 static dbus_bool_t 615 fill_group_info (DBusGroupInfo *info, 616 dbus_gid_t gid, 617 const DBusString *groupname, 618 DBusError *error) 619 { 620 const char *group_c_str; 621 622 _dbus_assert (groupname != NULL || gid != DBUS_GID_UNSET); 623 _dbus_assert (groupname == NULL || gid == DBUS_GID_UNSET); 624 625 if (groupname) 626 group_c_str = _dbus_string_get_const_data (groupname); 627 else 628 group_c_str = NULL; 629 630 /* For now assuming that the getgrnam() and getgrgid() flavors 631 * always correspond to the pwnam flavors, if not we have 632 * to add more configure checks. 633 */ 634 635 #if defined (HAVE_POSIX_GETPWNAM_R) || defined (HAVE_NONPOSIX_GETPWNAM_R) 636 { 637 struct group *g; 638 int result; 639 char buf[1024]; 640 struct group g_str; 641 642 g = NULL; 643 #ifdef HAVE_POSIX_GETPWNAM_R 644 645 if (group_c_str) 646 result = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf), 647 &g); 648 else 649 result = getgrgid_r (gid, &g_str, buf, sizeof (buf), 650 &g); 651 #else 652 g = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf)); 653 result = 0; 654 #endif /* !HAVE_POSIX_GETPWNAM_R */ 655 if (result == 0 && g == &g_str) 656 { 657 return fill_user_info_from_group (g, info, error); 658 } 659 else 660 { 661 dbus_set_error (error, _dbus_error_from_errno (errno), 662 "Group %s unknown or failed to look it up\n", 663 group_c_str ? group_c_str : "???"); 664 return FALSE; 665 } 666 } 667 #else /* ! HAVE_GETPWNAM_R */ 668 { 669 /* I guess we're screwed on thread safety here */ 670 struct group *g; 671 672 g = getgrnam (group_c_str); 673 674 if (g != NULL) 675 { 676 return fill_user_info_from_group (g, info, error); 677 } 678 else 679 { 680 dbus_set_error (error, _dbus_error_from_errno (errno), 681 "Group %s unknown or failed to look it up\n", 682 group_c_str ? group_c_str : "???"); 683 return FALSE; 684 } 685 } 686 #endif /* ! HAVE_GETPWNAM_R */ 687 } 688 689 /** 690 * Initializes the given DBusGroupInfo struct 691 * with information about the given group name. 692 * 693 * @param info the group info struct 694 * @param groupname name of group 695 * @param error the error return 696 * @returns #FALSE if error is set 697 */ 698 dbus_bool_t 699 _dbus_group_info_fill (DBusGroupInfo *info, 700 const DBusString *groupname, 701 DBusError *error) 702 { 703 return fill_group_info (info, DBUS_GID_UNSET, 704 groupname, error); 705 706 } 707 708 /** 709 * Initializes the given DBusGroupInfo struct 710 * with information about the given group ID. 711 * 712 * @param info the group info struct 713 * @param gid group ID 714 * @param error the error return 715 * @returns #FALSE if error is set 716 */ 717 dbus_bool_t 718 _dbus_group_info_fill_gid (DBusGroupInfo *info, 719 dbus_gid_t gid, 720 DBusError *error) 721 { 722 return fill_group_info (info, gid, NULL, error); 723 } 724 725 /** @} */ /* End of DBusInternalsUtils functions */ 726 727 /** 728 * @addtogroup DBusString 729 * 730 * @{ 731 */ 732 /** 733 * Get the directory name from a complete filename 734 * @param filename the filename 735 * @param dirname string to append directory name to 736 * @returns #FALSE if no memory 737 */ 738 dbus_bool_t 739 _dbus_string_get_dirname (const DBusString *filename, 740 DBusString *dirname) 741 { 742 int sep; 743 744 _dbus_assert (filename != dirname); 745 _dbus_assert (filename != NULL); 746 _dbus_assert (dirname != NULL); 747 748 /* Ignore any separators on the end */ 749 sep = _dbus_string_get_length (filename); 750 if (sep == 0) 751 return _dbus_string_append (dirname, "."); /* empty string passed in */ 752 753 while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/') 754 --sep; 755 756 _dbus_assert (sep >= 0); 757 758 if (sep == 0) 759 return _dbus_string_append (dirname, "/"); 760 761 /* Now find the previous separator */ 762 _dbus_string_find_byte_backward (filename, sep, '/', &sep); 763 if (sep < 0) 764 return _dbus_string_append (dirname, "."); 765 766 /* skip multiple separators */ 767 while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/') 768 --sep; 769 770 _dbus_assert (sep >= 0); 771 772 if (sep == 0 && 773 _dbus_string_get_byte (filename, 0) == '/') 774 return _dbus_string_append (dirname, "/"); 775 else 776 return _dbus_string_copy_len (filename, 0, sep - 0, 777 dirname, _dbus_string_get_length (dirname)); 778 } 779 /** @} */ /* DBusString stuff */ 780 781