debian/0000775000000000000000000000000011646575725007212 5ustar debian/default0000664000000000000000000000065411646574706010564 0ustar # Default start options for Ajaxterm # Sourced by /etc/init.d/ajaxterm # # This is a POSIX shell fragment # # Set the daemon's user id (ajaxterm by default) # If run as root ajaxterm will run `/bin/login', # otherwise it will run `ssh localhost'. #AJAXTERM_UID="ajaxterm" # Allow to change the default port used by Ajaxterm #PORT="8022" # Allow to use a different port than 22 to connect to the ssh server #SERVERPORT="22" debian/postrm0000664000000000000000000000025211646574706010456 0ustar #!/bin/sh set -e if [ "$1" = "purge" ] ; then # locks ajaxterm system user account on purge usermod -L -e 1 ajaxterm > /dev/null || true fi #DEBHELPER# exit 0 debian/copyright0000664000000000000000000000335511646574706011151 0ustar Format: http://dep.debian.net/deps/dep5/ Upstream-Name: Ajaxterm Source: https://github.com/antonylesuisse/qweb Files: * Copyright: This software is in the public domain License: public-domain This software is in the public domain Files: sarissa.js sarrissa_dhtml.js Copyright: Manos Batsis License: GPL-2 or LGPL-2.1 Files: debian/* Copyright: 2006-2011, Julien Valroff License: GPL-2 License: GPL-2 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. . 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. . On Debian systems, the full text of the GNU General Public License version 2 can be found in the file `/usr/share/common-licenses/GPL-2'. License: LGPL-2.1 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 or the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation (your choice between the two). . 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 or GNU Lesser General Public License for more details. . On Debian systems, the complete texts of the GNU Lesser General Public License version 2.1 can be found in the file `/usr/share/common-licenses/LGPL-2.1'. debian/watch0000664000000000000000000000012711646574706010241 0ustar version=3 http://antony.lesuisse.org/software/ajaxterm/files/Ajaxterm-([\d\.]+).tar.gz debian/examples0000664000000000000000000000002311646574706010744 0ustar debian/apache.conf debian/docs0000664000000000000000000000001311646574706010055 0ustar README.txt debian/README.Debian0000664000000000000000000000266311646574706011260 0ustar ajaxterm for Debian ------------------- * Ajaxterm only supports utf8. * With the default settings, you have to install openssh-server and allow password authentication. Open file /etc/ssh/sshd_config and set: PasswordAuthentication yes As an alternative, you might choose to run ajaxterm as root. Change the default daemon setting in file /etc/default/ajaxterm to: AJAXTERM_UID="root" Ajaxterm will then fall back to use /bin/login. * Apache setup By default Ajaxterm only listen at 127.0.0.1:8022. For remote access, it is strongly recommended to use https SSL/TLS, and that is simple to configure if you use the apache web server using mod_proxy. If apache2 is not already set up for for https SSL/TLS, ensure openssl is installed to issue a self signed certificate (apache.pem): export RANDFILE=/dev/random \ openssl req -new -x509 -days 365 -nodes \ -out /etc/apache2/ssl/apache.pem \ -keyout /etc/apache2/ssl/apache.pem With apache2, copy the site file: cp /usr/share/doc/ajaxterm/examples/apache.conf \ /etc/apache2/sites-available/ajaxterm.conf Edit it to suit your needs, enable site, enable apache features, and restart: a2ensite ajaxterm a2enmod ssl a2enmod proxy_http /etc/init.d/apache reload -- Julien Valroff Sun, 29 Aug 2010 21:12:33 +0200 debian/ajaxterm.conf0000664000000000000000000000035411646574706011674 0ustar // Ajaxterm configuration file // // This is a javascript snippet // // Don't forget to restart ajaxterm after editing this file // Sets the terminal width (default: 80) width=80; // Sets the terminal height (default: 25) height=25; debian/changelog0000664000000000000000000002367611646575667011107 0ustar ajaxterm (0.10-12ubuntu1) precise; urgency=low * Merge from debian testing. Remaining changes: - debian/control: Moved dependency for python-psyco from Recommends to Suggests to avoid pulling python-psyco into main. (LP: #829271 * Dropped changes: - debian/patches/93_bug795159.diff: - Applied in Debian. - debian/rules: delete auto-installed /usr/share/python/runtime.d: - Determined to be required (See Debian bug 638332). -- Dave Walker (Daviey) Sun, 16 Oct 2011 16:37:30 +0100 ajaxterm (0.10-12) unstable; urgency=low * Update VCS fields * Apply patch from Ubuntu to remove unneeded sys.path call - thanks to C de-Avillez (Closes: #638332) * Ensures system user is unlocked in case the package is reinstalled * Update copyright information: + New upstream git repository location + Fix DEP-5 url * Add retry=0 to ProxyPass lines in Apache configuration example: this prevents 503 errors to be sent by Apache after Ajaxterm was restarted -- Julien Valroff Fri, 19 Aug 2011 16:31:06 +0200 ajaxterm (0.10-11ubuntu2) oneiric; urgency=low * debian/control: Moved dependency for python-psyco from Recommends to Suggests to avoid pulling python-psyco into main. (LP: #829271) -- Marc Cluet Fri, 19 Aug 2011 11:40:27 +0100 ajaxterm (0.10-11ubuntu1) oneiric; urgency=low * Resolutions for issues outlined in MIR (LP: #795159, Closes: 638332): + debian/patches/93_bug795159.diff: removed add to sys.path at beginning of the code (unneeded, potential security issue). + debian/rules: delete auto-installed /usr/share/python/runtime.d. -- C de-Avillez Wed, 17 Aug 2011 12:29:51 -0500 ajaxterm (0.10-11) unstable; urgency=low * Switch from pysupport to dh_python2 * Add patches from Soren Hansen : + add a simple token-based access control system to ajaxterm (Closes: #620789) + fix improper escaping of command arguments in /usr/bin wrapper (Closes: #620790) + add a -T option to terminate ajaxterm itself after n secs idle (Closes: #620701) * Update to new policy 3.9.2 (no changes needed) * Lock system user on purge rather than deleting it * Make use of dh_install and dh_links rather than using a patch to set up the configuration file -- Julien Valroff Sun, 17 Apr 2011 09:32:01 +0200 ajaxterm (0.10-10) unstable; urgency=low * Update my email address * Remove DMUA field, now useless * Update copyright file for current revision of DEP-5 * Restrict recommends on python-psyco to i386 architectures * Improve manpage to state all options * Bump debhelper compat to 8 -- Julien Valroff Sat, 12 Feb 2011 15:07:52 +0100 ajaxterm (0.10-9) unstable; urgency=low * Fix typo in README.Debian (thanks to Julien Cristau for spotting this) * Upload to unstable now that 0.10-7 has entered testing -- Julien Valroff Sun, 17 Oct 2010 09:22:13 +0200 ajaxterm (0.10-8) experimental; urgency=low * Apply fix for bold attribute (Closes: #580977) * Add patch to add support for Ctrl-@ and Ctrl-space (thanks to Daniel Risacher ) -- Julien Valroff Sun, 26 Sep 2010 10:28:11 +0200 ajaxterm (0.10-7) unstable; urgency=low * Update to new policy 3.9.1 (no changes needed) * Rephrase README.Debian - thanks to Jari Aalto (Closes: #580164, #580166, #580167) * Ship apache configuration as a separate example file (Closes: #580165) * Suggest openssl -- Julien Valroff Sun, 26 Sep 2010 08:54:33 +0200 ajaxterm (0.10-6) unstable; urgency=low * Fix exception (remove spurious "del self.session[s]") Thanks to Raphael Geissert (Closes: #569270) * Add dependency on $remote_fs in init script to ensure /usr is mounted when starting/stopping the daemon -- Julien Valroff Thu, 11 Feb 2010 20:33:25 +0100 ajaxterm (0.10-5) unstable; urgency=low * Make use of python-support >= 0.6 * Updated to new policy 3.8.4 (no changes needed) * Bumped debhelper compat to 7 * Removed useless lintian override * Updated Debian packaging copyright * Added $AJAXTERM_UID in default file, allowing to change the user running ajaxterm (Closes: #531165) * Make use of start-stop-daemon --group option to also allow to change the GID (Closes: #528208) * Updated README.Debian * Added patch from Berki Lukács T. : + Make it work with Chrome and possibly other Webkit-based browsers + Returns Connection: keep-alive and Content-Length HTTP headers to avoid doing a complete SSL handshake on every keystroke and screen update + Added a reaper thread to kill off disconnected sessions + Sends SIGHUP rather than SIGTERM on end of session + Threaded mode is default * CVE-2009-1629: ajaxterm generated session IDs with predictable random numbers - thanks to Raphael Geissert (Closes: #528938) * Added configuration file allowing to set terminal size (Closes: #515987) * Fixed typo in copyright file - license for sarissa* files is now correct * Added patch from Sergej Pupykin to switch ajaxterm from Latin-1 to UTF-8 encoding (Closes: #541850) * Use start-stop-daemon return code in the init script * Removed sleep call when restarting ajaxterm daemon * Added patch to display hostname in login prompt * Fixed manpage to make lintian happy * Switched to GIT - updated VCS-* fields accordingly * Converted package to dh minimal rules files * Switched to 3.0 (quilt) source format * Removed pyversions file and use XS-Python-Version field instead * Build-depend on python rather than on python-dev * Fixed issue in sarissa with Firefox/Iceweasel 3.6 (Closes: #568372) -- Julien Valroff Sat, 06 Feb 2010 09:57:33 +0100 ajaxterm (0.10-4) unstable; urgency=low * Fixed debian/watch to match new files location * Added ${misc:Depends} dependency -- Julien Valroff Sun, 04 Jan 2009 12:00:07 +0100 ajaxterm (0.10-3) unstable; urgency=low * Fixed "IOError: [Errno 22] Invalid argument" error - patch from Marco d'Itri (md@linux.it) (Closes: #496470) * Fixed initscript to prevent ajaxterm to be started twice (Closes: #501386) * Made copyright information machine-interpretable * Updated to new policy 3.8.0 (no changes needed) * Added patch from Brian Minton to allow use of psyco when available (Closes: #504020) * Added python-psyco to Recommends: (currently only available for i386) -- Julien Valroff Fri, 31 Oct 2008 20:04:40 +0100 ajaxterm (0.10-2) unstable; urgency=low * Added patch to allow use a different port than 22 to connect to the ssh server. Thanks to Wolf Wiegand (Closes: #455245) * Updated README.Debian to state proxy_http is required (and not only proxy). Thanks to sp (Closes: #468582) * Added watch file * Moved Homepage to own field (from pseudo-field in long description) * Added Vcs-* fields * Added XS-DM-Upload-Allowed field * Bumped to new standards version 3.7.3 (no changes needed) * Fixed Python capitalisation in description -- Julien Valroff Sun, 02 Mar 2008 09:24:28 +0100 ajaxterm (0.10-1) unstable; urgency=low * New upstream release (Closes: #400501): - allow space in login - cgi launch fix * debian/patches/: - Updated 02_initd.patch for new release * debian/rules: - Removed dh_python call * debian/postrm: - Don't remove the ajaxterm group (done automatically by deluser) * debian/README.Debian: - Documented the fact that SSH password authentication should be allowed (Close: #407429) - Added note describing apache ssl configuration (thanks to Brendan M. Sleight ) -- Julien Valroff Sun, 4 Mar 2007 00:09:02 +0100 ajaxterm (0.9-2) unstable; urgency=low * Changed dependency on openssh-server to recommend (Closes: #384931) * Moved python-support to Build-depends as used in the clean target * Added LSB keyword section to init script -- Julien Valroff Fri, 6 Oct 2006 23:07:49 +0200 ajaxterm (0.9-1) unstable; urgency=low * New upstream release (Closes: #377597) + changed uid + daemon fix * Now daemon runs as ajaxterm system user * Added patch to use default python version -- Julien Valroff Sat, 15 Jul 2006 11:17:39 +0200 ajaxterm (0.8-1) unstable; urgency=low * New upstream release: + added login support to ssh + changed max width to 256 -- Julien Valroff Mon, 10 Jul 2006 18:27:07 +0200 ajaxterm (0.7-3) unstable; urgency=low * Removed bashisms from init script (Closes: #376088) * Added patch to update man page -- Julien Valroff Sat, 1 Jul 2006 00:25:54 +0200 ajaxterm (0.7-2) unstable; urgency=low * Fixed init script so that only root can start Ajaxterm as daemon * Updated to comply with new Debian python policy * Fixed Homepage: pseudo-header in debian/control -- Julien Valroff Sun, 4 Jun 2006 10:23:16 +0200 ajaxterm (0.7-1) unstable; urgency=low * New upstream release: + minor fixes + daemon option * Removed patch to add a correct DTD to ajaxterm.html (fixed upstream) * Removed patch to fix man directory (fixed upstream) * Removed patch to fix permissions (fixed upstream) * Changed init script to use the new --daemon option * Overrided Lintian warning about non-executable python helper script * Added dependency on lsb-base to ease backporting -- Julien Valroff Thu, 1 Jun 2006 19:23:41 +0200 ajaxterm (0.6-1) unstable; urgency=low * Initial release (Closes: #366285) -- Julien Valroff Tue, 23 May 2006 20:48:06 +0200 debian/postinst0000664000000000000000000000103711646574706011017 0ustar #! /bin/sh set -e case "$1" in configure) if ! getent passwd ajaxterm >/dev/null; then adduser --disabled-password --quiet --system \ --no-create-home \ --gecos "Ajaxterm system user" --group ajaxterm else # Unlock account in case it was locked from previous purge. usermod -U -e '' ajaxterm > /dev/null || true fi ;; abort-upgrade|abort-remove|abort-deconfigure) ;; *) echo "postinst called with unknown argument \`$1'" >&2 exit 1 ;; esac #DEBHELPER# exit 0 debian/control0000664000000000000000000000151411646575523010612 0ustar Source: ajaxterm Section: web Priority: optional Maintainer: Ubuntu Developers XSBC-Original-Maintainer: Julien Valroff Build-Depends: debhelper (>= 8.0.0), python (>= 2.6.6-3) Standards-Version: 3.9.2 X-Python-Version: >= 2.3 Homepage: http://antony.lesuisse.org/qweb/trac/wiki/AjaxTerm Vcs-Git: git://git.kirya.net/debian/ajaxterm.git Vcs-Browser: http://git.kirya.net/?p=debian/ajaxterm.git;a=summary Package: ajaxterm Architecture: all Depends: ${python:Depends}, ${misc:Depends}, adduser Recommends: apache2 | httpd, openssh-server Suggests: openssl, python-psyco Description: Web based terminal written in Python Ajaxterm is a web based terminal written in Python and some AJAX javascript for client side. It can use almost any web browser and even works through firewalls. debian/init0000664000000000000000000000262211646574706010100 0ustar #!/bin/sh # ### BEGIN INIT INFO # Provides: ajaxterm # Required-Start: $syslog $local_fs $remote_fs # Required-Stop: $syslog $local_fs $remote_fs # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: starts/stops ajaxterm # Description: starts and stops Ajaterm, # a web based terminal written in Python ### END INIT INFO PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin DAEMON=/usr/bin/ajaxterm PORT=8022 SERVERPORT=22 PIDFILE=/var/run/ajaxterm.pid NAME=ajaxterm DESC="web based terminal" AJAXTERM_UID=ajaxterm AJAXTERM_GID=ajaxterm if [ $(id -u) != 0 ]; then echo "You should run this program as root" exit 1 fi [ -x "$DAEMON" ] || exit 0 [ -f "/etc/default/ajaxterm" ] && . /etc/default/ajaxterm . /lib/lsb/init-functions case "$1" in start) log_begin_msg "Starting $DESC:" "$NAME" if [ -f $PIDFILE ]; then log_action_cont_msg " already running" log_end_msg 1 else start-stop-daemon --start --group=$AJAXTERM_GID --pidfile $PIDFILE --exec $DAEMON -- --daemon --port=$PORT --serverport=$SERVERPORT \ --uid=$AJAXTERM_UID >/dev/null log_end_msg $? fi ;; stop) log_begin_msg "Stopping $DESC:" "$NAME" start-stop-daemon --stop --pidfile $PIDFILE rm -f $PIDFILE log_end_msg $? ;; restart|force-reload) $0 stop $0 start ;; *) echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2 exit 3 ;; esac debian/rules0000775000000000000000000000022111646574706010263 0ustar #!/usr/bin/make -f %: dh $@ --with python2 override_dh_auto_configure: ./configure --prefix=debian/ajaxterm/usr --confdir=debian/ajaxterm/etc debian/patches/0000775000000000000000000000000011646575725010641 5ustar debian/patches/93_useless-sys.path-call_LP795159.diff0000664000000000000000000000077511646574706017257 0ustar Description: Remove unneeded sys.path call (potential security issue) Author: C de-Avillez Bug-Ubuntu: https://bugs.launchpad.net/bugs/795159 Bug-Debian: http://bugs.debian.org/638332 Last-Update: 2011-08-19 --- a/ajaxterm.py +++ b/ajaxterm.py @@ -18,8 +18,6 @@ sha1 = sha.new os.chdir(os.path.normpath(os.path.dirname(__file__))) -# Optional: Add QWeb in sys path -sys.path[0:0]=glob.glob('../../python') import qweb, codecs utf8decoder = codecs.getincrementaldecoder('utf8')() debian/patches/05_ssh-port.diff0000664000000000000000000000525111646574706013557 0ustar Description: Allows to change ssh server port Author: Wolf Wiegand Bug-Debian: http://bugs.debian.org/455245 --- a/ajaxterm.py +++ b/ajaxterm.py @@ -367,9 +367,10 @@ return r class Multiplex: - def __init__(self,cmd=None): + def __init__(self,cmd=None,serverport=None): signal.signal(signal.SIGCHLD, signal.SIG_IGN) self.cmd=cmd + self.serverport=serverport self.proc={} self.lock=threading.RLock() self.thread=threading.Thread(target=self.loop) @@ -403,7 +404,10 @@ cmd+=['-oPreferredAuthentications=keyboard-interactive,password'] cmd+=['-oNoHostAuthenticationForLocalhost=yes'] cmd+=['-oLogLevel=FATAL'] - cmd+=['-F/dev/null','-l',login,'localhost'] + cmd+=['-F/dev/null'] + if self.serverport: + cmd+=['-p %s'%self.serverport] + cmd+=['-l', login, 'localhost'] else: os._exit(0) env={} @@ -473,7 +477,7 @@ pass class AjaxTerm: - def __init__(self,cmd=None,index_file='ajaxterm.html'): + def __init__(self,cmd=None,index_file='ajaxterm.html',serverport=None): self.files={} for i in ['css','html','js']: for j in glob.glob('*.%s'%i): @@ -481,7 +485,7 @@ self.files['index']=file(index_file).read() self.mime = mimetypes.types_map.copy() self.mime['.html']= 'text/html; charset=UTF-8' - self.multi = Multiplex(cmd) + self.multi = Multiplex(cmd,serverport) self.session = {} def __call__(self, environ, start_response): req = qweb.QWebRequest(environ, start_response,session=None) @@ -528,6 +532,7 @@ parser.add_option("-P", "--pidfile",dest="pidfile",default="/var/run/ajaxterm.pid",help="set the pidfile (default: /var/run/ajaxterm.pid)") parser.add_option("-i", "--index", dest="index_file", default="ajaxterm.html",help="default index file (default: ajaxterm.html)") parser.add_option("-u", "--uid", dest="uid", help="Set the daemon's user id") + parser.add_option("-s", "--serverport", dest="serverport", help="Use a different port than 22 to connect to the ssh server") (o, a) = parser.parse_args() if o.daemon: pid=os.fork() @@ -553,7 +558,7 @@ sys.exit(0) else: print 'AjaxTerm at http://localhost:%s/' % o.port - at=AjaxTerm(o.cmd,o.index_file) + at=AjaxTerm(o.cmd,o.index_file,o.serverport) # f=lambda:os.system('firefox http://localhost:%s/&'%o.port) # qweb.qweb_wsgi_autorun(at,ip='localhost',port=int(o.port),threaded=0,log=o.log,callback_ready=None) try: --- a/ajaxterm.1 +++ b/ajaxterm.1 @@ -36,6 +36,10 @@ .TP \fB\-u\fR UID, \fB\-\-uid\fR=\fIUID\fR Set the daemon's user id +.TP +\fB\-s\fR SERVERPORT, \fB\-\-serverport\fR=\fISERVERPORT\fR +Use a different port than 22 to connect to the ssh +server .SH AUTHOR Antony Lesuisse debian/patches/06_fix-IOError.diff0000664000000000000000000000137711646574706014113 0ustar Description: Fix for "IOError: [Errno 22] Invalid argument" error Author: Marco d'Itri Bug-Debian: http://bugs.debian.org/496470 diff -Nur -x '*.orig' -x '*~' ajaxterm/ajaxterm.py ajaxterm.new/ajaxterm.py --- ajaxterm/ajaxterm.py 2008-08-25 11:14:53.000000000 +0200 +++ ajaxterm.new/ajaxterm.py 2008-08-25 11:15:26.000000000 +0200 @@ -419,7 +419,7 @@ else: fcntl.fcntl(fd, fcntl.F_SETFL, os.O_NONBLOCK) # python bug http://python.org/sf/1112949 on amd64 - fcntl.ioctl(fd, struct.unpack('i',struct.pack('I',termios.TIOCSWINSZ))[0], struct.pack("HHHH",h,w,0,0)) + fcntl.ioctl(fd, termios.TIOCSWINSZ, struct.pack("HHHH",h,w,0,0)) self.proc[fd]={'pid':pid,'term':Terminal(w,h),'buf':'','time':time.time()} return fd def die(self): debian/patches/01_bin_dir.diff0000664000000000000000000000044011646574706013375 0ustar Description: Fix binary location for Debian Author: Julien Valroff --- a/configure.ajaxterm.bin +++ b/configure.ajaxterm.bin @@ -1,2 +1,3 @@ #!/bin/sh -PYTHONPATH=%(lib)s exec %(lib)s/ajaxterm.py $@ +PYTHONPATH=/usr/share/ajaxterm +exec $PYTHONPATH/ajaxterm.py "$@" debian/patches/15_add-configure-file.diff0000664000000000000000000000173011646574706015423 0ustar Description: Adds a configuration file allowing to set terminal size Author: Julien Valroff Bug-Debian: http://bugs.debian.org/515987 --- a/ajaxterm.html +++ b/ajaxterm.html @@ -7,9 +7,10 @@ + --- a/ajaxterm.js +++ b/ajaxterm.js @@ -4,6 +4,14 @@ if(window.ActiveXObject) ie=1; var sid=""+Math.round(Math.random()*1000000000); + + if (width==0) { + width=80; + } + if (height==0) { + height=25; + } + var query0="s="+sid+"&w="+width+"&h="+height; var query1=query0+"&c=1&k="; var buf=""; debian/patches/07_use_psyco.diff0000664000000000000000000000213111646574706014005 0ustar Description: Allow use of psyco when available Author: Brian Minton Bug-Debian: http://bugs.debian.org/504020 diff -Nur -x '*.orig' -x '*~' ajaxterm/ajaxterm.py ajaxterm.new/ajaxterm.py --- ajaxterm/ajaxterm.py 2008-10-31 17:45:08.000000000 +0100 +++ ajaxterm.new/ajaxterm.py 2008-10-31 17:45:44.000000000 +0100 @@ -2,6 +2,12 @@ """ Ajaxterm """ +try: + import psyco + psyco.profile() +except: + pass + import array,cgi,fcntl,glob,mimetypes,optparse,os,pty,random,re,signal,select,sys,threading,time,termios,struct,pwd os.chdir(os.path.normpath(os.path.dirname(__file__))) diff -Nur -x '*.orig' -x '*~' ajaxterm/qweb.py ajaxterm.new/qweb.py --- ajaxterm/qweb.py 2008-10-31 17:45:07.000000000 +0100 +++ ajaxterm.new/qweb.py 2008-10-31 17:46:07.000000000 +0100 @@ -116,6 +116,12 @@ except ImportError: import StringIO +try: + import psyco + psyco.profile() +except: + pass + #---------------------------------------------------------- # Qweb Xml t-raw t-esc t-if t-foreach t-set t-call t-trim #---------------------------------------------------------- debian/patches/series0000664000000000000000000000061611646574706012057 0ustar 01_bin_dir.diff 02_initd.diff 03_fix_man.diff 04_use-default-python.diff 05_ssh-port.diff 06_fix-IOError.diff 07_use_psyco.diff 10_hostname-login.diff 15_add-configure-file.diff 20_bugfixes-tweaks-by-blt.diff 25_CVE-2009-1629.diff 30_utf8-support.diff 35_fix-sarissa.diff 40_more-ctrl-catches.diff 90_token_based_access_control.diff 91_terminate_on_idle.diff 93_useless-sys.path-call_LP795159.diff debian/patches/10_hostname-login.diff0000664000000000000000000000133011646574706014712 0ustar Description: Add the hostname to the login prompt Author: Julien Valroff diff -Nur -x '*.orig' -x '*~' ajaxterm/ajaxterm.py ajaxterm.new/ajaxterm.py --- ajaxterm/ajaxterm.py 2009-10-14 09:04:39.964957030 +0200 +++ ajaxterm.new/ajaxterm.py 2009-10-14 09:04:52.776956219 +0200 @@ -15,6 +15,7 @@ sys.path[0:0]=glob.glob('../../python') import qweb +from socket import gethostname class Terminal: def __init__(self,width=80,height=24): @@ -403,7 +404,7 @@ elif os.getuid()==0: cmd=['/bin/login'] else: - sys.stdout.write("Login: ") + sys.stdout.write(gethostname() + " login: ") login=sys.stdin.readline().strip() if re.match('^[0-9A-Za-z-_. ]+$',login): cmd=['ssh'] debian/patches/25_CVE-2009-1629.diff0000664000000000000000000001207211646574706013405 0ustar Description: Security fix for CVE-2009-1629 (generates session IDs with predictable random numbers) Use a cookie with a strong random name and a strong random value for each user to protect from session id hijacking attacks. The browser-generated session id is now stronger but only used to separate multiple sessions of the same ip. Additionally, a limiting mechanism sets a maximum of 20 simultaneous sessions in total and 4 maximum sessions per connecting ip. The X-Forwarded-For header is only honoured if the real remote ip is 127.0.0.1. Author: Raphael Geissert Origin: http://bugs.debian.org/cgi-bin/bugreport.cgi?msg=75;filename=CVE-2009-1629.patch;att=1;bug=528938 Debian-Bug: http://bugs.debian.org/528938 --- a/ajaxterm.js +++ b/ajaxterm.js @@ -6,7 +6,22 @@ ie=1; if (navigator.userAgent.indexOf("WebKit") >= 0) webkit=1; - var sid=""+Math.round(Math.random()*1000000000); + var sid=""; + + for (var i=0; i < 255; i++) { + var r = 0; + // now get a random number between 0 and 255 + // numbers not in the range are intentionally discarded + // as it reduces the chance of predicting the seed, by not + // using all of the numbers generated by the PRNG + do { + r = Math.round(Math.random()*1000); + } while(r >= 255); + r = r.toString(16); + if (r.length == 1) + r = "0"+r; + sid += "%" + r; + } if (width==0) { width=80; --- a/ajaxterm.py +++ b/ajaxterm.py @@ -8,8 +8,14 @@ except: pass -import array,cgi,fcntl,glob,mimetypes,optparse,os,pty,random,re,signal,select,sys,threading,time,termios,struct,pwd -from datetime import datetime +import array,cgi,fcntl,glob,mimetypes,optparse,os,pty,random,re,signal,select,sys,threading,time,termios,struct,pwd,Cookie +from datetime import datetime, timedelta + +try: + from hashlib import sha1 +except ImportError: + import sha + sha1 = sha.new os.chdir(os.path.normpath(os.path.dirname(__file__))) # Optional: Add QWeb in sys path @@ -517,30 +523,61 @@ self.multi = Multiplex(cmd,serverport) self.reaper = Reaper(self.multi) self.session = {} + self.session_ip = {} + self.sessions_limit = 20 + self.sessions_user_limit = 4 + m = sha1() + m.update(os.urandom(128)) + self.cookie_name = m.hexdigest() def __call__(self, environ, start_response): req = qweb.QWebRequest(environ, start_response,session=None) if req.PATH_INFO.endswith('/u'): + req.response_headers['Content-Type']='text/xml' + uid="" + if self.cookie_name not in req.request_cookies: + req.write('') + return req + uid = req.request_cookies[self.cookie_name].value s=req.REQUEST["s"] k=req.REQUEST["k"] c=req.REQUEST["c"] w=req.REQUEST.int("w") h=req.REQUEST.int("h") - if s in self.session: - term=self.session[s] + ip="unknown" + if environ.has_key("REMOTE_ADDR"): + ip=environ['REMOTE_ADDR'] + if ip == "127.0.0.1" and environ.has_key("HTTP_X_FORWARDED_FOR"): + ip=environ["HTTP_X_FORWARDED_FOR"] + + if (uid+s) in self.session: + term=self.session[uid+s] + req.response_cookies.load(req.request_cookies[self.cookie_name].OutputString()) + req.response_cookies[self.cookie_name]['expires'] = datetime.utcnow()+timedelta(seconds=60) else: if not (w>2 and w<256 and h>2 and h<100): w,h=80,25 - term=self.session[s]=self.multi.create(w,h) + # check if there aren't too many open sessions + if len(self.session) < self.sessions_limit: + count=0 + for i in self.session_ip.keys(): + if self.session_ip[i] == ip: + count+=1 + if count <= self.sessions_user_limit: + term=self.session[uid+s]=self.multi.create(w,h) + self.session_ip[uid+s]=ip + else: + req.write('') + return req if k: self.multi.proc_write(term,k) time.sleep(0.002) dump=self.multi.dump(term,c) - req.response_headers['Content-Type']='text/xml' if isinstance(dump,str): req.write(dump) req.response_gzencode=1 else: - del self.session[s] + del self.session[uid+s] + del self.session_ip[uid+s] req.write('') # print "sessions %r"%self.session else: @@ -549,9 +586,23 @@ req.response_headers['Content-Type'] = self.mime.get(os.path.splitext(n)[1].lower(), 'application/octet-stream') req.write(self.files[n]) else: + if self.cookie_name not in req.request_cookies: + self.genSidCookie(req) req.response_headers['Content-Type'] = 'text/html; charset=UTF-8' req.write(self.files['index']) return req + def genSidCookie(self, req): + m = sha1() + m.update(os.urandom(160)) + req.response_cookies[self.cookie_name] = m.hexdigest() + # try to set httponly if supported (added in 2.6) + try: + req.response_cookies[self.cookie_name]['httponly'] = 1 + except (Cookie.CookieError): + pass + req.response_cookies[self.cookie_name]['path'] = req.PATH_INFO + req.response_cookies[self.cookie_name]['expires'] = datetime.utcnow()+timedelta(seconds=60) + return req def main(): parser = optparse.OptionParser() debian/patches/04_use-default-python.diff0000664000000000000000000000054311646574706015533 0ustar Description: Use default python version Author: Julien Valroff diff -Nur ajaxterm/qweb.py ajaxterm.new/qweb.py --- ajaxterm/qweb.py 2006-07-10 18:27:05.000000000 +0200 +++ ajaxterm.new/qweb.py 2006-07-15 11:15:09.000000000 +0200 @@ -1,4 +1,4 @@ -#!/usr/bin/python2.3 +#!/usr/bin/env python # # vim:set et ts=4 fdc=0 fdn=2 fdl=0: # debian/patches/20_bugfixes-tweaks-by-blt.diff0000664000000000000000000001335211646574706016275 0ustar Description: + Make it work with Chrome and possibly other Webkit-based browsers + Returns Connection: keep-alive and Content-Length HTTP headers to avoid doing a complete SSL handshake on every keystroke and screen update + Added a reaper thread to kill off disconnected sessions + Sends SIGHUP rather than SIGTERM on end of session + Threaded mode is default Author: Berki Lukács T. --- a/ajaxterm.js +++ b/ajaxterm.js @@ -1,8 +1,11 @@ ajaxterm={}; ajaxterm.Terminal_ctor=function(id,width,height) { var ie=0; + var webkit=0; if(window.ActiveXObject) ie=1; + if (navigator.userAgent.indexOf("WebKit") >= 0) + webkit=1; var sid=""+Math.round(Math.random()*1000000000); if (width==0) { @@ -242,7 +245,7 @@ } function keydown(ev) { if (!ev) var ev=window.event; - if (ie) { + if (ie || webkit) { // s="kd keyCode="+ev.keyCode+" which="+ev.which+" shiftKey="+ev.shiftKey+" ctrlKey="+ev.ctrlKey+" altKey="+ev.altKey; // debug(s); o={9:1,8:1,27:1,33:1,34:1,35:1,36:1,37:1,38:1,39:1,40:1,45:1,46:1,112:1, --- a/ajaxterm.py +++ b/ajaxterm.py @@ -9,6 +9,7 @@ pass import array,cgi,fcntl,glob,mimetypes,optparse,os,pty,random,re,signal,select,sys,threading,time,termios,struct,pwd +from datetime import datetime os.chdir(os.path.normpath(os.path.dirname(__file__))) # Optional: Add QWeb in sys path @@ -17,6 +18,11 @@ import qweb from socket import gethostname + +def debug(str): + now = datetime.datetime.now() + print "%s - %s" % (now.isoformat(), str) + class Terminal: def __init__(self,width=80,height=24): self.width=width @@ -373,7 +379,23 @@ self.lock.release() return r +class Reaper: + WAKEUP_FREQUENCY=5 + + def __init__(self,multi): + self.multi = multi + self.thread = threading.Thread(target = self.reaper_thread) + self.thread.setDaemon(True) + self.thread.start() + + def reaper_thread(self): + while True: + time.sleep(Reaper.WAKEUP_FREQUENCY) + self.multi.proc_kill_inactive() + class Multiplex: + INACTIVE_PROCESS_TIMEOUT=120 # I guess this is the IP max packet lifetime + def __init__(self,cmd=None,serverport=None): signal.signal(signal.SIGCHLD, signal.SIG_IGN) self.cmd=cmd @@ -435,19 +457,19 @@ return self.alive def fds(self): return self.proc.keys() - def proc_kill(self,fd): - if fd in self.proc: - self.proc[fd]['time']=0 + def proc_kill(self, fd): + try: + os.close(fd) + os.kill(self.proc[fd]['pid'],signal.SIGHUP) + except (IOError,OSError): + pass + del self.proc[fd] + def proc_kill_inactive(self): t=time.time() for i in self.proc.keys(): t0=self.proc[i]['time'] - if (t-t0)>120: - try: - os.close(i) - os.kill(self.proc[i]['pid'],signal.SIGTERM) - except (IOError,OSError): - pass - del self.proc[i] + if (t-t0)>Multiplex.INACTIVE_PROCESS_TIMEOUT: + self.proc_kill(i) def proc_read(self,fd): try: t=self.proc[fd]['term'] @@ -493,6 +515,7 @@ self.mime = mimetypes.types_map.copy() self.mime['.html']= 'text/html; charset=UTF-8' self.multi = Multiplex(cmd,serverport) + self.reaper = Reaper(self.multi) self.session = {} def __call__(self, environ, start_response): req = qweb.QWebRequest(environ, start_response,session=None) @@ -569,7 +592,7 @@ # f=lambda:os.system('firefox http://localhost:%s/&'%o.port) # qweb.qweb_wsgi_autorun(at,ip='localhost',port=int(o.port),threaded=0,log=o.log,callback_ready=None) try: - qweb.QWebWSGIServer(at,ip='localhost',port=int(o.port),threaded=0,log=o.log).serve_forever() + qweb.QWebWSGIServer(at,ip='localhost',port=int(o.port),threaded=1,log=o.log).serve_forever() except KeyboardInterrupt,e: sys.excepthook(*sys.exc_info()) at.multi.die() --- a/qweb.py +++ b/qweb.py @@ -1182,6 +1182,10 @@ self.buffer=[zbuf] self.response_headers['Content-Encoding']="gzip" self.response_headers['Content-Length']=str(len(zbuf)) + else: + datalen = sum(map(len, self.buffer)) + self.response_headers['Content-Length']=str(datalen) + headers = self.response_headers.get() if isinstance(self.SESSION, QWebSession): headers.extend(self.SESSION.session_get_headers()) @@ -1257,6 +1261,7 @@ self.write(buf.getvalue()) self.wfile_buf=0 def serve(self,type): + self.handleKeepalive() path_info, parameters, query = urlparse.urlparse(self.path)[2:5] environ = { 'wsgi.version': (1,0), @@ -1287,10 +1292,31 @@ # Hack to avoid may TCP packets self.bufferon() appiter=self.server.wsgiapp(environ, self.start_response) + if self.close_connection == 0: + appiter.response_headers['Connection']='keep-alive' + appiter.response_headers['Keep-Alive']='timeout=10, max=100' + for data in appiter: self.write(data) self.bufferoff() self.bufferoff() + def handleKeepalive(self): + base_version_number=self.request_version.split("/",1)[1] + version_number = base_version_number.split(".") + version_number = int(version_number[0]), int(version_number[1]) + connection_header = self.headers.get("Connection", "").lower() + if version_number == (1,0): + if connection_header == "keepalive": + self.close_connection = 0 + else: + self.close_connection = 1 + elif version_number == (1,1): + if connection_header == "close": + self.close_connection=1 + else: + self.close_connection=0 + else: + self.close_connection=1 def do_GET(self): self.serve('GET') def do_POST(self): debian/patches/30_utf8-support.diff0000664000000000000000000002321011646574706014371 0ustar Description: Adds UTF-8 support Author: Sergej Pupykin Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=541850 --- a/ajaxterm.1 +++ b/ajaxterm.1 @@ -44,6 +44,8 @@ .SH AUTHOR Antony Lesuisse +Adopted to UTF-8 by Sergej Pupykin + This manual page was written for the Debian system by Julien Valroff (but may be used by others). --- a/ajaxterm.js +++ b/ajaxterm.js @@ -142,7 +142,16 @@ if (r.readyState==4) { if(r.status==200) { window.clearTimeout(error_timeout); - de=r.responseXML.documentElement; + if(ie) + { + var responseXMLdoc = new ActiveXObject("Microsoft.XMLDOM"); + responseXMLdoc.loadXML(r.responseText); + de = responseXMLdoc.documentElement; + } + else + { + de=r.responseXML.documentElement; + } if(de.tagName=="pre") { if(ie) { Sarissa.updateContentFromNode(de, dterm); @@ -250,7 +259,7 @@ if(k=="+") { queue("%2B"); } else { - queue(escape(k)); + queue(utf8Escape(k)); } } ev.cancelBubble=true; --- a/ajaxterm.py +++ b/ajaxterm.py @@ -21,7 +21,9 @@ # Optional: Add QWeb in sys path sys.path[0:0]=glob.glob('../../python') -import qweb +import qweb, codecs +utf8decoder = codecs.getincrementaldecoder('utf8')() + from socket import gethostname @@ -92,31 +94,14 @@ for i in [i[4] for i in dir(self) if i.startswith('csi_') and len(i)==5]: if not self.csi_seq.has_key(i): self.csi_seq[i]=(getattr(self,'csi_'+i),[1]) - # Init 0-256 to latin1 and html translation table - self.trl1="" - for i in range(256): - if i<32: - self.trl1+=" " - elif i<127 or i>160: - self.trl1+=chr(i) - else: - self.trl1+="?" - self.trhtml="" - for i in range(256): - if i==0x0a or (i>32 and i<127) or i>160: - self.trhtml+=chr(i) - elif i<=32: - self.trhtml+="\xa0" - else: - self.trhtml+="?" - def reset(self,s=""): - self.scr=array.array('i',[0x000700]*(self.width*self.height)) + def reset(self,s=u""): + self.scr=array.array('l',[0x07000000]*(self.width*self.height)) self.st=0 self.sb=self.height-1 self.cx_bak=self.cx=0 self.cy_bak=self.cy=0 self.cl=0 - self.sgr=0x000700 + self.sgr=0x07000000 self.buf="" self.outbuf="" self.last_html="" @@ -127,7 +112,7 @@ self.scr[pos:pos+len(s)]=s def zero(self,y1,x1,y2,x2): w=self.width*(y2-y1)+x2-x1+1 - z=array.array('i',[0x000700]*w) + z=array.array('l',[0x07000000]*w) self.scr[self.width*y1+x1:self.width*y2+x2+1]=z def scroll_up(self,y1,y2): self.poke(y1,0,self.peek(y1+1,0,y2,self.width)) @@ -280,17 +265,17 @@ def csi_m(self,l): for i in l: if i==0 or i==39 or i==49 or i==27: - self.sgr=0x000700 + self.sgr=0x07000000 elif i==1: - self.sgr=(self.sgr|0x000800) + self.sgr=(self.sgr|0x08000000) elif i==7: - self.sgr=0x070000 + self.sgr=0x70000000 elif i>=30 and i<=37: c=i-30 - self.sgr=(self.sgr&0xff08ff)|(c<<8) + self.sgr=(self.sgr&0xf8ffffff)|(c<<24) elif i>=40 and i<=47: c=i-40 - self.sgr=(self.sgr&0x00ffff)|(c<<16) + self.sgr=(self.sgr&0x0fffffff)|(c<<28) # else: # print "CSI sgr ignore",l,i # print 'sgr: %r %x'%(l,self.sgr) @@ -320,12 +305,12 @@ break # if self.buf=='': print "ESC %r\n"%e def write(self,s): - for i in s: + for i in utf8decoder.decode(s): if len(self.buf) or (i in self.esc_seq): - self.buf+=i + self.buf+=chr(ord(i)&255) self.escape() elif i == '\x1b': - self.buf+=i + self.buf+=chr(ord(i)&255) else: self.echo(i) def read(self): @@ -333,35 +318,41 @@ self.outbuf="" return b def dump(self): - r='' + r=u'' for i in self.scr: - r+=chr(i&255) + r+=unichr(i&0xFFFFFF) return r - def dumplatin1(self): - return self.dump().translate(self.trl1) + def dumputf8(self): + return self.dump().encode('utf8') def dumphtml(self,color=1): h=self.height w=self.width r="" - span="" + span=u"" span_bg,span_fg=-1,-1 for i in range(h*w): - q,c=divmod(self.scr[i],256) + q,c=divmod(self.scr[i],256*256*256) if color: - bg,fg=divmod(q,256) + bg,fg=divmod(q,16) + bg &= 0x7 else: bg,fg=0,7 if i==self.cy*w+self.cx: bg,fg=1,7 if (bg!=span_bg or fg!=span_fg or i==h*w-1): if len(span): - r+='%s'%(span_fg,span_bg,cgi.escape(span.translate(self.trhtml))) - span="" + r+='%s'%(span_fg,span_bg,cgi.escape(span.replace(u' ',u'\xa0').encode('utf8'))) + span=u"" span_bg,span_fg=bg,fg - span+=chr(c) + if c == 0: + span+=u' ' + elif c > 0x10000: + span+=u'?' + else: + span+=unichr(c&0xFFFF) if i%w==w-1: - span+='\n' - r='
%s
'%r + span+=u'\n' + r='
%s
'%r if self.last_html==r: return '' else: @@ -369,8 +360,8 @@ # print self return r def __repr__(self): - d=self.dumplatin1() - r="" + d=self.dumputf8() + r=u"" for i in range(self.height): r+="|%s|\n"%d[self.width*i:self.width*(i+1)] return r @@ -432,7 +423,7 @@ elif os.getuid()==0: cmd=['/bin/login'] else: - sys.stdout.write(gethostname() + " login: ") + sys.stdout.write(gethostname() + u" login: ") login=sys.stdin.readline().strip() if re.match('^[0-9A-Za-z-_. ]+$',login): cmd=['ssh'] --- /dev/null +++ b/utf8-escape.js @@ -0,0 +1,80 @@ +var char2hex = new Array( + "%00", "%01", "%02", "%03", "%04", "%05", "%06", "%07", + "%08", "%09", "%0a", "%0b", "%0c", "%0d", "%0e", "%0f", + "%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17", + "%18", "%19", "%1a", "%1b", "%1c", "%1d", "%1e", "%1f", + "%20", "%21", "%22", "%23", "%24", "%25", "%26", "%27", + "%28", "%29", "%2a", "%2b", "%2c", "%2d", "%2e", "%2f", + "%30", "%31", "%32", "%33", "%34", "%35", "%36", "%37", + "%38", "%39", "%3a", "%3b", "%3c", "%3d", "%3e", "%3f", + "%40", "%41", "%42", "%43", "%44", "%45", "%46", "%47", + "%48", "%49", "%4a", "%4b", "%4c", "%4d", "%4e", "%4f", + "%50", "%51", "%52", "%53", "%54", "%55", "%56", "%57", + "%58", "%59", "%5a", "%5b", "%5c", "%5d", "%5e", "%5f", + "%60", "%61", "%62", "%63", "%64", "%65", "%66", "%67", + "%68", "%69", "%6a", "%6b", "%6c", "%6d", "%6e", "%6f", + "%70", "%71", "%72", "%73", "%74", "%75", "%76", "%77", + "%78", "%79", "%7a", "%7b", "%7c", "%7d", "%7e", "%7f", + "%80", "%81", "%82", "%83", "%84", "%85", "%86", "%87", + "%88", "%89", "%8a", "%8b", "%8c", "%8d", "%8e", "%8f", + "%90", "%91", "%92", "%93", "%94", "%95", "%96", "%97", + "%98", "%99", "%9a", "%9b", "%9c", "%9d", "%9e", "%9f", + "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%a7", + "%a8", "%a9", "%aa", "%ab", "%ac", "%ad", "%ae", "%af", + "%b0", "%b1", "%b2", "%b3", "%b4", "%b5", "%b6", "%b7", + "%b8", "%b9", "%ba", "%bb", "%bc", "%bd", "%be", "%bf", + "%c0", "%c1", "%c2", "%c3", "%c4", "%c5", "%c6", "%c7", + "%c8", "%c9", "%ca", "%cb", "%cc", "%cd", "%ce", "%cf", + "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", + "%d8", "%d9", "%da", "%db", "%dc", "%dd", "%de", "%df", + "%e0", "%e1", "%e2", "%e3", "%e4", "%e5", "%e6", "%e7", + "%e8", "%e9", "%ea", "%eb", "%ec", "%ed", "%ee", "%ef", + "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7", + "%f8", "%f9", "%fa", "%fb", "%fc", "%fd", "%fe", "%ff" + ); + +function utf8Escape(s) +{ + var sbuf = ""; + var i; + + var len = s.length; + for (i = 0; i < len; i++) + { + var ch = s.charCodeAt(i); + if( (65 <= ch && ch <= 90) || + (97 <= ch && ch <= 122) || + (48 <= ch && ch <= 57) ) + { + sbuf += String.fromCharCode(ch); + } + else if (ch == 32) + { + sbuf += '+'; + } + else if (ch == 45 || ch == 95 + || ch == 46 || ch == 33 + || ch == 126 || ch == 42 + || ch == 39 || ch == 40 + || ch == 41) + { + sbuf += char2hex[ch]; + } + else if (ch <= 0x007F) + { + sbuf += char2hex[ch]; + } + else if (ch <= 0x07FF) + { + sbuf += char2hex[0xc0 | (ch >> 6)]; + sbuf += char2hex[0x80 | (ch & 0x3F)]; + } + else + { + sbuf += char2hex[0xe0 | (ch >> 12)]; + sbuf += char2hex[0x80 | ((ch >> 6) & 0x3F)]; + sbuf += char2hex[0x80 | (ch & 0x3F)]; + } + } + return sbuf; +} --- a/README.txt +++ b/README.txt @@ -41,7 +41,7 @@ == Documentation and Caveats == - * Ajaxterm only support latin1, if you use Ubuntu or any LANG==en_US.UTF-8 distribution don't forget to "unset LANG". + * Ajaxterm only support utf8. * If run as root ajaxterm will run /bin/login, otherwise it will run ssh localhost. To use an other command use the -c option. --- a/ajaxterm.html +++ b/ajaxterm.html @@ -8,6 +8,7 @@ +