diff -NurpP util-vserver-0.30.210/scripts/Makefile-files util-vserver-0.30.210-vlogin/scripts/Makefile-files --- util-vserver-0.30.210/scripts/Makefile-files 2005-04-28 19:45:34.000000000 +0200 +++ util-vserver-0.30.210-vlogin/scripts/Makefile-files 2006-03-04 09:48:30.000000000 +0100 @@ -52,7 +52,8 @@ scripts_pkglib_src_DTA = scripts/functio scripts/vserver.functions \ scripts/vserver.start \ scripts/vserver.stop \ - scripts/vserver.suexec + scripts/vserver.suexec \ + scripts/vserver.login scripts_pkglib_gen_DTA = scripts/util-vserver-vars diff -NurpP util-vserver-0.30.210/scripts/util-vserver-vars.pathsubst util-vserver-0.30.210-vlogin/scripts/util-vserver-vars.pathsubst --- util-vserver-0.30.210/scripts/util-vserver-vars.pathsubst 2006-01-22 13:24:25.000000000 +0100 +++ util-vserver-0.30.210-vlogin/scripts/util-vserver-vars.pathsubst 2006-03-04 09:55:46.000000000 +0100 @@ -72,6 +72,7 @@ _VDU="$__SBINDIR/vdu" _VHASHIFY="$__PKGLIBDIR/vhashify" _VKILL="$__SBINDIR/vkill" _VLIMIT="$__SBINDIR/vlimit" +_VLOGIN="$__SBINDIR/vlogin" _VNAMESPACE="$__SBINDIR/vnamespace" _VPKG="$__PKGLIBDIR/vpkg" _VPROCUNHIDE="$__PKGLIBDIR/vprocunhide" diff -NurpP util-vserver-0.30.210/scripts/vserver util-vserver-0.30.210-vlogin/scripts/vserver --- util-vserver-0.30.210/scripts/vserver 2005-10-28 20:29:00.000000000 +0200 +++ util-vserver-0.30.210-vlogin/scripts/vserver 2006-03-04 09:47:52.000000000 +0100 @@ -101,6 +101,11 @@ function suexec() . $__PKGLIBDIR/vserver.suexec } +function vlogin() +{ + . $__PKGLIBDIR/vserver.login +} + function restart() { "${SELF[@]}" --sync "$vserver" stop @@ -220,7 +225,7 @@ case "$2" in ;; (enter) getEnterShell "$VSERVER_DIR" - suexec root "${ENTER_SHELL[@]}" + vlogin "${ENTER_SHELL[@]}" ;; (running) isVserverRunning "$VSERVER_DIR" diff -NurpP util-vserver-0.30.210/scripts/vserver.login util-vserver-0.30.210-vlogin/scripts/vserver.login --- util-vserver-0.30.210/scripts/vserver.login 1970-01-01 01:00:00.000000000 +0100 +++ util-vserver-0.30.210-vlogin/scripts/vserver.login 2006-03-04 09:46:19.000000000 +0100 @@ -0,0 +1,32 @@ +# $Id: vserver.suexec,v 1.14 2005/07/15 19:01:06 ensc Exp $ --*- sh -*-- + +# Copyright (C) 2003 Enrico Scholz +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +is_stopped= +isVserverRunning "$VSERVER_DIR" S_CONTEXT || is_stopped=1 +test -z "$is_stopped" || { + echo $"'vserver ... suexec' is supported for running vservers only; aborting..." >&2 + exit 1 +} + +generateOptions "$VSERVER_DIR" + +pushd "$VSERVER_DIR"/vdir/ >/dev/null + +${USE_VNAMESPACE:+$_VNAMESPACE --enter "$S_CONTEXT" -- } \ +${_VLOGIN} -n ${S_CONTEXT} -x ${S_CONTEXT} -- "$@" + +popd >/dev/null diff -NurpP util-vserver-0.30.210/src/Makefile-files util-vserver-0.30.210-vlogin/src/Makefile-files --- util-vserver-0.30.210/src/Makefile-files 2006-01-22 12:28:00.000000000 +0100 +++ util-vserver-0.30.210-vlogin/src/Makefile-files 2006-03-04 09:34:00.000000000 +0100 @@ -67,6 +67,7 @@ DIETPROGS += src/chcontext-compat \ src/vcontext \ src/vcopy \ src/vkill \ + src/vlogin \ src/vsched \ src/vshelper-sync \ src/vrsetup \ @@ -141,6 +142,7 @@ sbin_PROGRAMS += src/chbind \ src/vcontext \ src/vlimit \ src/vkill \ + src/vlogin \ src/vnamespace \ src/vrsetup \ src/vsched \ @@ -201,6 +203,10 @@ src_vkill_LDADD = $(VSERVER_LDADDS) src_vkill_LDFLAGS = $(VSERVER_LDFLGS) src_vkill_CPPFLAGS = $(AM_CPPFLAGS) -DLEGACYDIR=\"$(legacydir)\" +src_vlogin_SOURCES = src/vlogin.c +src_vlogin_LDADD = $(VSERVER_LDADDS) +src_vlogin_LDFLAGS = $(VSERVER_LDFLGS) + src_vlimit_SOURCES = src/vlimit.c src_vlimit_LDADD = $(VSERVER_LDADDS) src_vlimit_LDFLAGS = $(VSERVER_LDFLGS) diff -NurpP util-vserver-0.30.210/src/vlogin.c util-vserver-0.30.210-vlogin/src/vlogin.c --- util-vserver-0.30.210/src/vlogin.c 1970-01-01 01:00:00.000000000 +0100 +++ util-vserver-0.30.210-vlogin/src/vlogin.c 2006-03-04 09:56:27.000000000 +0100 @@ -0,0 +1,450 @@ +/*************************************************************************** + * Copyright 2005 by the vserver-utils team * + * See AUTHORS for details * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vserver.h" + +#define GLOBAL_CMDS "hV" + +#define GLOBAL_CMDS_GETOPT \ +case 'h': \ + cmd_help(); \ + break; \ +\ +case 'V': \ + CMD_VERSION(NAME, DESCR); \ + break; \ + +#define DEFAULT_GETOPT \ +default: \ + printf("Try '%s -h' for more information\n", argv[0]); \ + exit(EXIT_USAGE); \ + break; \ + + +#define CMD_VERSION(name, desc) do { \ + printf("%s -- %s\n", name, desc); \ + printf("This program is part of %s\n\n", PACKAGE_STRING); \ + printf("Copyright (c) 2005 The vserver-utils Team\n"); \ + printf("This program is free software; you can redistribute it and/or\n"); \ + printf("modify it under the terms of the GNU General Public License\n"); \ + exit(0); \ +} while(0) + +/* exit, silent exit, perror exit + * + * exit code conventions: + * + * 0 = OK + * 1 = Wrong usage + * 2 = A command failed + * 3 = An opts specific function failed + */ +#define EXIT_USAGE 1 +#define EXIT_COMMAND 2 +#define EXIT_OPTS 3 + +#define EXIT(MSG,RC) { \ + printf(MSG"; try '%s -h' for more information\n", argv[0]); \ + exit(RC); \ +} + +#define SEXIT(MSG,RC) { \ + printf(MSG"\n"); \ + exit(RC); \ +} + +#define PEXIT(MSG,RC) { \ + perror(MSG); \ + exit(RC); \ +} + +#define NAME "vlogin" +#define DESCR "Context Login" + +#define SHORT_OPTS "n:x:" + +struct options { + nid_t nid; + xid_t xid; +}; + +#define TS_RESET 0 +#define TS_RAW 1 + +struct terminal { + int fd; /* terminal file descriptor */ + struct termios term; /* terminal settings */ + struct winsize ws; /* terminal size */ + pid_t pid; /* terminal process id */ + struct termios termo; /* original terminal settings */ + int state; /* terminal state */ +}; + +static struct terminal t; + +static inline +void cmd_help() +{ + printf("Usage: %s * [-- *]\n" + "\n" + "Available options:\n" + " -n Network Context ID\n" + " -x Context ID\n" + "\n", + NAME); + exit(EXIT_SUCCESS); +} + +/* set terminal to raw mode */ +static +int terminal_raw(void) +{ + struct termios buf; + + /* save original terminal settings */ + if (tcgetattr(STDIN_FILENO, &t.termo) == -1) + return -1; + + buf = t.termo; + + /* echo off + ** canonical mode off + ** extended input processing off + ** signal chars off */ + buf.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); + + /* no SIGINT on BREAK + ** CR-to-NL off + ** input parity check off + ** don't strip 8th bit on input + ** output flow control off */ + buf.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); + + /* clear size bits + ** parity checking off */ + buf.c_cflag &= ~(CSIZE | PARENB); + + /* set 8 bits/char */ + buf.c_cflag |= CS8; + + /* output processing off */ + buf.c_oflag &= ~(OPOST); + + /* 1 byte at a time + ** no timer */ + buf.c_cc[VMIN] = 1; + buf.c_cc[VTIME] = 0; + + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &buf) == -1) + return -1; + + t.state = TS_RAW; + + return 0; +} + +/* reset terminal to original state */ +static +int terminal_reset(void) +{ + if (t.state != TS_RAW) + return 0; + + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t.termo) == -1) + return -1; + + t.state = TS_RESET; + + return 0; +} + +/* exit handler */ +static +void terminal_atexit(void) +{ + terminal_reset(); + printf("\n"); /* for cosmetic reasons */ +} + +/* send signal to terminal */ +static +void terminal_kill(int sig) +{ + pid_t pgrp = -1; + + /* try to get process group leader */ + if (ioctl(t.fd, TIOCGPGRP, &pgrp) >= 0 && + pgrp != -1 && + kill(-pgrp, sig) != -1) + return; + + /* fallback using terminal pid */ + kill(-t.pid, sig); +} + +/* redraw the terminal screen */ +static +void terminal_redraw(void) +{ + /* get winsize from stdin */ + ioctl(0, TIOCGWINSZ, &t.ws); + + /* set winsize in terminal */ + ioctl(t.fd, TIOCSWINSZ, &t.ws); + + /* set winsize change signal to terminal */ + terminal_kill(SIGWINCH); +} + +/* copy terminal activity to user */ +static +void terminal_activity(void) +{ + char buf[64]; + int len; + + /* read terminal activity */ + len = read(t.fd, buf, sizeof(buf)); + + /* terminal died or strange things happened */ + if (len == -1) + PEXIT("Failed to read from terminal", EXIT_COMMAND); + + /* get the current terminal settings */ + if (tcgetattr(t.fd, &t.term) == -1) + PEXIT("Failed to get terminal attributes", EXIT_COMMAND); + + /* set the current terminal settings */ + if (tcsetattr(STDIN_FILENO, TCSANOW, &t.term) == -1) + PEXIT("Failed to set terminal attributes", EXIT_COMMAND); + + /* write activity to user */ + if (write(STDOUT_FILENO, buf, len) == -1) + PEXIT("Failed to write to stdout", EXIT_COMMAND); +} + +/* copy user activity to terminal */ +static +void user_activity(void) +{ + char buf[64]; + int len; + + /* read user activity */ + len = read(STDIN_FILENO, buf, sizeof(buf)); + + /* the user process died or strange thins happened */ + if (len == -1) + PEXIT("Failed to read from stdin", EXIT_COMMAND); + + /* write activity to terminal */ + if (write(t.fd, buf, len) == -1) + PEXIT("Failed to write to terminal", EXIT_COMMAND); +} + +/* catch signals */ +static +void signal_handler(int sig) +{ + int status; + + switch(sig) { + /* catch interrupt */ + case SIGINT: + terminal_kill(sig); + break; + + /* terminal died */ + case SIGCHLD: + wait(&status); + exit(status); + break; + + /* window size has changed */ + case SIGWINCH: + signal(SIGWINCH, signal_handler); + terminal_redraw(); + break; + + default: + exit(0); + } + +} + +int main(int argc, char *argv[]) +{ + /* init program data */ + struct options opts = { + .nid = 0, + .xid = 0, + }; + + int c; + + /* parse command line */ + while (1) { + c = getopt(argc, argv, GLOBAL_CMDS SHORT_OPTS); + if (c == -1) break; + + switch (c) { + GLOBAL_CMDS_GETOPT + + case 'n': + opts.nid = (nid_t) atoi(optarg); + break; + + case 'x': + opts.xid = (xid_t) atoi(optarg); + break; + + DEFAULT_GETOPT + } + } + + if (opts.xid == 0) + EXIT("Invalid xid", EXIT_USAGE); + + /* enter context */ + if (opts.nid > 1 && vc_net_migrate(opts.nid) == -1) + PEXIT("Failed to migrate to network context", EXIT_COMMAND); + + if (vc_ctx_migrate(opts.xid) == -1) + PEXIT("Failed to migrate to context", EXIT_COMMAND); + + /* set terminal to raw mode */ + atexit(terminal_atexit); + if (terminal_raw() == -1) + PEXIT("Failed to set terminal to raw mode", EXIT_COMMAND); + + /* fork new pseudo terminal */ + int slave; + + if (openpty(&t.fd, &slave, NULL, NULL, NULL) == -1) + PEXIT("Failed to open new pseudo terminal", EXIT_COMMAND); + + /* chroot to cwd */ + if (chdir(".") == -1) + PEXIT("Failed to chdir to cwd", EXIT_COMMAND); + + if (chroot(".") == -1) + PEXIT("Failed to chroot to cwd", EXIT_COMMAND); + + pid_t pid; + pid = fork(); + + /* setup some signal handlers */ + signal(SIGINT, signal_handler); + signal(SIGCHLD, signal_handler); + signal(SIGWINCH, signal_handler); + + if (pid == -1) + PEXIT("Failed to fork new pseudo terminal", EXIT_COMMAND); + + if (pid == 0) { + /* we don't need the master side of the terminal */ + close(t.fd); + + /* login_tty() stupid dietlibc doesn't have it */ + setsid(); + + if (ioctl(slave, TIOCSCTTY, NULL) == -1) + PEXIT("Failed to set controlling terminal", EXIT_COMMAND); + + dup2(slave, 0); + dup2(slave, 1); + dup2(slave, 2); + + if (slave > 2) + close(slave); + + /* check shell */ + if (argc > optind) { + if (execv(argv[optind], argv+optind) == -1) { + PEXIT("Failed to execute shell", EXIT_COMMAND); + } + } + else { + if (execl("/bin/sh", "/bin/sh", "-l", NULL) == -1) { + PEXIT("Failed to execute default shell", EXIT_COMMAND); + } + } + } + + /* save terminals pid */ + t.pid = pid; + + /* set process title for ps */ + int i, len; + + for (i = 1; i < argc; i++) { + memset(argv[i], '\0', strlen(argv[i])); + } + + len = strlen(argv[0]); + memset(argv[0], '\0', len); + strncpy(argv[0], "VLOGIN", len); + + /* we want a redraw */ + terminal_redraw(); + + /* main loop */ + fd_set rfds; + int n = 0; + + for(;;) { + /* init file descriptors for select */ + FD_ZERO(&rfds); + FD_SET(STDIN_FILENO, &rfds); + FD_SET(t.fd, &rfds); + n = t.fd; + + /* wait for something to happen */ + while (select(n + 1, &rfds, NULL, NULL, NULL) == -1) { + if (errno == EINTR || errno == EAGAIN) continue; + PEXIT("Failed to select", EXIT_COMMAND); + } + + if (FD_ISSET(STDIN_FILENO, &rfds)) + user_activity(); + + if (FD_ISSET(t.fd, &rfds)) + terminal_activity(); + } + + /* never get here */ + return -1; +}