diff --git a/ChangeLog b/ChangeLog index 8605eac..b9bfc8c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2009-03-30 Markus Gutschke + + * Added initial revision of demo application + +2009-03-29 Markus Gutschke + + * Added support for chained SSL certificates + 2009-03-23 Markus Gutschke * Added an INSTALL.Debian file with Debian-specific instructions on diff --git a/Makefile.am b/Makefile.am index 5ec35d2..1f7ca61 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,9 +1,10 @@ AM_CPPFLAGS = -AM_CFLAGS = -g -std=gnu99 -Wall -Werror -Os +AM_CFLAGS = -g -std=gnu99 -Wall AM_LDFLAGS = -g noinst_LTLIBRARIES = libhttp.la \ liblogging.la +noinst_DATA = $(top_srcdir)/demo/demo.js bin_PROGRAMS = shellinaboxd man_MANS = shellinaboxd.1 noinst_HEADERS = libhttp/http.h @@ -15,7 +16,14 @@ dist_doc_DATA = AUTHORS \ NEWS \ README \ TODO -EXTRA_DIST = shellinabox/shellinaboxd.man.in \ +EXTRA_DIST = demo/beep.wav \ + demo/favicon.ico \ + demo/demo.html \ + demo/demo.js \ + demo/demo.jspp \ + demo/styles.css \ + demo/vt100.js \ + shellinabox/shellinaboxd.man.in \ shellinabox/shell_in_a_box.js \ shellinabox/vt100.js \ debian/README \ diff --git a/Makefile.in b/Makefile.in index 5ab9484..770d552 100644 --- a/Makefile.in +++ b/Makefile.in @@ -110,7 +110,7 @@ am__vpath_adj = case $$p in \ esac; am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; dist_docDATA_INSTALL = $(INSTALL_DATA) -DATA = $(dist_doc_DATA) +DATA = $(dist_doc_DATA) $(noinst_DATA) HEADERS = $(noinst_HEADERS) ETAGS = etags CTAGS = ctags @@ -237,11 +237,12 @@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -AM_CFLAGS = -g -std=gnu99 -Wall -Werror -Os +AM_CFLAGS = -g -std=gnu99 -Wall AM_LDFLAGS = -g noinst_LTLIBRARIES = libhttp.la \ liblogging.la +noinst_DATA = $(top_srcdir)/demo/demo.js man_MANS = shellinaboxd.1 noinst_HEADERS = libhttp/http.h dist_doc_DATA = AUTHORS \ @@ -253,7 +254,14 @@ dist_doc_DATA = AUTHORS \ README \ TODO -EXTRA_DIST = shellinabox/shellinaboxd.man.in \ +EXTRA_DIST = demo/beep.wav \ + demo/favicon.ico \ + demo/demo.html \ + demo/demo.js \ + demo/demo.jspp \ + demo/styles.css \ + demo/vt100.js \ + shellinabox/shellinaboxd.man.in \ shellinabox/shell_in_a_box.js \ shellinabox/vt100.js \ debian/README \ diff --git a/commit b/commit index 6741a2a..821cd39 100755 --- a/commit +++ b/commit @@ -34,7 +34,9 @@ yes_no() { test -r configure.ac svn update +{ rev=$(($(svn info | sed -e 's/^Revision: \(.*\)/\1/;t1;d;:1;q')+1)) +} 2>/dev/null prj="$(sed -e 's/^AC_INIT(\([^,]*\),.*/\1/;t1;d;:1;q' configure.ac)" ver="$(sed -e 's/^AC_INIT([^,]*, *\([^,]*\),.*/\1/;t1;d;:1;q' configure.ac)" sed -ie 's/^\(VCS_REVISION=\).*/\1'"${rev}"'/' configure.ac @@ -43,7 +45,7 @@ make all distcheck rm -f "${prj}-${ver}" && tar zfx "${prj}-${ver}.tar.gz" && cd "${prj}-${ver}" && - { fakeroot dpkg-buildpackage || :; } && + fakeroot dpkg-buildpackage -us -uc && cd .. && rm -f $(ls "${prj}_${ver}-"*.* | egrep -v '.deb$') ) || : svn diff $(svn st | diff --git a/config.h b/config.h index 8be1646..3a5fcb8 100644 --- a/config.h +++ b/config.h @@ -95,7 +95,7 @@ #define STDC_HEADERS 1 /* Most recent revision number in the version control system */ -#define VCS_REVISION "91" +#define VCS_REVISION "93" /* Version number of package */ #define VERSION "2.5" diff --git a/configure b/configure index 9bf31b7..79330f6 100755 --- a/configure +++ b/configure @@ -754,6 +754,7 @@ PACKAGE_VERSION='2.5' PACKAGE_STRING='shellinabox 2.5' PACKAGE_BUGREPORT='markus@shellinabox.com' +ac_c_werror_flag= # Factoring default headers for most tests. ac_includes_default="\ #include @@ -2055,7 +2056,7 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $ ac_compiler_gnu=$ac_cv_c_compiler_gnu -VCS_REVISION=91 +VCS_REVISION=93 cat >>confdefs.h <<_ACEOF @@ -2063,6 +2064,7 @@ cat >>confdefs.h <<_ACEOF _ACEOF +CFLAGS="${CFLAGS:--Os}" am__api_version='1.10' ac_aux_dir= @@ -3658,6 +3660,8 @@ else fi + +ac_c_werror_flag=yes # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: @@ -4531,7 +4535,7 @@ ia64-*-hpux*) ;; *-*-irix6*) # Find out which ABI we are using. - echo '#line 4534 "configure"' > conftest.$ac_ext + echo '#line 4538 "configure"' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -7616,11 +7620,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7619: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7623: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:7623: \$? = $ac_status" >&5 + echo "$as_me:7627: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -7906,11 +7910,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7909: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7913: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:7913: \$? = $ac_status" >&5 + echo "$as_me:7917: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -8010,11 +8014,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:8013: $lt_compile\"" >&5) + (eval echo "\"\$as_me:8017: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:8017: \$? = $ac_status" >&5 + echo "$as_me:8021: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -10423,7 +10427,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < conftest.$ac_ext <&5) + (eval echo "\"\$as_me:12939: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:12939: \$? = $ac_status" >&5 + echo "$as_me:12943: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -13036,11 +13040,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:13039: $lt_compile\"" >&5) + (eval echo "\"\$as_me:13043: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:13043: \$? = $ac_status" >&5 + echo "$as_me:13047: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -14634,11 +14638,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:14637: $lt_compile\"" >&5) + (eval echo "\"\$as_me:14641: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:14641: \$? = $ac_status" >&5 + echo "$as_me:14645: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -14738,11 +14742,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:14741: $lt_compile\"" >&5) + (eval echo "\"\$as_me:14745: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:14745: \$? = $ac_status" >&5 + echo "$as_me:14749: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -16966,11 +16970,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:16969: $lt_compile\"" >&5) + (eval echo "\"\$as_me:16973: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:16973: \$? = $ac_status" >&5 + echo "$as_me:16977: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -17256,11 +17260,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:17259: $lt_compile\"" >&5) + (eval echo "\"\$as_me:17263: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:17263: \$? = $ac_status" >&5 + echo "$as_me:17267: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -17360,11 +17364,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:17363: $lt_compile\"" >&5) + (eval echo "\"\$as_me:17367: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:17367: \$? = $ac_status" >&5 + echo "$as_me:17371: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -20565,7 +20569,7 @@ cat >>conftest.$ac_ext <<_ACEOF int main () { -ptsname_r(0, 0, 0); +char buf[10]; ptsname_r(0, buf, sizeof(buf)); ; return 0; } diff --git a/configure.ac b/configure.ac index 12a321f..25688dc 100644 --- a/configure.ac +++ b/configure.ac @@ -2,15 +2,17 @@ AC_PREREQ(2.57) dnl This is the one location where the authoritative version number is stored AC_INIT(shellinabox, 2.5, markus@shellinabox.com) -VCS_REVISION=91 +VCS_REVISION=93 AC_SUBST(VCS_REVISION) AC_DEFINE_UNQUOTED(VCS_REVISION, "${VCS_REVISION}", [Most recent revision number in the version control system]) dnl Set up autoconf/automake for building C libraries and binaries with GCC +CFLAGS="${CFLAGS:--Os}" AM_INIT_AUTOMAKE AM_CONFIG_HEADER(config.h) AC_PROG_CC +AC_LANG_WERROR AC_PROG_INSTALL AC_PROG_LIBTOOL AC_SUBST(LIBTOOL_DEPS) @@ -34,7 +36,7 @@ AC_TRY_LINK([#ifndef _XOPEN_SOURCE #define _GNU_SOURCE #endif #include ], - [ptsname_r(0, 0, 0);], + [char buf[10]; ptsname_r(0, buf, sizeof(buf));], [AC_DEFINE(HAVE_PTSNAME_R, 1, Define to 1 if you have a re-entrant version of ptsname)]) diff --git a/demo/beep.wav b/demo/beep.wav new file mode 120000 index 0000000..63a996d --- /dev/null +++ b/demo/beep.wav @@ -0,0 +1 @@ +../shellinabox/beep.wav \ No newline at end of file diff --git a/demo/demo.html b/demo/demo.html new file mode 100644 index 0000000..b726bfe --- /dev/null +++ b/demo/demo.html @@ -0,0 +1,79 @@ + + + + + + Shell In A Box + + + + + + + + + diff --git a/demo/demo.js b/demo/demo.js new file mode 100644 index 0000000..8f2a89f --- /dev/null +++ b/demo/demo.js @@ -0,0 +1,371 @@ +// Demo.js -- Demonstrate some of the features of ShellInABox +// Copyright (C) 2008-2009 Markus Gutschke +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// 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., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// In addition to these license terms, the author grants the following +// additional rights: +// +// If you modify this program, or any covered work, by linking or +// combining it with the OpenSSL project's OpenSSL library (or a +// modified version of that library), containing parts covered by the +// terms of the OpenSSL or SSLeay licenses, the author +// grants you additional permission to convey the resulting work. +// Corresponding Source for a non-source form of such a combination +// shall include the source code for the parts of OpenSSL used as well +// as that of the covered work. +// +// You may at your option choose to remove this additional permission from +// the work, or from any part of it. +// +// It is possible to build this program in a way that it loads OpenSSL +// libraries at run-time. If doing so, the following notices are required +// by the OpenSSL and SSLeay licenses: +// +// This product includes software developed by the OpenSSL Project +// for use in the OpenSSL Toolkit. (http://www.openssl.org/) +// +// This product includes cryptographic software written by Eric Young +// (eay@cryptsoft.com) +// +// +// The most up-to-date version of this program is always available from +// http://shellinabox.com +// +// +// Notes: +// +// The author believes that for the purposes of this license, you meet the +// requirements for publishing the source code, if your web server publishes +// the source in unmodified form (i.e. with licensing information, comments, +// formatting, and identifier names intact). If there are technical reasons +// that require you to make changes to the source code when serving the +// JavaScript (e.g to remove pre-processor directives from the source), these +// changes should be done in a reversible fashion. +// +// The author does not consider websites that reference this script in +// unmodified form, and web servers that serve this script in unmodified form +// to be derived works. As such, they are believed to be outside of the +// scope of this license and not subject to the rights or restrictions of the +// GNU General Public License. +// +// If in doubt, consult a legal professional familiar with the laws that +// apply in your country. + +// #define STATE_IDLE 0 +// #define STATE_INIT 1 +// #define STATE_PROMPT 2 +// #define STATE_READLINE 3 +// #define STATE_COMMAND 4 +// #define STATE_EVAL 5 +// #define STATE_RUN 6 +// #define STATE_EXEC 7 + +function extend(subClass, baseClass) { + function inheritance() { } + inheritance.prototype = baseClass.prototype; + subClass.prototype = new inheritance(); + subClass.prototype.constructor = subClass; + subClass.prototype.superClass = baseClass.prototype; +}; + +function Demo(container) { + this.superClass.constructor.call(this, container); + this.gotoState(1 /* STATE_INIT */); +}; +extend(Demo, VT100); + +Demo.prototype.keysPressed = function(ch) { + this.keys += ch; + this.gotoState(this.state); +}; + +Demo.prototype.gotoState = function(state, tmo) { + this.state = state; + if (!this.timer || tmo) { + if (!tmo) { + tmo = 1; + } + this.timer = setTimeout(function(demo) { + return function() { + demo.demo(); + }; + }(this), tmo); + } +}; + +Demo.prototype.demo = function() { + var done = false; + while (!done) { + var state = this.state; + this.state = 0 /* STATE_IDLE */; + switch (state) { + case 1 /* STATE_INIT */: + this.doInit(); + break; + case 2 /* STATE_PROMPT */: + this.doPrompt(); + break; + case 3 /* STATE_READLINE */: + this.doReadLine(); + if (this.state == 3 /* STATE_READLINE */) { + done = true; + } + break; + case 4 /* STATE_COMMAND */: + this.doCommand(); + break; + case 5 /* STATE_EVAL */: + this.doEval(); + break; + case 6 /* STATE_RUN */: + this.doRun(); + break; + case 7 /* STATE_EXEC */: + if (this.doExec()) { + return; + } + break; + case 0 /* STATE_IDLE */: + default: + done = true; + break; + } + } + this.timer = undefined; +}; + +Demo.prototype.error = function(msg) { + if (msg == undefined) { + msg = 'Syntax Error'; + } + this.vt100('\u0007? ' + msg + '\r\n'); + this.gotoState(2 /* STATE_PROMPT */); +}; + +Demo.prototype.doInit = function() { + this.program = new Array(); + this.vt100( + '\u001Bc\u001B[34;4m' + + 'ShellInABox Demo Script\u001B[24;31m\r\n' + + '\r\n' + + 'Copyright 2009 by Markus Gutschke \u001B[0m\r\n' + + '\r\n' + + '\r\n' + + 'This script simulates a minimal BASIC interpreter, allowing you to\r\n' + + 'experiment with the JavaScript terminal emulator that is part of\r\n' + + 'the ShellInABox project.\r\n' + + '\r\n' + + 'Type HELP for a list of commands.\r\n' + + '\r\n'); + this.gotoState(2 /* STATE_PROMPT */); +}; + +Demo.prototype.doPrompt = function() { + this.keys = ''; + this.line = ''; + this.currentLineIndex = -1; + this.vt100('> '); + this.gotoState(3 /* STATE_READLINE */); +}; + +Demo.prototype.doReadLine = function() { + this.gotoState(3 /* STATE_READLINE */); + var keys = this.keys; + this.keys = ''; + for (var i = 0; i < keys.length; i++) { + var ch = keys.charAt(i); + if (ch >= ' ' && ch < '\u007F' || ch > '\u00A0') { + this.line += ch; + this.vt100(ch); + } else if (ch == '\r' || ch == '\n') { + this.vt100('\r\n'); + this.gotoState(4 /* STATE_COMMAND */); + } else if (ch == '\u0008' || ch == '\u007F') { + if (this.line.length > 0) { + this.line = this.line.substr(0, this.line.length - 1); + if (this.cursorX == 0) { + var x = this.terminalWidth - 1; + var y = this.cursorY - 1; + this.gotoXY(x, y); + this.vt100(' '); + this.gotoXY(x, y); + } else { + this.vt100('\u0008 \u0008'); + } + } else { + this.vt100('\u0007'); + } + } else if (ch == '\u001B') { + // This was probably a function key. Just eat all of the following keys. + break; + } + } +}; + +Demo.prototype.doCommand = function() { + this.gotoState(2 /* STATE_PROMPT */); + var tokens = new Tokens(this.line); + this.line = ''; + var cmd = tokens.nextToken().toUpperCase(); + if (cmd.match(/^[0-9]+$/)) { + tokens.removeLineNumber(); + var lineNumber = parseInt(cmd); + var index = this.findLine(lineNumber); + if (tokens.nextToken() == undefined) { + if (index > 0) { + // Delete line from program + this.program.splice(index, 1); + } + } else { + if (index >= 0) { + // Replace line in program + this.program[index].setTokens(tokens); + } else { + // Add new line to program + this.program.splice(-index - 1, 0, new Line(lineNumber, tokens)); + } + } + } else { + this.currentLineIndex = -1; + this.tokens = tokens; + this.gotoState(5 /* STATE_EVAL */); + } + tokens.reset(); +}; + +Demo.prototype.doEval = function() { + this.gotoState(2 /* STATE_PROMPT */); + var cmd = this.tokens.nextToken().toUpperCase(); + if (cmd == "HELP") { + this.vt100('Supported commands:\r\n' + + ' HELP LIST RUN\r\n'); + } else if (cmd == "LIST") { + if (this.tokens.nextToken() != undefined) { + this.error(); + return false; + } else { + for (var i = 0; i < this.program.length; i++) { + var line = this.program[i]; + this.vt100('' + line.lineNumber()); + line.tokens().reset(); + for (var token; (token = line.tokens().nextToken()) != undefined; ) { + this.vt100(' ' + token); + } + line.tokens().reset(); + this.vt100('\r\n'); + } + } + } else if (cmd == "RUN") { + if (this.tokens.nextToken() != undefined) { + this.error(); + } else { + this.gotoState(6 /* STATE_RUN */); + } + return false; + } else { + this.error(); + return false; + } + return true; +}; + +Demo.prototype.doRun = function() { + if (this.program.length > 0) { + this.currentLineIndex = 0; + this.gotoState(7 /* STATE_EXEC */); + } +}; + +Demo.prototype.doExec = function() { + this.tokens = this.program[this.currentLineIndex++].tokens(); + this.tokens.reset(); + if (this.doEval()) { + if (this.currentLineIndex >= this.program.length) { + this.gotoState(2 /* STATE_PROMPT */); + return false; + } else { + this.gotoState(7 /* STATE_EXEC */, 20); + return true; + } + } +}; + +Demo.prototype.findLine = function(lineNumber) { + var l = 0; + var h = this.program.length; + while (h > l) { + var m = Math.floor((l + h) / 2); + var n = this.program[m].lineNumber(); + if (n == lineNumber) { + return m; + } else if (n > lineNumber) { + h = m; + } else { + l = m + 1; + } + } + return -l - 1; +}; + +function Tokens(line) { + this.tokens = line.split(' '); + this.index = 0; +}; + +Tokens.prototype.nextToken = function() { + while (this.index < this.tokens.length) { + var token = this.tokens[this.index++]; + token = token.replace(/^[ \t]*/, ''); + token = token.replace(/[ \t]*$/, ''); + if (token.length) { + return token; + } + } + return undefined; +}; + +Tokens.prototype.removeLineNumber = function() { + if (this.tokens.length > 0) { + this.tokens.splice(0, 1); + if (this.index > 0) { + this.index--; + } + } +}; + +Tokens.prototype.reset = function() { + this.index = 0; +}; + +function Line(lineNumber, tokens) { + this.lineNumber_ = lineNumber; + this.tokens_ = tokens; +}; + +Line.prototype.lineNumber = function() { + return this.lineNumber_; +}; + +Line.prototype.tokens = function() { + return this.tokens_; +}; + +Line.prototype.setTokens = function(tokens) { + this.tokens_ = tokens; +}; + +Line.prototype.sort = function(a, b) { + return a.lineNumber_ - b.lineNumber_; +}; diff --git a/demo/demo.jspp b/demo/demo.jspp new file mode 100644 index 0000000..cef6a69 --- /dev/null +++ b/demo/demo.jspp @@ -0,0 +1,371 @@ +// Demo.js -- Demonstrate some of the features of ShellInABox +// Copyright (C) 2008-2009 Markus Gutschke +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// 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., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// In addition to these license terms, the author grants the following +// additional rights: +// +// If you modify this program, or any covered work, by linking or +// combining it with the OpenSSL project's OpenSSL library (or a +// modified version of that library), containing parts covered by the +// terms of the OpenSSL or SSLeay licenses, the author +// grants you additional permission to convey the resulting work. +// Corresponding Source for a non-source form of such a combination +// shall include the source code for the parts of OpenSSL used as well +// as that of the covered work. +// +// You may at your option choose to remove this additional permission from +// the work, or from any part of it. +// +// It is possible to build this program in a way that it loads OpenSSL +// libraries at run-time. If doing so, the following notices are required +// by the OpenSSL and SSLeay licenses: +// +// This product includes software developed by the OpenSSL Project +// for use in the OpenSSL Toolkit. (http://www.openssl.org/) +// +// This product includes cryptographic software written by Eric Young +// (eay@cryptsoft.com) +// +// +// The most up-to-date version of this program is always available from +// http://shellinabox.com +// +// +// Notes: +// +// The author believes that for the purposes of this license, you meet the +// requirements for publishing the source code, if your web server publishes +// the source in unmodified form (i.e. with licensing information, comments, +// formatting, and identifier names intact). If there are technical reasons +// that require you to make changes to the source code when serving the +// JavaScript (e.g to remove pre-processor directives from the source), these +// changes should be done in a reversible fashion. +// +// The author does not consider websites that reference this script in +// unmodified form, and web servers that serve this script in unmodified form +// to be derived works. As such, they are believed to be outside of the +// scope of this license and not subject to the rights or restrictions of the +// GNU General Public License. +// +// If in doubt, consult a legal professional familiar with the laws that +// apply in your country. + +#define STATE_IDLE 0 +#define STATE_INIT 1 +#define STATE_PROMPT 2 +#define STATE_READLINE 3 +#define STATE_COMMAND 4 +#define STATE_EVAL 5 +#define STATE_RUN 6 +#define STATE_EXEC 7 + +function extend(subClass, baseClass) { + function inheritance() { } + inheritance.prototype = baseClass.prototype; + subClass.prototype = new inheritance(); + subClass.prototype.constructor = subClass; + subClass.prototype.superClass = baseClass.prototype; +}; + +function Demo(container) { + this.superClass.constructor.call(this, container); + this.gotoState(STATE_INIT); +}; +extend(Demo, VT100); + +Demo.prototype.keysPressed = function(ch) { + this.keys += ch; + this.gotoState(this.state); +}; + +Demo.prototype.gotoState = function(state, tmo) { + this.state = state; + if (!this.timer || tmo) { + if (!tmo) { + tmo = 1; + } + this.timer = setTimeout(function(demo) { + return function() { + demo.demo(); + }; + }(this), tmo); + } +}; + +Demo.prototype.demo = function() { + var done = false; + while (!done) { + var state = this.state; + this.state = STATE_IDLE; + switch (state) { + case STATE_INIT: + this.doInit(); + break; + case STATE_PROMPT: + this.doPrompt(); + break; + case STATE_READLINE: + this.doReadLine(); + if (this.state == STATE_READLINE) { + done = true; + } + break; + case STATE_COMMAND: + this.doCommand(); + break; + case STATE_EVAL: + this.doEval(); + break; + case STATE_RUN: + this.doRun(); + break; + case STATE_EXEC: + if (this.doExec()) { + return; + } + break; + case STATE_IDLE: + default: + done = true; + break; + } + } + this.timer = undefined; +}; + +Demo.prototype.error = function(msg) { + if (msg == undefined) { + msg = 'Syntax Error'; + } + this.vt100('\u0007? ' + msg + '\r\n'); + this.gotoState(STATE_PROMPT); +}; + +Demo.prototype.doInit = function() { + this.program = new Array(); + this.vt100( + '\u001Bc\u001B[34;4m' + + 'ShellInABox Demo Script\u001B[24;31m\r\n' + + '\r\n' + + 'Copyright 2009 by Markus Gutschke \u001B[0m\r\n' + + '\r\n' + + '\r\n' + + 'This script simulates a minimal BASIC interpreter, allowing you to\r\n' + + 'experiment with the JavaScript terminal emulator that is part of\r\n' + + 'the ShellInABox project.\r\n' + + '\r\n' + + 'Type HELP for a list of commands.\r\n' + + '\r\n'); + this.gotoState(STATE_PROMPT); +}; + +Demo.prototype.doPrompt = function() { + this.keys = ''; + this.line = ''; + this.currentLineIndex = -1; + this.vt100('> '); + this.gotoState(STATE_READLINE); +}; + +Demo.prototype.doReadLine = function() { + this.gotoState(STATE_READLINE); + var keys = this.keys; + this.keys = ''; + for (var i = 0; i < keys.length; i++) { + var ch = keys.charAt(i); + if (ch >= ' ' && ch < '\u007F' || ch > '\u00A0') { + this.line += ch; + this.vt100(ch); + } else if (ch == '\r' || ch == '\n') { + this.vt100('\r\n'); + this.gotoState(STATE_COMMAND); + } else if (ch == '\u0008' || ch == '\u007F') { + if (this.line.length > 0) { + this.line = this.line.substr(0, this.line.length - 1); + if (this.cursorX == 0) { + var x = this.terminalWidth - 1; + var y = this.cursorY - 1; + this.gotoXY(x, y); + this.vt100(' '); + this.gotoXY(x, y); + } else { + this.vt100('\u0008 \u0008'); + } + } else { + this.vt100('\u0007'); + } + } else if (ch == '\u001B') { + // This was probably a function key. Just eat all of the following keys. + break; + } + } +}; + +Demo.prototype.doCommand = function() { + this.gotoState(STATE_PROMPT); + var tokens = new Tokens(this.line); + this.line = ''; + var cmd = tokens.nextToken().toUpperCase(); + if (cmd.match(/^[0-9]+$/)) { + tokens.removeLineNumber(); + var lineNumber = parseInt(cmd); + var index = this.findLine(lineNumber); + if (tokens.nextToken() == undefined) { + if (index > 0) { + // Delete line from program + this.program.splice(index, 1); + } + } else { + if (index >= 0) { + // Replace line in program + this.program[index].setTokens(tokens); + } else { + // Add new line to program + this.program.splice(-index - 1, 0, new Line(lineNumber, tokens)); + } + } + } else { + this.currentLineIndex = -1; + this.tokens = tokens; + this.gotoState(STATE_EVAL); + } + tokens.reset(); +}; + +Demo.prototype.doEval = function() { + this.gotoState(STATE_PROMPT); + var cmd = this.tokens.nextToken().toUpperCase(); + if (cmd == "HELP") { + this.vt100('Supported commands:\r\n' + + ' HELP LIST RUN\r\n'); + } else if (cmd == "LIST") { + if (this.tokens.nextToken() != undefined) { + this.error(); + return false; + } else { + for (var i = 0; i < this.program.length; i++) { + var line = this.program[i]; + this.vt100('' + line.lineNumber()); + line.tokens().reset(); + for (var token; (token = line.tokens().nextToken()) != undefined; ) { + this.vt100(' ' + token); + } + line.tokens().reset(); + this.vt100('\r\n'); + } + } + } else if (cmd == "RUN") { + if (this.tokens.nextToken() != undefined) { + this.error(); + } else { + this.gotoState(STATE_RUN); + } + return false; + } else { + this.error(); + return false; + } + return true; +}; + +Demo.prototype.doRun = function() { + if (this.program.length > 0) { + this.currentLineIndex = 0; + this.gotoState(STATE_EXEC); + } +}; + +Demo.prototype.doExec = function() { + this.tokens = this.program[this.currentLineIndex++].tokens(); + this.tokens.reset(); + if (this.doEval()) { + if (this.currentLineIndex >= this.program.length) { + this.gotoState(STATE_PROMPT); + return false; + } else { + this.gotoState(STATE_EXEC, 20); + return true; + } + } +}; + +Demo.prototype.findLine = function(lineNumber) { + var l = 0; + var h = this.program.length; + while (h > l) { + var m = Math.floor((l + h) / 2); + var n = this.program[m].lineNumber(); + if (n == lineNumber) { + return m; + } else if (n > lineNumber) { + h = m; + } else { + l = m + 1; + } + } + return -l - 1; +}; + +function Tokens(line) { + this.tokens = line.split(' '); + this.index = 0; +}; + +Tokens.prototype.nextToken = function() { + while (this.index < this.tokens.length) { + var token = this.tokens[this.index++]; + token = token.replace(/^[ \t]*/, ''); + token = token.replace(/[ \t]*$/, ''); + if (token.length) { + return token; + } + } + return undefined; +}; + +Tokens.prototype.removeLineNumber = function() { + if (this.tokens.length > 0) { + this.tokens.splice(0, 1); + if (this.index > 0) { + this.index--; + } + } +}; + +Tokens.prototype.reset = function() { + this.index = 0; +}; + +function Line(lineNumber, tokens) { + this.lineNumber_ = lineNumber; + this.tokens_ = tokens; +}; + +Line.prototype.lineNumber = function() { + return this.lineNumber_; +}; + +Line.prototype.tokens = function() { + return this.tokens_; +}; + +Line.prototype.setTokens = function(tokens) { + this.tokens_ = tokens; +}; + +Line.prototype.sort = function(a, b) { + return a.lineNumber_ - b.lineNumber_; +}; diff --git a/demo/favicon.ico b/demo/favicon.ico new file mode 120000 index 0000000..68215d3 --- /dev/null +++ b/demo/favicon.ico @@ -0,0 +1 @@ +../shellinabox/favicon.ico \ No newline at end of file diff --git a/demo/styles.css b/demo/styles.css new file mode 120000 index 0000000..56f3b96 --- /dev/null +++ b/demo/styles.css @@ -0,0 +1 @@ +../shellinabox/styles.css \ No newline at end of file diff --git a/demo/vt100.js b/demo/vt100.js new file mode 120000 index 0000000..6cacc8e --- /dev/null +++ b/demo/vt100.js @@ -0,0 +1 @@ +../shellinabox/vt100.js \ No newline at end of file diff --git a/libhttp/ssl.c b/libhttp/ssl.c index 6966939..d4e1634 100644 --- a/libhttp/ssl.c +++ b/libhttp/ssl.c @@ -46,6 +46,9 @@ #define _GNU_SOURCE #include "config.h" +#define pthread_once x_pthread_once +#define pthread_sigmask x_pthread_sigmask + #include #include #include @@ -61,6 +64,9 @@ #include "libhttp/httpconnection.h" #include "logging/logging.h" +#undef pthread_once +#undef pthread_sigmask + #if defined(HAVE_OPENSSL) && !defined(OPENSSL_NO_TLSEXT) && \ defined(TLSEXT_NAMETYPE_host_name) && defined(SSL_TLSEXT_ERR_OK) #define HAVE_TLSEXT @@ -683,8 +689,11 @@ void sslBlockSigPipe(void) { sigset_t set; sigemptyset(&set); sigaddset(&set, SIGPIPE); - dcheck(!(&pthread_sigmask ? pthread_sigmask : sigprocmask) - (SIG_BLOCK, &set, NULL)); + if (&pthread_sigmask) { + dcheck(!pthread_sigmask(SIG_BLOCK, &set, NULL)); + } else { + dcheck(!sigprocmask(SIG_BLOCK, &set, NULL)); + } } int sslUnblockSigPipe(void) { @@ -696,8 +705,11 @@ int sslUnblockSigPipe(void) { } sigemptyset(&set); sigaddset(&set, SIGPIPE); - check(!(&pthread_sigmask ? pthread_sigmask : sigprocmask) - (SIG_UNBLOCK, &set, NULL)); + if (&pthread_sigmask) { + dcheck(!pthread_sigmask(SIG_UNBLOCK, &set, NULL)); + } else { + dcheck(!sigprocmask(SIG_UNBLOCK, &set, NULL)); + } return signum; } diff --git a/shellinabox/launcher.c b/shellinabox/launcher.c index 1f01dbb..7f57e79 100644 --- a/shellinabox/launcher.c +++ b/shellinabox/launcher.c @@ -46,6 +46,8 @@ #define _GNU_SOURCE #include "config.h" +#define pthread_once x_pthread_once + #include #include #include @@ -91,17 +93,19 @@ struct pam_conv; typedef struct pam_handle pam_handle_t; #endif -#if defined(HAVE_PTHREAD_H) && defined(__linux__) -#include -extern int pthread_once(pthread_once_t *, void (*)(void))__attribute__((weak)); -#endif - #include "shellinabox/launcher.h" #include "shellinabox/privileges.h" #include "shellinabox/service.h" #include "libhttp/hashmap.h" #include "logging/logging.h" +#undef pthread_once + +#if defined(HAVE_PTHREAD_H) && defined(__linux__) +#include +extern int pthread_once(pthread_once_t *, void (*)(void))__attribute__((weak)); +#endif + // If PAM support is available, take advantage of it. Otherwise, silently fall // back on legacy operations for session management. #if defined(HAVE_SECURITY_PAM_APPL_H) && defined(HAVE_DLOPEN)