/** * Verify that after the fork we can successfully change to this user. * * @param user the username given in the daemon configuration * @returns #TRUE if username is valid */ dbus_bool_t _dbus_verify_daemon_user (const char *user) { DBusString u; _dbus_string_init_const (&u, user); return _dbus_get_user_id_and_primary_group (&u, NULL, NULL); }
/** * Changes the user and group the bus is running as. * * @param user the user to become * @param error return location for errors * @returns #FALSE on failure */ dbus_bool_t _dbus_change_to_daemon_user (const char *user, DBusError *error) { dbus_uid_t uid; dbus_gid_t gid; DBusString u; _dbus_string_init_const (&u, user); if (!_dbus_get_user_id_and_primary_group (&u, &uid, &gid)) { dbus_set_error (error, DBUS_ERROR_FAILED, "User '%s' does not appear to exist?", user); return FALSE; } /* setgroups() only works if we are a privileged process, * so we don't return error on failure; the only possible * failure is that we don't have perms to do it. * * not sure this is right, maybe if setuid() * is going to work then setgroups() should also work. */ if (setgroups (0, NULL) < 0) _dbus_warn ("Failed to drop supplementary groups: %s\n", _dbus_strerror (errno)); /* Set GID first, or the setuid may remove our permission * to change the GID */ if (setgid (gid) < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to set GID to %lu: %s", gid, _dbus_strerror (errno)); return FALSE; } if (setuid (uid) < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to set UID to %lu: %s", uid, _dbus_strerror (errno)); return FALSE; } return TRUE; }
/** * Gets user ID given username * * @param username the username * @param uid return location for UID * @returns #TRUE if username existed and we got the UID */ dbus_bool_t _dbus_get_user_id (const DBusString *username, dbus_uid_t *uid) { return _dbus_get_user_id_and_primary_group (username, uid, NULL); }
/** * Changes the user and group the bus is running as. * * @param user the user to become * @param error return location for errors * @returns #FALSE on failure */ dbus_bool_t _dbus_change_to_daemon_user (const char *user, DBusError *error) { dbus_uid_t uid; dbus_gid_t gid; DBusString u; _dbus_string_init_const (&u, user); if (!_dbus_get_user_id_and_primary_group (&u, &uid, &gid)) { dbus_set_error (error, DBUS_ERROR_FAILED, "User '%s' does not appear to exist?", user); return FALSE; } /* If we were root */ if (_dbus_geteuid () == 0) { int rc; int have_audit_write; have_audit_write = capng_have_capability (CAPNG_PERMITTED, CAP_AUDIT_WRITE); capng_clear (CAPNG_SELECT_BOTH); /* Only attempt to retain CAP_AUDIT_WRITE if we had it when * starting. See: * https://bugs.freedesktop.org/show_bug.cgi?id=49062#c9 */ if (have_audit_write) capng_update (CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED, CAP_AUDIT_WRITE); rc = capng_change_id (uid, gid, CAPNG_DROP_SUPP_GRP); if (rc) { switch (rc) { default: dbus_set_error (error, DBUS_ERROR_FAILED, "Failed to drop capabilities: %s\n", _dbus_strerror (errno)); break; case -4: dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to set GID to %lu: %s", gid, _dbus_strerror (errno)); break; case -5: _dbus_warn ("Failed to drop supplementary groups: %s\n", _dbus_strerror (errno)); break; case -6: dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to set UID to %lu: %s", uid, _dbus_strerror (errno)); break; case -7: dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to unset keep-capabilities: %s\n", _dbus_strerror (errno)); break; } return FALSE; } } return TRUE; }