|
D-Bus
1.6.30
|
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 00002 /* dbus-sysdeps-util-unix.c Would be in dbus-sysdeps-unix.c, but not used in libdbus 00003 * 00004 * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. 00005 * Copyright (C) 2003 CodeFactory AB 00006 * 00007 * Licensed under the Academic Free License version 2.1 00008 * 00009 * This program is free software; you can redistribute it and/or modify 00010 * it under the terms of the GNU General Public License as published by 00011 * the Free Software Foundation; either version 2 of the License, or 00012 * (at your option) any later version. 00013 * 00014 * This program is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 * GNU General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU General Public License 00020 * along with this program; if not, write to the Free Software 00021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00022 * 00023 */ 00024 00025 #include <config.h> 00026 #include "dbus-sysdeps.h" 00027 #include "dbus-sysdeps-unix.h" 00028 #include "dbus-internals.h" 00029 #include "dbus-pipe.h" 00030 #include "dbus-protocol.h" 00031 #include "dbus-string.h" 00032 #define DBUS_USERDB_INCLUDES_PRIVATE 1 00033 #include "dbus-userdb.h" 00034 #include "dbus-test.h" 00035 00036 #include <sys/types.h> 00037 #include <stdlib.h> 00038 #include <string.h> 00039 #include <signal.h> 00040 #include <unistd.h> 00041 #include <stdio.h> 00042 #include <errno.h> 00043 #include <fcntl.h> 00044 #include <sys/stat.h> 00045 #ifdef HAVE_SYS_RESOURCE_H 00046 #include <sys/resource.h> 00047 #endif 00048 #include <grp.h> 00049 #include <sys/socket.h> 00050 #include <dirent.h> 00051 #include <sys/un.h> 00052 #include <syslog.h> 00053 00054 #ifdef HAVE_SYS_SYSLIMITS_H 00055 #include <sys/syslimits.h> 00056 #endif 00057 00058 #ifndef O_BINARY 00059 #define O_BINARY 0 00060 #endif 00061 00077 dbus_bool_t 00078 _dbus_become_daemon (const DBusString *pidfile, 00079 DBusPipe *print_pid_pipe, 00080 DBusError *error, 00081 dbus_bool_t keep_umask) 00082 { 00083 const char *s; 00084 pid_t child_pid; 00085 int dev_null_fd; 00086 00087 _dbus_verbose ("Becoming a daemon...\n"); 00088 00089 _dbus_verbose ("chdir to /\n"); 00090 if (chdir ("/") < 0) 00091 { 00092 dbus_set_error (error, DBUS_ERROR_FAILED, 00093 "Could not chdir() to root directory"); 00094 return FALSE; 00095 } 00096 00097 _dbus_verbose ("forking...\n"); 00098 switch ((child_pid = fork ())) 00099 { 00100 case -1: 00101 _dbus_verbose ("fork failed\n"); 00102 dbus_set_error (error, _dbus_error_from_errno (errno), 00103 "Failed to fork daemon: %s", _dbus_strerror (errno)); 00104 return FALSE; 00105 break; 00106 00107 case 0: 00108 _dbus_verbose ("in child, closing std file descriptors\n"); 00109 00110 /* silently ignore failures here, if someone 00111 * doesn't have /dev/null we may as well try 00112 * to continue anyhow 00113 */ 00114 00115 dev_null_fd = open ("/dev/null", O_RDWR); 00116 if (dev_null_fd >= 0) 00117 { 00118 dup2 (dev_null_fd, 0); 00119 dup2 (dev_null_fd, 1); 00120 00121 s = _dbus_getenv ("DBUS_DEBUG_OUTPUT"); 00122 if (s == NULL || *s == '\0') 00123 dup2 (dev_null_fd, 2); 00124 else 00125 _dbus_verbose ("keeping stderr open due to DBUS_DEBUG_OUTPUT\n"); 00126 close (dev_null_fd); 00127 } 00128 00129 if (!keep_umask) 00130 { 00131 /* Get a predictable umask */ 00132 _dbus_verbose ("setting umask\n"); 00133 umask (022); 00134 } 00135 00136 _dbus_verbose ("calling setsid()\n"); 00137 if (setsid () == -1) 00138 _dbus_assert_not_reached ("setsid() failed"); 00139 00140 break; 00141 00142 default: 00143 if (!_dbus_write_pid_to_file_and_pipe (pidfile, print_pid_pipe, 00144 child_pid, error)) 00145 { 00146 _dbus_verbose ("pid file or pipe write failed: %s\n", 00147 error->message); 00148 kill (child_pid, SIGTERM); 00149 return FALSE; 00150 } 00151 00152 _dbus_verbose ("parent exiting\n"); 00153 _exit (0); 00154 break; 00155 } 00156 00157 return TRUE; 00158 } 00159 00160 00169 static dbus_bool_t 00170 _dbus_write_pid_file (const DBusString *filename, 00171 unsigned long pid, 00172 DBusError *error) 00173 { 00174 const char *cfilename; 00175 int fd; 00176 FILE *f; 00177 00178 cfilename = _dbus_string_get_const_data (filename); 00179 00180 fd = open (cfilename, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644); 00181 00182 if (fd < 0) 00183 { 00184 dbus_set_error (error, _dbus_error_from_errno (errno), 00185 "Failed to open \"%s\": %s", cfilename, 00186 _dbus_strerror (errno)); 00187 return FALSE; 00188 } 00189 00190 if ((f = fdopen (fd, "w")) == NULL) 00191 { 00192 dbus_set_error (error, _dbus_error_from_errno (errno), 00193 "Failed to fdopen fd %d: %s", fd, _dbus_strerror (errno)); 00194 _dbus_close (fd, NULL); 00195 return FALSE; 00196 } 00197 00198 if (fprintf (f, "%lu\n", pid) < 0) 00199 { 00200 dbus_set_error (error, _dbus_error_from_errno (errno), 00201 "Failed to write to \"%s\": %s", cfilename, 00202 _dbus_strerror (errno)); 00203 00204 fclose (f); 00205 return FALSE; 00206 } 00207 00208 if (fclose (f) == EOF) 00209 { 00210 dbus_set_error (error, _dbus_error_from_errno (errno), 00211 "Failed to close \"%s\": %s", cfilename, 00212 _dbus_strerror (errno)); 00213 return FALSE; 00214 } 00215 00216 return TRUE; 00217 } 00218 00230 dbus_bool_t 00231 _dbus_write_pid_to_file_and_pipe (const DBusString *pidfile, 00232 DBusPipe *print_pid_pipe, 00233 dbus_pid_t pid_to_write, 00234 DBusError *error) 00235 { 00236 if (pidfile) 00237 { 00238 _dbus_verbose ("writing pid file %s\n", _dbus_string_get_const_data (pidfile)); 00239 if (!_dbus_write_pid_file (pidfile, 00240 pid_to_write, 00241 error)) 00242 { 00243 _dbus_verbose ("pid file write failed\n"); 00244 _DBUS_ASSERT_ERROR_IS_SET(error); 00245 return FALSE; 00246 } 00247 } 00248 else 00249 { 00250 _dbus_verbose ("No pid file requested\n"); 00251 } 00252 00253 if (print_pid_pipe != NULL && _dbus_pipe_is_valid (print_pid_pipe)) 00254 { 00255 DBusString pid; 00256 int bytes; 00257 00258 _dbus_verbose ("writing our pid to pipe %d\n", 00259 print_pid_pipe->fd); 00260 00261 if (!_dbus_string_init (&pid)) 00262 { 00263 _DBUS_SET_OOM (error); 00264 return FALSE; 00265 } 00266 00267 if (!_dbus_string_append_int (&pid, pid_to_write) || 00268 !_dbus_string_append (&pid, "\n")) 00269 { 00270 _dbus_string_free (&pid); 00271 _DBUS_SET_OOM (error); 00272 return FALSE; 00273 } 00274 00275 bytes = _dbus_string_get_length (&pid); 00276 if (_dbus_pipe_write (print_pid_pipe, &pid, 0, bytes, error) != bytes) 00277 { 00278 /* _dbus_pipe_write sets error only on failure, not short write */ 00279 if (error != NULL && !dbus_error_is_set(error)) 00280 { 00281 dbus_set_error (error, DBUS_ERROR_FAILED, 00282 "Printing message bus PID: did not write enough bytes\n"); 00283 } 00284 _dbus_string_free (&pid); 00285 return FALSE; 00286 } 00287 00288 _dbus_string_free (&pid); 00289 } 00290 else 00291 { 00292 _dbus_verbose ("No pid pipe to write to\n"); 00293 } 00294 00295 return TRUE; 00296 } 00297 00304 dbus_bool_t 00305 _dbus_verify_daemon_user (const char *user) 00306 { 00307 DBusString u; 00308 00309 _dbus_string_init_const (&u, user); 00310 00311 return _dbus_get_user_id_and_primary_group (&u, NULL, NULL); 00312 } 00313 00314 00315 /* The HAVE_LIBAUDIT case lives in selinux.c */ 00316 #ifndef HAVE_LIBAUDIT 00317 00324 dbus_bool_t 00325 _dbus_change_to_daemon_user (const char *user, 00326 DBusError *error) 00327 { 00328 dbus_uid_t uid; 00329 dbus_gid_t gid; 00330 DBusString u; 00331 00332 _dbus_string_init_const (&u, user); 00333 00334 if (!_dbus_get_user_id_and_primary_group (&u, &uid, &gid)) 00335 { 00336 dbus_set_error (error, DBUS_ERROR_FAILED, 00337 "User '%s' does not appear to exist?", 00338 user); 00339 return FALSE; 00340 } 00341 00342 /* setgroups() only works if we are a privileged process, 00343 * so we don't return error on failure; the only possible 00344 * failure is that we don't have perms to do it. 00345 * 00346 * not sure this is right, maybe if setuid() 00347 * is going to work then setgroups() should also work. 00348 */ 00349 if (setgroups (0, NULL) < 0) 00350 _dbus_warn ("Failed to drop supplementary groups: %s\n", 00351 _dbus_strerror (errno)); 00352 00353 /* Set GID first, or the setuid may remove our permission 00354 * to change the GID 00355 */ 00356 if (setgid (gid) < 0) 00357 { 00358 dbus_set_error (error, _dbus_error_from_errno (errno), 00359 "Failed to set GID to %lu: %s", gid, 00360 _dbus_strerror (errno)); 00361 return FALSE; 00362 } 00363 00364 if (setuid (uid) < 0) 00365 { 00366 dbus_set_error (error, _dbus_error_from_errno (errno), 00367 "Failed to set UID to %lu: %s", uid, 00368 _dbus_strerror (errno)); 00369 return FALSE; 00370 } 00371 00372 return TRUE; 00373 } 00374 #endif /* !HAVE_LIBAUDIT */ 00375 00376 #ifdef HAVE_SETRLIMIT 00377 00378 /* We assume that if we have setrlimit, we also have getrlimit and 00379 * struct rlimit. 00380 */ 00381 00382 struct DBusRLimit { 00383 struct rlimit lim; 00384 }; 00385 00386 DBusRLimit * 00387 _dbus_rlimit_save_fd_limit (DBusError *error) 00388 { 00389 DBusRLimit *self; 00390 00391 self = dbus_new0 (DBusRLimit, 1); 00392 00393 if (self == NULL) 00394 { 00395 _DBUS_SET_OOM (error); 00396 return NULL; 00397 } 00398 00399 if (getrlimit (RLIMIT_NOFILE, &self->lim) < 0) 00400 { 00401 dbus_set_error (error, _dbus_error_from_errno (errno), 00402 "Failed to get fd limit: %s", _dbus_strerror (errno)); 00403 dbus_free (self); 00404 return NULL; 00405 } 00406 00407 return self; 00408 } 00409 00410 dbus_bool_t 00411 _dbus_rlimit_raise_fd_limit_if_privileged (unsigned int desired, 00412 DBusError *error) 00413 { 00414 struct rlimit lim; 00415 00416 /* No point to doing this practically speaking 00417 * if we're not uid 0. We expect the system 00418 * bus to use this before we change UID, and 00419 * the session bus takes the Linux default, 00420 * currently 1024 for cur and 4096 for max. 00421 */ 00422 if (getuid () != 0) 00423 { 00424 /* not an error, we're probably the session bus */ 00425 return TRUE; 00426 } 00427 00428 if (getrlimit (RLIMIT_NOFILE, &lim) < 0) 00429 { 00430 dbus_set_error (error, _dbus_error_from_errno (errno), 00431 "Failed to get fd limit: %s", _dbus_strerror (errno)); 00432 return FALSE; 00433 } 00434 00435 if (lim.rlim_cur == RLIM_INFINITY || lim.rlim_cur >= desired) 00436 { 00437 /* not an error, everything is fine */ 00438 return TRUE; 00439 } 00440 00441 /* Ignore "maximum limit", assume we have the "superuser" 00442 * privileges. On Linux this is CAP_SYS_RESOURCE. 00443 */ 00444 lim.rlim_cur = lim.rlim_max = desired; 00445 00446 if (setrlimit (RLIMIT_NOFILE, &lim) < 0) 00447 { 00448 dbus_set_error (error, _dbus_error_from_errno (errno), 00449 "Failed to set fd limit to %u: %s", 00450 desired, _dbus_strerror (errno)); 00451 return FALSE; 00452 } 00453 00454 return TRUE; 00455 } 00456 00457 dbus_bool_t 00458 _dbus_rlimit_restore_fd_limit (DBusRLimit *saved, 00459 DBusError *error) 00460 { 00461 if (setrlimit (RLIMIT_NOFILE, &saved->lim) < 0) 00462 { 00463 dbus_set_error (error, _dbus_error_from_errno (errno), 00464 "Failed to restore old fd limit: %s", 00465 _dbus_strerror (errno)); 00466 return FALSE; 00467 } 00468 00469 return TRUE; 00470 } 00471 00472 #else /* !HAVE_SETRLIMIT */ 00473 00474 static void 00475 fd_limit_not_supported (DBusError *error) 00476 { 00477 dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, 00478 "cannot change fd limit on this platform"); 00479 } 00480 00481 DBusRLimit * 00482 _dbus_rlimit_save_fd_limit (DBusError *error) 00483 { 00484 fd_limit_not_supported (error); 00485 return NULL; 00486 } 00487 00488 dbus_bool_t 00489 _dbus_rlimit_raise_fd_limit_if_privileged (unsigned int desired, 00490 DBusError *error) 00491 { 00492 fd_limit_not_supported (error); 00493 return FALSE; 00494 } 00495 00496 dbus_bool_t 00497 _dbus_rlimit_restore_fd_limit (DBusRLimit *saved, 00498 DBusError *error) 00499 { 00500 fd_limit_not_supported (error); 00501 return FALSE; 00502 } 00503 00504 #endif 00505 00506 void 00507 _dbus_rlimit_free (DBusRLimit *lim) 00508 { 00509 dbus_free (lim); 00510 } 00511 00512 void 00513 _dbus_init_system_log (void) 00514 { 00515 #if HAVE_DECL_LOG_PERROR 00516 openlog ("dbus", LOG_PID | LOG_PERROR, LOG_DAEMON); 00517 #else 00518 openlog ("dbus", LOG_PID, LOG_DAEMON); 00519 #endif 00520 } 00521 00530 void 00531 _dbus_system_log (DBusSystemLogSeverity severity, const char *msg, ...) 00532 { 00533 va_list args; 00534 00535 va_start (args, msg); 00536 00537 _dbus_system_logv (severity, msg, args); 00538 00539 va_end (args); 00540 } 00541 00552 void 00553 _dbus_system_logv (DBusSystemLogSeverity severity, const char *msg, va_list args) 00554 { 00555 int flags; 00556 switch (severity) 00557 { 00558 case DBUS_SYSTEM_LOG_INFO: 00559 flags = LOG_DAEMON | LOG_NOTICE; 00560 break; 00561 case DBUS_SYSTEM_LOG_SECURITY: 00562 flags = LOG_AUTH | LOG_NOTICE; 00563 break; 00564 case DBUS_SYSTEM_LOG_FATAL: 00565 flags = LOG_DAEMON|LOG_CRIT; 00566 break; 00567 default: 00568 return; 00569 } 00570 00571 #ifndef HAVE_DECL_LOG_PERROR 00572 { 00573 /* vsyslog() won't write to stderr, so we'd better do it */ 00574 va_list tmp; 00575 00576 DBUS_VA_COPY (tmp, args); 00577 fprintf (stderr, "dbus[" DBUS_PID_FORMAT "]: ", _dbus_getpid ()); 00578 vfprintf (stderr, msg, tmp); 00579 fputc ('\n', stderr); 00580 va_end (tmp); 00581 } 00582 #endif 00583 00584 vsyslog (flags, msg, args); 00585 00586 if (severity == DBUS_SYSTEM_LOG_FATAL) 00587 exit (1); 00588 } 00589 00595 void 00596 _dbus_set_signal_handler (int sig, 00597 DBusSignalHandler handler) 00598 { 00599 struct sigaction act; 00600 sigset_t empty_mask; 00601 00602 sigemptyset (&empty_mask); 00603 act.sa_handler = handler; 00604 act.sa_mask = empty_mask; 00605 act.sa_flags = 0; 00606 sigaction (sig, &act, NULL); 00607 } 00608 00614 dbus_bool_t 00615 _dbus_file_exists (const char *file) 00616 { 00617 return (access (file, F_OK) == 0); 00618 } 00619 00626 dbus_bool_t 00627 _dbus_user_at_console (const char *username, 00628 DBusError *error) 00629 { 00630 00631 DBusString u, f; 00632 dbus_bool_t result; 00633 00634 result = FALSE; 00635 if (!_dbus_string_init (&f)) 00636 { 00637 _DBUS_SET_OOM (error); 00638 return FALSE; 00639 } 00640 00641 if (!_dbus_string_append (&f, DBUS_CONSOLE_AUTH_DIR)) 00642 { 00643 _DBUS_SET_OOM (error); 00644 goto out; 00645 } 00646 00647 _dbus_string_init_const (&u, username); 00648 00649 if (!_dbus_concat_dir_and_file (&f, &u)) 00650 { 00651 _DBUS_SET_OOM (error); 00652 goto out; 00653 } 00654 00655 result = _dbus_file_exists (_dbus_string_get_const_data (&f)); 00656 00657 out: 00658 _dbus_string_free (&f); 00659 00660 return result; 00661 } 00662 00663 00670 dbus_bool_t 00671 _dbus_path_is_absolute (const DBusString *filename) 00672 { 00673 if (_dbus_string_get_length (filename) > 0) 00674 return _dbus_string_get_byte (filename, 0) == '/'; 00675 else 00676 return FALSE; 00677 } 00678 00687 dbus_bool_t 00688 _dbus_stat (const DBusString *filename, 00689 DBusStat *statbuf, 00690 DBusError *error) 00691 { 00692 const char *filename_c; 00693 struct stat sb; 00694 00695 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00696 00697 filename_c = _dbus_string_get_const_data (filename); 00698 00699 if (stat (filename_c, &sb) < 0) 00700 { 00701 dbus_set_error (error, _dbus_error_from_errno (errno), 00702 "%s", _dbus_strerror (errno)); 00703 return FALSE; 00704 } 00705 00706 statbuf->mode = sb.st_mode; 00707 statbuf->nlink = sb.st_nlink; 00708 statbuf->uid = sb.st_uid; 00709 statbuf->gid = sb.st_gid; 00710 statbuf->size = sb.st_size; 00711 statbuf->atime = sb.st_atime; 00712 statbuf->mtime = sb.st_mtime; 00713 statbuf->ctime = sb.st_ctime; 00714 00715 return TRUE; 00716 } 00717 00718 00722 struct DBusDirIter 00723 { 00724 DIR *d; 00726 }; 00727 00735 DBusDirIter* 00736 _dbus_directory_open (const DBusString *filename, 00737 DBusError *error) 00738 { 00739 DIR *d; 00740 DBusDirIter *iter; 00741 const char *filename_c; 00742 00743 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00744 00745 filename_c = _dbus_string_get_const_data (filename); 00746 00747 d = opendir (filename_c); 00748 if (d == NULL) 00749 { 00750 dbus_set_error (error, _dbus_error_from_errno (errno), 00751 "Failed to read directory \"%s\": %s", 00752 filename_c, 00753 _dbus_strerror (errno)); 00754 return NULL; 00755 } 00756 iter = dbus_new0 (DBusDirIter, 1); 00757 if (iter == NULL) 00758 { 00759 closedir (d); 00760 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, 00761 "Could not allocate memory for directory iterator"); 00762 return NULL; 00763 } 00764 00765 iter->d = d; 00766 00767 return iter; 00768 } 00769 00783 dbus_bool_t 00784 _dbus_directory_get_next_file (DBusDirIter *iter, 00785 DBusString *filename, 00786 DBusError *error) 00787 { 00788 struct dirent *ent; 00789 int err; 00790 00791 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00792 00793 again: 00794 errno = 0; 00795 ent = readdir (iter->d); 00796 00797 if (!ent) 00798 { 00799 err = errno; 00800 00801 if (err != 0) 00802 dbus_set_error (error, 00803 _dbus_error_from_errno (err), 00804 "%s", _dbus_strerror (err)); 00805 00806 return FALSE; 00807 } 00808 else if (ent->d_name[0] == '.' && 00809 (ent->d_name[1] == '\0' || 00810 (ent->d_name[1] == '.' && ent->d_name[2] == '\0'))) 00811 goto again; 00812 else 00813 { 00814 _dbus_string_set_length (filename, 0); 00815 if (!_dbus_string_append (filename, ent->d_name)) 00816 { 00817 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, 00818 "No memory to read directory entry"); 00819 return FALSE; 00820 } 00821 else 00822 { 00823 return TRUE; 00824 } 00825 } 00826 } 00827 00831 void 00832 _dbus_directory_close (DBusDirIter *iter) 00833 { 00834 closedir (iter->d); 00835 dbus_free (iter); 00836 } 00837 00838 static dbus_bool_t 00839 fill_user_info_from_group (struct group *g, 00840 DBusGroupInfo *info, 00841 DBusError *error) 00842 { 00843 _dbus_assert (g->gr_name != NULL); 00844 00845 info->gid = g->gr_gid; 00846 info->groupname = _dbus_strdup (g->gr_name); 00847 00848 /* info->members = dbus_strdupv (g->gr_mem) */ 00849 00850 if (info->groupname == NULL) 00851 { 00852 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00853 return FALSE; 00854 } 00855 00856 return TRUE; 00857 } 00858 00859 static dbus_bool_t 00860 fill_group_info (DBusGroupInfo *info, 00861 dbus_gid_t gid, 00862 const DBusString *groupname, 00863 DBusError *error) 00864 { 00865 const char *group_c_str; 00866 00867 _dbus_assert (groupname != NULL || gid != DBUS_GID_UNSET); 00868 _dbus_assert (groupname == NULL || gid == DBUS_GID_UNSET); 00869 00870 if (groupname) 00871 group_c_str = _dbus_string_get_const_data (groupname); 00872 else 00873 group_c_str = NULL; 00874 00875 /* For now assuming that the getgrnam() and getgrgid() flavors 00876 * always correspond to the pwnam flavors, if not we have 00877 * to add more configure checks. 00878 */ 00879 00880 #if defined (HAVE_POSIX_GETPWNAM_R) || defined (HAVE_NONPOSIX_GETPWNAM_R) 00881 { 00882 struct group *g; 00883 int result; 00884 size_t buflen; 00885 char *buf; 00886 struct group g_str; 00887 dbus_bool_t b; 00888 00889 /* retrieve maximum needed size for buf */ 00890 buflen = sysconf (_SC_GETGR_R_SIZE_MAX); 00891 00892 /* sysconf actually returns a long, but everything else expects size_t, 00893 * so just recast here. 00894 * https://bugs.freedesktop.org/show_bug.cgi?id=17061 00895 */ 00896 if ((long) buflen <= 0) 00897 buflen = 1024; 00898 00899 result = -1; 00900 while (1) 00901 { 00902 buf = dbus_malloc (buflen); 00903 if (buf == NULL) 00904 { 00905 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00906 return FALSE; 00907 } 00908 00909 g = NULL; 00910 #ifdef HAVE_POSIX_GETPWNAM_R 00911 if (group_c_str) 00912 result = getgrnam_r (group_c_str, &g_str, buf, buflen, 00913 &g); 00914 else 00915 result = getgrgid_r (gid, &g_str, buf, buflen, 00916 &g); 00917 #else 00918 g = getgrnam_r (group_c_str, &g_str, buf, buflen); 00919 result = 0; 00920 #endif /* !HAVE_POSIX_GETPWNAM_R */ 00921 /* Try a bigger buffer if ERANGE was returned: 00922 https://bugs.freedesktop.org/show_bug.cgi?id=16727 00923 */ 00924 if (result == ERANGE && buflen < 512 * 1024) 00925 { 00926 dbus_free (buf); 00927 buflen *= 2; 00928 } 00929 else 00930 { 00931 break; 00932 } 00933 } 00934 00935 if (result == 0 && g == &g_str) 00936 { 00937 b = fill_user_info_from_group (g, info, error); 00938 dbus_free (buf); 00939 return b; 00940 } 00941 else 00942 { 00943 dbus_set_error (error, _dbus_error_from_errno (errno), 00944 "Group %s unknown or failed to look it up\n", 00945 group_c_str ? group_c_str : "???"); 00946 dbus_free (buf); 00947 return FALSE; 00948 } 00949 } 00950 #else /* ! HAVE_GETPWNAM_R */ 00951 { 00952 /* I guess we're screwed on thread safety here */ 00953 struct group *g; 00954 00955 g = getgrnam (group_c_str); 00956 00957 if (g != NULL) 00958 { 00959 return fill_user_info_from_group (g, info, error); 00960 } 00961 else 00962 { 00963 dbus_set_error (error, _dbus_error_from_errno (errno), 00964 "Group %s unknown or failed to look it up\n", 00965 group_c_str ? group_c_str : "???"); 00966 return FALSE; 00967 } 00968 } 00969 #endif /* ! HAVE_GETPWNAM_R */ 00970 } 00971 00981 dbus_bool_t 00982 _dbus_group_info_fill (DBusGroupInfo *info, 00983 const DBusString *groupname, 00984 DBusError *error) 00985 { 00986 return fill_group_info (info, DBUS_GID_UNSET, 00987 groupname, error); 00988 00989 } 00990 01000 dbus_bool_t 01001 _dbus_group_info_fill_gid (DBusGroupInfo *info, 01002 dbus_gid_t gid, 01003 DBusError *error) 01004 { 01005 return fill_group_info (info, gid, NULL, error); 01006 } 01007 01016 dbus_bool_t 01017 _dbus_parse_unix_user_from_config (const DBusString *username, 01018 dbus_uid_t *uid_p) 01019 { 01020 return _dbus_get_user_id (username, uid_p); 01021 01022 } 01023 01032 dbus_bool_t 01033 _dbus_parse_unix_group_from_config (const DBusString *groupname, 01034 dbus_gid_t *gid_p) 01035 { 01036 return _dbus_get_group_id (groupname, gid_p); 01037 } 01038 01049 dbus_bool_t 01050 _dbus_unix_groups_from_uid (dbus_uid_t uid, 01051 dbus_gid_t **group_ids, 01052 int *n_group_ids) 01053 { 01054 return _dbus_groups_from_uid (uid, group_ids, n_group_ids); 01055 } 01056 01066 dbus_bool_t 01067 _dbus_unix_user_is_at_console (dbus_uid_t uid, 01068 DBusError *error) 01069 { 01070 return _dbus_is_console_user (uid, error); 01071 01072 } 01073 01081 dbus_bool_t 01082 _dbus_unix_user_is_process_owner (dbus_uid_t uid) 01083 { 01084 return uid == _dbus_geteuid (); 01085 } 01086 01094 dbus_bool_t 01095 _dbus_windows_user_is_process_owner (const char *windows_sid) 01096 { 01097 return FALSE; 01098 } 01099 /* End of DBusInternalsUtils functions */ 01101 01113 dbus_bool_t 01114 _dbus_string_get_dirname (const DBusString *filename, 01115 DBusString *dirname) 01116 { 01117 int sep; 01118 01119 _dbus_assert (filename != dirname); 01120 _dbus_assert (filename != NULL); 01121 _dbus_assert (dirname != NULL); 01122 01123 /* Ignore any separators on the end */ 01124 sep = _dbus_string_get_length (filename); 01125 if (sep == 0) 01126 return _dbus_string_append (dirname, "."); /* empty string passed in */ 01127 01128 while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/') 01129 --sep; 01130 01131 _dbus_assert (sep >= 0); 01132 01133 if (sep == 0) 01134 return _dbus_string_append (dirname, "/"); 01135 01136 /* Now find the previous separator */ 01137 _dbus_string_find_byte_backward (filename, sep, '/', &sep); 01138 if (sep < 0) 01139 return _dbus_string_append (dirname, "."); 01140 01141 /* skip multiple separators */ 01142 while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/') 01143 --sep; 01144 01145 _dbus_assert (sep >= 0); 01146 01147 if (sep == 0 && 01148 _dbus_string_get_byte (filename, 0) == '/') 01149 return _dbus_string_append (dirname, "/"); 01150 else 01151 return _dbus_string_copy_len (filename, 0, sep - 0, 01152 dirname, _dbus_string_get_length (dirname)); 01153 } /* DBusString stuff */ 01155 01156 static void 01157 string_squash_nonprintable (DBusString *str) 01158 { 01159 unsigned char *buf; 01160 int i, len; 01161 01162 buf = _dbus_string_get_data (str); 01163 len = _dbus_string_get_length (str); 01164 01165 for (i = 0; i < len; i++) 01166 { 01167 unsigned char c = (unsigned char) buf[i]; 01168 if (c == '\0') 01169 buf[i] = ' '; 01170 else if (c < 0x20 || c > 127) 01171 buf[i] = '?'; 01172 } 01173 } 01174 01189 dbus_bool_t 01190 _dbus_command_for_pid (unsigned long pid, 01191 DBusString *str, 01192 int max_len, 01193 DBusError *error) 01194 { 01195 /* This is all Linux-specific for now */ 01196 DBusString path; 01197 DBusString cmdline; 01198 int fd; 01199 01200 if (!_dbus_string_init (&path)) 01201 { 01202 _DBUS_SET_OOM (error); 01203 return FALSE; 01204 } 01205 01206 if (!_dbus_string_init (&cmdline)) 01207 { 01208 _DBUS_SET_OOM (error); 01209 _dbus_string_free (&path); 01210 return FALSE; 01211 } 01212 01213 if (!_dbus_string_append_printf (&path, "/proc/%ld/cmdline", pid)) 01214 goto oom; 01215 01216 fd = open (_dbus_string_get_const_data (&path), O_RDONLY); 01217 if (fd < 0) 01218 { 01219 dbus_set_error (error, 01220 _dbus_error_from_errno (errno), 01221 "Failed to open \"%s\": %s", 01222 _dbus_string_get_const_data (&path), 01223 _dbus_strerror (errno)); 01224 goto fail; 01225 } 01226 01227 if (!_dbus_read (fd, &cmdline, max_len)) 01228 { 01229 dbus_set_error (error, 01230 _dbus_error_from_errno (errno), 01231 "Failed to read from \"%s\": %s", 01232 _dbus_string_get_const_data (&path), 01233 _dbus_strerror (errno)); 01234 _dbus_close (fd, NULL); 01235 goto fail; 01236 } 01237 01238 if (!_dbus_close (fd, error)) 01239 goto fail; 01240 01241 string_squash_nonprintable (&cmdline); 01242 01243 if (!_dbus_string_copy (&cmdline, 0, str, _dbus_string_get_length (str))) 01244 goto oom; 01245 01246 _dbus_string_free (&cmdline); 01247 _dbus_string_free (&path); 01248 return TRUE; 01249 oom: 01250 _DBUS_SET_OOM (error); 01251 fail: 01252 _dbus_string_free (&cmdline); 01253 _dbus_string_free (&path); 01254 return FALSE; 01255 }
1.7.6.1