tags 374713 + patch thanks Christian Hammers <[EMAIL PROTECTED]> writes:
> On 2006-06-21 Christian Hammers wrote: >> In the old version dchroot-0.13 it jumped to the home directory as >> specified in /etc/passwd *always*, regardless of the actual cwd of the >> calling user. It did this by executing e.g. "/bin/su - ch -c foobar". >> >> My suggestion would be to change the code to do something like: >> p = popen("/bin/sh -c 'pwd'", "r"); >> target_dir = fgets(p); >> ... chroot() ... >> chdir(target_dir); > > Or maybe add an option that behaves like a "su" as I just found out that the > new schroot does not read ~/.bashrc like both interactive and > non-interactive new bash instances are supposed to. E.g. in my > setup .bashrc tested for /etc/debian_chroot and changed $DISPLAY from > ":0.0" (socket) to "localhost:0.0" (inet) and changed the PS1 prompt for > interactive shells so that I did not mix up my xterms... I have now made most of the changes needed to restore the original dchroot behaviour. I've attached a patch (against upstream SVN). This needs a bit more work, but it's basically done. A "login" shell is only run if you don't run a command. If you run with a command, you get a regular "non-login" shell. Either way, it /should/ source .bashrc in both cases--we just run bash, so it should read it in. This is with the patch applied, BTW. I'll create a test package later on for you to try. Regards, Roger -- Roger Leigh Printing on GNU/Linux? http://gutenprint.sourceforge.net/ Debian GNU/Linux http://www.debian.org/ GPG Public Key: 0x25BFB848. Please sign and encrypt your mail.
Index: schroot/sbuild-session.cc =================================================================== --- schroot/sbuild-session.cc (revision 758) +++ schroot/sbuild-session.cc (working copy) @@ -28,6 +28,8 @@ #include <iostream> #include <memory> +#include <sys/types.h> +#include <sys/stat.h> #include <unistd.h> #include <syslog.h> @@ -66,16 +68,26 @@ emap(session::USER_SWITCH, N_("User switching is not permitted")) }; -} + /** + * Get the current working directory. If it can't be found, fall + * back to root. + * + * @returns the current working directory. + */ + std::string + getcwd () + { + std::string cwd; -template<> -std::map<session::error_code,const char *> -custom_error<session::error_code>::error_strings -(init_errors, - init_errors + (sizeof(init_errors) / sizeof(init_errors[0]))); + char *raw_cwd = ::getcwd (NULL, 0); + if (raw_cwd) + cwd = raw_cwd; + else + cwd = "/"; + free(raw_cwd); -namespace -{ + return cwd; + } /** * Check group membership. @@ -157,6 +169,12 @@ } +template<> +std::map<session::error_code,const char *> +custom_error<session::error_code>::error_strings +(init_errors, + init_errors + (sizeof(init_errors) / sizeof(init_errors[0]))); + session::session (std::string const& service, config_ptr& config, operation operation, @@ -169,7 +187,8 @@ session_operation(operation), session_id(), force(false), - saved_signals() + saved_signals(), + cwd(getcwd()) { } @@ -372,6 +391,7 @@ log_debug(DEBUG_NOTICE) << format("Running session in %1% chroot:") % *cur << endl; + const chroot::ptr ch = this->config->find_alias(*cur); if (!ch) // Should never happen, but cater for it anyway. { @@ -500,7 +520,169 @@ } } +string_list +session::get_login_directories () const +{ + string_list ret; + + // Set current working directory. + ret.push_back(this->cwd); + + // Set $HOME. + environment env = get_pam_environment(); + std::string home; + if (env.get("HOME", home) && + std::find(ret.begin(), ret.end(), home) == ret.end()) + ret.push_back(home); + + // Set passwd home. + if (std::find(ret.begin(), ret.end(), get_home()) == ret.end()) + ret.push_back(get_home()); + + // Final fallback to root. + if (std::find(ret.begin(), ret.end(), "/") == ret.end()) + ret.push_back("/"); + + return ret; +} + +string_list +session::get_command_directories () const +{ + string_list ret; + + // Set current working directory. + ret.push_back(this->cwd); + + return ret; +} + +std::string +session::get_shell () const +{ + assert (!auth::get_shell().empty()); + std::string shell = auth::get_shell(); + + struct stat statbuf; + if (stat(shell.c_str(), &statbuf) < 0) + { + if (shell != "/bin/sh") + { + log_warning() << format(_("%1%: Shell not available: %2%")) + % shell % strerror(errno) << endl; + shell = "/bin/sh"; + log_warning() << format(_("Falling back to %1%")) + % shell << endl; + } + } + + return shell; +} + void +session::get_command (sbuild::chroot::ptr& session_chroot, + std::string& file, + string_list& command) const +{ + /* Run login shell */ + if (command.empty() || + command[0].empty()) // No command + { + command.clear(); + + std::string shell = get_shell(); + file = shell; + + if (get_environment().empty() && + session_chroot->get_command_prefix().empty()) + // Not keeping environment and can setup argv correctly; login shell + { + std::string shellbase = basename(shell, '/'); + std::string loginshell = "-" + shellbase; + command.push_back(loginshell); + + log_debug(DEBUG_NOTICE) + << format("Running login shell: %1%") % shell << endl; + syslog(LOG_USER|LOG_NOTICE, + "[%s chroot] (%s->%s) Running login shell: \"%s\"", + session_chroot->get_name().c_str(), + get_ruser().c_str(), get_user().c_str(), + shell.c_str()); + } + else + { + command.push_back(shell); + log_debug(DEBUG_NOTICE) + << format("Running shell: %1%") % shell << endl; + syslog(LOG_USER|LOG_NOTICE, + "[%s chroot] (%s->%s) Running shell: \"%s\"", + session_chroot->get_name().c_str(), + get_ruser().c_str(), get_user().c_str(), + shell.c_str()); + } + + if (get_verbosity() != auth::VERBOSITY_QUIET) + { + std::string format_string; + if (get_ruid() == get_uid()) + { + if (get_environment().empty() && + session_chroot->get_command_prefix().empty()) + format_string = _("[%1% chroot] Running login shell: \"%4%\""); + else + format_string = _("[%1% chroot] Running shell: \"%4%\""); + } + else + { + if (get_environment().empty() && + session_chroot->get_command_prefix().empty()) + format_string = _("[%1% chroot] (%2%->%3%) Running login shell: \"%4%\""); + else + format_string = _("[%1% chroot] (%2%->%3%) Running shell: \"%4%\""); + } + + format fmt(format_string); + fmt % session_chroot->get_name() + % get_ruser() % get_user() + % shell; + log_info() << fmt << endl; + } + } + else + { + /* Search for program in path. */ + environment env = get_pam_environment(); + std::string path; + if (!env.get("PATH", path)) + path.clear(); + + file = find_program_in_path(command[0], path, ""); + if (file.empty()) + file = command[0]; + std::string commandstring = string_list_to_string(command, " "); + log_debug(DEBUG_NOTICE) + << format("Running command: %1%") % commandstring << endl; + syslog(LOG_USER|LOG_NOTICE, "[%s chroot] (%s->%s) Running command: \"%s\"", + session_chroot->get_name().c_str(), get_ruser().c_str(), get_user().c_str(), commandstring.c_str()); + + if (get_verbosity() != auth::VERBOSITY_QUIET) + { + std::string format_string; + if (get_ruid() == get_uid()) + format_string = _("[%1% chroot] Running command: \"%4%\""); + else + format_string = (_("[%1% chroot] (%2%->%3%) Running command: \"%4%\"")); + + format fmt(format_string); + fmt % session_chroot->get_name() + % get_ruser() % get_user() + % commandstring; + log_info() << fmt << endl; + } + } +} + +void session::setup_chroot (sbuild::chroot::ptr& session_chroot, sbuild::chroot::setup_type setup_type) { @@ -689,16 +871,10 @@ assert(!get_shell().empty()); assert(auth::pam != NULL); // PAM must be initialised + // Store before chroot call. + this->cwd = getcwd(); + std::string location(session_chroot->get_path()); - std::string cwd; - { - char *raw_cwd = getcwd (NULL, 0); - if (raw_cwd) - cwd = raw_cwd; - else - cwd = "/"; - free(raw_cwd); - } /* Child errors result in immediate exit(). Errors are not propagated back via an exception, because there is no longer any @@ -769,130 +945,51 @@ } std::string file; + string_list command(auth::get_command()); - string_list command(get_command()); + string_list dlist; + if (command.empty() || + command[0].empty()) // No command + dlist = get_login_directories(); + else + dlist = get_command_directories(); + log_debug(DEBUG_NOTICE) + << format("Directory fallbacks: %1%") % string_list_to_string(dlist, ", ") << endl; - /* chdir to current directory */ - if (chdir (cwd.c_str())) + /* Attempt to chdir to current directory. */ + bool dir_changed = false; + for (string_list::const_iterator dpos = dlist.begin(); + dpos != dlist.end(); + ++dpos) { - /* Fall back to home directory, but only for a login shell, - since for a command we require deterministic behaviour. */ - if (command.empty() || - command[0].empty()) // No command + if (chdir ((*dpos).c_str()) < 0) { - log_warning() << format(_("Could not chdir to '%1%': %2%")) - % cwd % strerror(errno) - << endl; - - if (chdir (get_home().c_str())) - log_warning() << format(_("Falling back to '%1%'")) - % "/" - << endl; - else - log_warning() << format(_("Falling back to home directory '%1%'")) - % get_home() - << endl; + ((dpos + 1 == dlist.end()) ? log_error() : log_warning()) + << format(_("Could not chdir to '%1%': %2%")) + % *dpos % strerror(errno) + << endl; } else { - log_error() << format(_("Could not chdir to '%1%': %2%")) - % cwd % strerror(errno) - << endl; - exit (EXIT_FAILURE); + if (dpos != dlist.begin()) + log_warning() << format(_("Falling back to '%1%'")) + % *dpos + << endl; + dir_changed = true; + break; } } + if (dir_changed == false) + exit (EXIT_FAILURE); // Warning already logged. + + /* Fix up the command for exec. */ + get_command(session_chroot, file, command); + /* Set up environment */ environment env = get_pam_environment(); - log_debug(DEBUG_INFO) - << "Set environment:\n" << env; + log_debug(DEBUG_INFO) << "Set environment:\n" << env; - /* Run login shell */ - if (command.empty() || - command[0].empty()) // No command - { - assert (!get_shell().empty()); - - file = get_shell(); - if (get_environment().empty() && - session_chroot->get_command_prefix().empty()) - // Not keeping environment and can setup argv correctly; login shell - { - std::string shellbase = basename(get_shell(), '/'); - std::string loginshell = "-" + shellbase; - command.push_back(loginshell); - log_debug(DEBUG_INFO) - << format("Login shell: %1%") % command[0] << endl; - } - else - { - command.push_back(get_shell()); - } - - if (get_environment().empty() && - session_chroot->get_command_prefix().empty()) - { - log_debug(DEBUG_NOTICE) - << format("Running login shell: %1%") % get_shell() << endl; - syslog(LOG_USER|LOG_NOTICE, "[%s chroot] (%s->%s) Running login shell: \"%s\"", - session_chroot->get_name().c_str(), get_ruser().c_str(), get_user().c_str(), get_shell().c_str()); - } - else - { - log_debug(DEBUG_NOTICE) - << format("Running shell: %1%") % get_shell() << endl; - syslog(LOG_USER|LOG_NOTICE, "[%s chroot] (%s->%s) Running shell: \"%s\"", - session_chroot->get_name().c_str(), get_ruser().c_str(), get_user().c_str(), get_shell().c_str()); - } - - if (get_verbosity() != auth::VERBOSITY_QUIET) - { - if (get_ruid() == get_uid()) - log_info() - << format((get_environment().empty() && - session_chroot->get_command_prefix().empty() ? - _("[%1% chroot] Running login shell: \"%2%\"") : - _("[%1% chroot] Running shell: \"%2%\""))) - % session_chroot->get_name() % get_shell() - << endl; - else - log_info() - << format((get_environment().empty() && - session_chroot->get_command_prefix().empty() ? - _("[%1% chroot] (%2%->%3%) Running login shell: \"%4%\"") : - _("[%1% chroot] (%2%->%3%) Running shell: \"%4%\""))) - % session_chroot->get_name() - % get_ruser() % get_user() - % get_shell() - << endl; - } - } - else - { - /* Search for program in path. */ - file = find_program_in_path(command[0], getenv("PATH"), ""); - if (file.empty()) - file = command[0]; - std::string commandstring = string_list_to_string(command, " "); - log_debug(DEBUG_NOTICE) - << format("Running command: %1%") % commandstring << endl; - syslog(LOG_USER|LOG_NOTICE, "[%s chroot] (%s->%s) Running command: \"%s\"", - session_chroot->get_name().c_str(), get_ruser().c_str(), get_user().c_str(), commandstring.c_str()); - if (get_verbosity() != auth::VERBOSITY_QUIET) - { - if (get_ruid() == get_uid()) - log_info() << format(_("[%1% chroot] Running command: \"%2%\"")) - % session_chroot->get_name() % commandstring - << endl; - else - log_info() << format(_("[%1% chroot] (%2%->%3%) Running command: \"%4%\"")) - % session_chroot->get_name() - % get_ruser() % get_user() - % commandstring - << endl; - } - } - // The user's command does not use our syslog fd. closelog(); @@ -993,6 +1090,7 @@ else if (pid == 0) { #ifdef SBUILD_DEBUG + sbuild::debug_level = sbuild::DEBUG_NOTICE; while (child_wait) ; #endif Index: schroot/sbuild-session.h =================================================================== --- schroot/sbuild-session.h (revision 758) +++ schroot/sbuild-session.h (working copy) @@ -202,7 +202,7 @@ get_chroot_auth_status (auth::status status, chroot::ptr const& chroot) const; - public: + public: /** * Check if authentication is required, taking users, groups, * root-users and root-groups membership of all chroots specified @@ -211,6 +211,7 @@ virtual sbuild::auth::status get_auth_status () const; + protected: /** * Run a session. If a command has been specified, this will be * run in each of the specified chroots. If no command has been @@ -221,6 +222,47 @@ virtual void run_impl (); + /** + * Get a list of directories to change to when running a login + * shell. Multiple directories are used as fallbacks. + * + * @returns a list of directories + */ + virtual string_list + get_login_directories () const; + + /** + * Get a list of directories to change to when running a command + * Multiple directories are used as fallbacks. + * + * @returns a list of directories + */ + virtual string_list + get_command_directories () const; + + /** + * Get the shell to run. This finds a suitable shell to run in + * the chroot, falling back to /bin/sh if necessary. Note that it + * assumes it is inside the chroot when called. + * + * @returns the shell. + */ + virtual std::string + get_shell () const; + + /** + * Get the command to run. + * + * @param session_chroot the chroot to setup. This must be + * present in the chroot list and the chroot configuration object. + * @param file the filename to pass to execve(2). + * @param command the argv to pass to execve(2). + */ + virtual void + get_command (chroot::ptr& session_chroot, + std::string& file, + string_list& command) const; + private: /** * execve wrapper. Run the command specified by file (an absolute @@ -317,6 +359,10 @@ bool force; /// Signals saved while sighup handler is set. struct sigaction saved_signals; + + protected: + /// Current working directory. + std::string cwd; }; } Index: schroot/schroot-options.cc =================================================================== --- schroot/schroot-options.cc (revision 759) +++ schroot/schroot-options.cc (working copy) @@ -141,6 +141,7 @@ hidden.add_options() ("command", opt::value<sbuild::string_list>(&this->command), _("Command to run")); + opt::positional_options_description pos; pos.add("command", -1); @@ -243,6 +244,12 @@ } } + // dchroot and dchroot-dsa only allow one command. + if ((this->compat == COMPAT_DCHROOT || + this->compat == COMPAT_DCHROOT_DSA) && + this->command.size() > 1) + throw opt::validation_error(_("Only one command may be specified")); + if (this->quiet && this->verbose) { sbuild::log_warning() Index: schroot/dchroot-session.cc =================================================================== --- schroot/dchroot-session.cc (revision 758) +++ schroot/dchroot-session.cc (working copy) @@ -41,12 +41,13 @@ using std::cout; using std::endl; using boost::format; +using sbuild::string_list; using namespace dchroot; -session::session (std::string const& service, - config_ptr& config, - operation operation, - sbuild::string_list const& chroots): +session::session (std::string const& service, + config_ptr& config, + operation operation, + string_list const& chroots): sbuild::session(service, config, operation, chroots) { } @@ -67,8 +68,8 @@ restrictions. This only applies if not switching users (dchroot does not support user switching) */ - sbuild::string_list const& users = chroot->get_users(); - sbuild::string_list const& groups = chroot->get_groups(); + string_list const& users = chroot->get_users(); + string_list const& groups = chroot->get_groups(); if (this->get_ruid() == this->get_uid() && users.empty() && groups.empty()) @@ -95,7 +96,137 @@ sbuild::session::run_impl(); } +string_list +session::get_login_directories () const +{ + string_list ret; +#ifndef SBUILD_DCHROOT_DSA_COMPAT + // Set current working directory only if preserving environment. + // Only change to home if not preserving the environment. + if (!get_environment().empty()) + ret.push_back(this->sbuild::session::cwd); + else + ret.push_back(get_home()); +#else + ret.push_back(get_home()); +#endif + + // Final fallback to root. + if (std::find(ret.begin(), ret.end(), "/") == ret.end()) + ret.push_back("/"); + + return ret; +} + +string_list +session::get_command_directories () const +{ + // dchroot does not treat logins differently from commands with + // respect to the cwd inside the chroot. + return get_login_directories(); +} + +void +session::get_command (sbuild::chroot::ptr& session_chroot, + std::string& file, + string_list& command) const +{ + /* Run login shell */ + if (command.empty() || + command[0].empty()) // No command + { + command.clear(); + + std::string shell = get_shell(); + file = shell; + + if (get_environment().empty() && + session_chroot->get_command_prefix().empty()) + // Not keeping environment and can setup argv correctly; login shell + { + std::string shellbase = sbuild::basename(shell, '/'); + std::string loginshell = "-" + shellbase; + command.push_back(loginshell); + + sbuild::log_debug(sbuild::DEBUG_NOTICE) + << format("Running login shell: %1%") % shell << endl; + syslog(LOG_USER|LOG_NOTICE, + "[%s chroot] (%s->%s) Running login shell: \"%s\"", + session_chroot->get_name().c_str(), + get_ruser().c_str(), get_user().c_str(), + shell.c_str()); + } + else + { + command.push_back(shell); + sbuild::log_debug(sbuild::DEBUG_NOTICE) + << format("Running shell: %1%") % shell << endl; + syslog(LOG_USER|LOG_NOTICE, + "[%s chroot] (%s->%s) Running shell: \"%s\"", + session_chroot->get_name().c_str(), + get_ruser().c_str(), get_user().c_str(), + shell.c_str()); + } + + if (get_verbosity() != auth::VERBOSITY_QUIET) + { + std::string format_string; + if (get_ruid() == get_uid()) + { + if (get_environment().empty() && + session_chroot->get_command_prefix().empty()) + format_string = _("[%1% chroot] Running login shell: \"%4%\""); + else + format_string = _("[%1% chroot] Running shell: \"%4%\""); + } + else + { + if (get_environment().empty() && + session_chroot->get_command_prefix().empty()) + format_string = _("[%1% chroot] (%2%->%3%) Running login shell: \"%4%\""); + else + format_string = _("[%1% chroot] (%2%->%3%) Running shell: \"%4%\""); + } + + format fmt(format_string); + fmt % session_chroot->get_name() + % get_ruser() % get_user() + % shell; + sbuild::log_info() << fmt << endl; + } + } + else + { + std::string programstring = command[0]; +#ifdef SBUILD_DCHROOT_DSA_COMPAT + file = programstring; +#else + command.clear(); + command.push_back(get_shell()); + command.push_back("-c"); + command.push_back(programstring); +#endif + + std::string commandstring = sbuild::string_list_to_string(command, " "); + sbuild::log_debug(sbuild::DEBUG_NOTICE) + << format("Running command: %1%") % commandstring << endl; + syslog(LOG_USER|LOG_NOTICE, "[%s chroot] (%s->%s) Running command: \"%s\"", + session_chroot->get_name().c_str(), get_ruser().c_str(), get_user().c_str(), commandstring.c_str()); + + if (get_verbosity() != auth::VERBOSITY_QUIET) + { + std::string format_string; + format_string = (_("[%1% chroot] Running command: \"%2%\"")); + + format fmt(format_string); + fmt % session_chroot->get_name() + % programstring; + sbuild::log_info() << fmt << endl; + } + } +} + /* * Local Variables: * mode:C++ Index: schroot/dchroot-session.h =================================================================== --- schroot/dchroot-session.h (revision 758) +++ schroot/dchroot-session.h (working copy) @@ -66,6 +66,17 @@ virtual void run_impl (); + + virtual sbuild::string_list + get_login_directories () const; + + virtual sbuild::string_list + get_command_directories () const; + + virtual void + get_command (sbuild::chroot::ptr& session_chroot, + std::string& file, + sbuild::string_list& command) const; }; } Index: ChangeLog =================================================================== --- ChangeLog (revision 760) +++ ChangeLog (working copy) @@ -1,3 +1,44 @@ +2006-06-22 Roger Leigh <[EMAIL PROTECTED]> + + * schroot/schroot-options.cc: dchroot and dchroot-dsa only permit + a single command option. + + * schroot/dchroot-session.cc + (get_login_directories): New virtual method. For dchroot, use the + home directory and then / if not preserving the environment, + otherwise use the current working directory and /. For + dchroot-dsa, always use the home directory and then /. + (get_command_directories): New virtual method. This simply wraps + get_login_directories; dchroot and dchroot-dsa do not distinguish + between these two use cases. + (get_command): When running a login shell, this behaves similarly + to sbuild::session::get_command. When running a command, dchroot + runs "sh -c command", and dchroot-dsa runs "command". + + * schroot/sbuild-session.cc + (getcwd): New utility function, split out from run_child. + (get_login_directories): New protected virtual method. Get a list + of directories to use (including fallbacks) when running a login + shell. Use the current working directory, $HOME, passwd pw_dir + and / in that order. + (get_command_directories): New protected virtual method. Get a + list of directories to use (including fallbacks) when running a + command. This is currently only the current working directory; + there are no fallbacks. + (get_shell): New protected virtual method. Get the program to run + as a shell, falling back to /bin/sh if unavailable. + (get_command): New protected virtual method. Get the parameters + for calling exec with (file and argv). + (run_child): Use the new functions and methods getcwd, + get_login_directories, get_command_directories, get_shell and + get_command. Handle directory fallbacks when changing directory + inside the chroot. + (run_chroot): If debugging is enabled, automatically set the debug + level to DEBUG_NOTICE. + + * schroot/sbuild-session.h (sbuild): New protected member cwd, to + hold the current directory before entering the chroot. + 2006-06-21 Roger Leigh <[EMAIL PROTECTED]> * schroot/sbuild-chroot-file.h: Remove dangerous TODO item.
pgpQNwZk4jZj7.pgp
Description: PGP signature