| Index: third_party/twisted_8_1/twisted/conch/unix.py
|
| diff --git a/third_party/twisted_8_1/twisted/conch/unix.py b/third_party/twisted_8_1/twisted/conch/unix.py
|
| deleted file mode 100644
|
| index c1e0675cdaa901b5d6c857f3bd021663160ac75b..0000000000000000000000000000000000000000
|
| --- a/third_party/twisted_8_1/twisted/conch/unix.py
|
| +++ /dev/null
|
| @@ -1,457 +0,0 @@
|
| -# Copyright (c) 2001-2007 Twisted Matrix Laboratories.
|
| -# See LICENSE for details.
|
| -
|
| -from twisted.cred import portal
|
| -from twisted.python import components, log
|
| -from twisted.internet.error import ProcessExitedAlready
|
| -from zope import interface
|
| -from ssh import session, forwarding, filetransfer
|
| -from ssh.filetransfer import FXF_READ, FXF_WRITE, FXF_APPEND, FXF_CREAT, FXF_TRUNC, FXF_EXCL
|
| -from twisted.conch.ls import lsLine
|
| -
|
| -from avatar import ConchUser
|
| -from error import ConchError
|
| -from interfaces import ISession, ISFTPServer, ISFTPFile
|
| -
|
| -import struct, os, time, socket
|
| -import fcntl, tty
|
| -import pwd, grp
|
| -import pty
|
| -import ttymodes
|
| -
|
| -try:
|
| - import utmp
|
| -except ImportError:
|
| - utmp = None
|
| -
|
| -class UnixSSHRealm:
|
| - interface.implements(portal.IRealm)
|
| -
|
| - def requestAvatar(self, username, mind, *interfaces):
|
| - user = UnixConchUser(username)
|
| - return interfaces[0], user, user.logout
|
| -
|
| -
|
| -class UnixConchUser(ConchUser):
|
| -
|
| - def __init__(self, username):
|
| - ConchUser.__init__(self)
|
| - self.username = username
|
| - self.pwdData = pwd.getpwnam(self.username)
|
| - l = [self.pwdData[3]]
|
| - for groupname, password, gid, userlist in grp.getgrall():
|
| - if username in userlist:
|
| - l.append(gid)
|
| - self.otherGroups = l
|
| - self.listeners = {} # dict mapping (interface, port) -> listener
|
| - self.channelLookup.update(
|
| - {"session": session.SSHSession,
|
| - "direct-tcpip": forwarding.openConnectForwardingClient})
|
| -
|
| - self.subsystemLookup.update(
|
| - {"sftp": filetransfer.FileTransferServer})
|
| -
|
| - def getUserGroupId(self):
|
| - return self.pwdData[2:4]
|
| -
|
| - def getOtherGroups(self):
|
| - return self.otherGroups
|
| -
|
| - def getHomeDir(self):
|
| - return self.pwdData[5]
|
| -
|
| - def getShell(self):
|
| - return self.pwdData[6]
|
| -
|
| - def global_tcpip_forward(self, data):
|
| - hostToBind, portToBind = forwarding.unpackGlobal_tcpip_forward(data)
|
| - from twisted.internet import reactor
|
| - try: listener = self._runAsUser(
|
| - reactor.listenTCP, portToBind,
|
| - forwarding.SSHListenForwardingFactory(self.conn,
|
| - (hostToBind, portToBind),
|
| - forwarding.SSHListenServerForwardingChannel),
|
| - interface = hostToBind)
|
| - except:
|
| - return 0
|
| - else:
|
| - self.listeners[(hostToBind, portToBind)] = listener
|
| - if portToBind == 0:
|
| - portToBind = listener.getHost()[2] # the port
|
| - return 1, struct.pack('>L', portToBind)
|
| - else:
|
| - return 1
|
| -
|
| - def global_cancel_tcpip_forward(self, data):
|
| - hostToBind, portToBind = forwarding.unpackGlobal_tcpip_forward(data)
|
| - listener = self.listeners.get((hostToBind, portToBind), None)
|
| - if not listener:
|
| - return 0
|
| - del self.listeners[(hostToBind, portToBind)]
|
| - self._runAsUser(listener.stopListening)
|
| - return 1
|
| -
|
| - def logout(self):
|
| - # remove all listeners
|
| - for listener in self.listeners.itervalues():
|
| - self._runAsUser(listener.stopListening)
|
| - log.msg('avatar %s logging out (%i)' % (self.username, len(self.listeners)))
|
| -
|
| - def _runAsUser(self, f, *args, **kw):
|
| - euid = os.geteuid()
|
| - egid = os.getegid()
|
| - groups = os.getgroups()
|
| - uid, gid = self.getUserGroupId()
|
| - os.setegid(0)
|
| - os.seteuid(0)
|
| - os.setgroups(self.getOtherGroups())
|
| - os.setegid(gid)
|
| - os.seteuid(uid)
|
| - try:
|
| - f = iter(f)
|
| - except TypeError:
|
| - f = [(f, args, kw)]
|
| - try:
|
| - for i in f:
|
| - func = i[0]
|
| - args = len(i)>1 and i[1] or ()
|
| - kw = len(i)>2 and i[2] or {}
|
| - r = func(*args, **kw)
|
| - finally:
|
| - os.setegid(0)
|
| - os.seteuid(0)
|
| - os.setgroups(groups)
|
| - os.setegid(egid)
|
| - os.seteuid(euid)
|
| - return r
|
| -
|
| -class SSHSessionForUnixConchUser:
|
| -
|
| - interface.implements(ISession)
|
| -
|
| - def __init__(self, avatar):
|
| - self.avatar = avatar
|
| - self. environ = {'PATH':'/bin:/usr/bin:/usr/local/bin'}
|
| - self.pty = None
|
| - self.ptyTuple = 0
|
| -
|
| - def addUTMPEntry(self, loggedIn=1):
|
| - if not utmp:
|
| - return
|
| - ipAddress = self.avatar.conn.transport.transport.getPeer().host
|
| - packedIp ,= struct.unpack('L', socket.inet_aton(ipAddress))
|
| - ttyName = self.ptyTuple[2][5:]
|
| - t = time.time()
|
| - t1 = int(t)
|
| - t2 = int((t-t1) * 1e6)
|
| - entry = utmp.UtmpEntry()
|
| - entry.ut_type = loggedIn and utmp.USER_PROCESS or utmp.DEAD_PROCESS
|
| - entry.ut_pid = self.pty.pid
|
| - entry.ut_line = ttyName
|
| - entry.ut_id = ttyName[-4:]
|
| - entry.ut_tv = (t1,t2)
|
| - if loggedIn:
|
| - entry.ut_user = self.avatar.username
|
| - entry.ut_host = socket.gethostbyaddr(ipAddress)[0]
|
| - entry.ut_addr_v6 = (packedIp, 0, 0, 0)
|
| - a = utmp.UtmpRecord(utmp.UTMP_FILE)
|
| - a.pututline(entry)
|
| - a.endutent()
|
| - b = utmp.UtmpRecord(utmp.WTMP_FILE)
|
| - b.pututline(entry)
|
| - b.endutent()
|
| -
|
| -
|
| - def getPty(self, term, windowSize, modes):
|
| - self.environ['TERM'] = term
|
| - self.winSize = windowSize
|
| - self.modes = modes
|
| - master, slave = pty.openpty()
|
| - ttyname = os.ttyname(slave)
|
| - self.environ['SSH_TTY'] = ttyname
|
| - self.ptyTuple = (master, slave, ttyname)
|
| -
|
| - def openShell(self, proto):
|
| - from twisted.internet import reactor
|
| - if not self.ptyTuple: # we didn't get a pty-req
|
| - log.msg('tried to get shell without pty, failing')
|
| - raise ConchError("no pty")
|
| - uid, gid = self.avatar.getUserGroupId()
|
| - homeDir = self.avatar.getHomeDir()
|
| - shell = self.avatar.getShell()
|
| - self.environ['USER'] = self.avatar.username
|
| - self.environ['HOME'] = homeDir
|
| - self.environ['SHELL'] = shell
|
| - shellExec = os.path.basename(shell)
|
| - peer = self.avatar.conn.transport.transport.getPeer()
|
| - host = self.avatar.conn.transport.transport.getHost()
|
| - self.environ['SSH_CLIENT'] = '%s %s %s' % (peer.host, peer.port, host.port)
|
| - self.getPtyOwnership()
|
| - self.pty = reactor.spawnProcess(proto, \
|
| - shell, ['-%s' % shellExec], self.environ, homeDir, uid, gid,
|
| - usePTY = self.ptyTuple)
|
| - self.addUTMPEntry()
|
| - fcntl.ioctl(self.pty.fileno(), tty.TIOCSWINSZ,
|
| - struct.pack('4H', *self.winSize))
|
| - if self.modes:
|
| - self.setModes()
|
| - self.oldWrite = proto.transport.write
|
| - proto.transport.write = self._writeHack
|
| - self.avatar.conn.transport.transport.setTcpNoDelay(1)
|
| -
|
| - def execCommand(self, proto, cmd):
|
| - from twisted.internet import reactor
|
| - uid, gid = self.avatar.getUserGroupId()
|
| - homeDir = self.avatar.getHomeDir()
|
| - shell = self.avatar.getShell() or '/bin/sh'
|
| - command = (shell, '-c', cmd)
|
| - peer = self.avatar.conn.transport.transport.getPeer()
|
| - host = self.avatar.conn.transport.transport.getHost()
|
| - self.environ['SSH_CLIENT'] = '%s %s %s' % (peer.host, peer.port, host.port)
|
| - if self.ptyTuple:
|
| - self.getPtyOwnership()
|
| - self.pty = reactor.spawnProcess(proto, \
|
| - shell, command, self.environ, homeDir,
|
| - uid, gid, usePTY = self.ptyTuple or 0)
|
| - if self.ptyTuple:
|
| - self.addUTMPEntry()
|
| - if self.modes:
|
| - self.setModes()
|
| -# else:
|
| -# tty.setraw(self.pty.pipes[0].fileno(), tty.TCSANOW)
|
| - self.avatar.conn.transport.transport.setTcpNoDelay(1)
|
| -
|
| - def getPtyOwnership(self):
|
| - ttyGid = os.stat(self.ptyTuple[2])[5]
|
| - uid, gid = self.avatar.getUserGroupId()
|
| - euid, egid = os.geteuid(), os.getegid()
|
| - os.setegid(0)
|
| - os.seteuid(0)
|
| - try:
|
| - os.chown(self.ptyTuple[2], uid, ttyGid)
|
| - finally:
|
| - os.setegid(egid)
|
| - os.seteuid(euid)
|
| -
|
| - def setModes(self):
|
| - pty = self.pty
|
| - attr = tty.tcgetattr(pty.fileno())
|
| - for mode, modeValue in self.modes:
|
| - if not ttymodes.TTYMODES.has_key(mode): continue
|
| - ttyMode = ttymodes.TTYMODES[mode]
|
| - if len(ttyMode) == 2: # flag
|
| - flag, ttyAttr = ttyMode
|
| - if not hasattr(tty, ttyAttr): continue
|
| - ttyval = getattr(tty, ttyAttr)
|
| - if modeValue:
|
| - attr[flag] = attr[flag]|ttyval
|
| - else:
|
| - attr[flag] = attr[flag]&~ttyval
|
| - elif ttyMode == 'OSPEED':
|
| - attr[tty.OSPEED] = getattr(tty, 'B%s'%modeValue)
|
| - elif ttyMode == 'ISPEED':
|
| - attr[tty.ISPEED] = getattr(tty, 'B%s'%modeValue)
|
| - else:
|
| - if not hasattr(tty, ttyMode): continue
|
| - ttyval = getattr(tty, ttyMode)
|
| - attr[tty.CC][ttyval] = chr(modeValue)
|
| - tty.tcsetattr(pty.fileno(), tty.TCSANOW, attr)
|
| -
|
| - def eofReceived(self):
|
| - if self.pty:
|
| - self.pty.closeStdin()
|
| -
|
| - def closed(self):
|
| - if self.ptyTuple and os.path.exists(self.ptyTuple[2]):
|
| - ttyGID = os.stat(self.ptyTuple[2])[5]
|
| - os.chown(self.ptyTuple[2], 0, ttyGID)
|
| - if self.pty:
|
| - try:
|
| - self.pty.signalProcess('HUP')
|
| - except (OSError,ProcessExitedAlready):
|
| - pass
|
| - self.pty.loseConnection()
|
| - self.addUTMPEntry(0)
|
| - log.msg('shell closed')
|
| -
|
| - def windowChanged(self, winSize):
|
| - self.winSize = winSize
|
| - fcntl.ioctl(self.pty.fileno(), tty.TIOCSWINSZ,
|
| - struct.pack('4H', *self.winSize))
|
| -
|
| - def _writeHack(self, data):
|
| - """
|
| - Hack to send ignore messages when we aren't echoing.
|
| - """
|
| - if self.pty is not None:
|
| - attr = tty.tcgetattr(self.pty.fileno())[3]
|
| - if not attr & tty.ECHO and attr & tty.ICANON: # no echo
|
| - self.avatar.conn.transport.sendIgnore('\x00'*(8+len(data)))
|
| - self.oldWrite(data)
|
| -
|
| -
|
| -class SFTPServerForUnixConchUser:
|
| -
|
| - interface.implements(ISFTPServer)
|
| -
|
| - def __init__(self, avatar):
|
| - self.avatar = avatar
|
| -
|
| -
|
| - def _setAttrs(self, path, attrs):
|
| - """
|
| - NOTE: this function assumes it runs as the logged-in user:
|
| - i.e. under _runAsUser()
|
| - """
|
| - if attrs.has_key("uid") and attrs.has_key("gid"):
|
| - os.chown(path, attrs["uid"], attrs["gid"])
|
| - if attrs.has_key("permissions"):
|
| - os.chmod(path, attrs["permissions"])
|
| - if attrs.has_key("atime") and attrs.has_key("mtime"):
|
| - os.utime(path, (attrs["atime"], attrs["mtime"]))
|
| -
|
| - def _getAttrs(self, s):
|
| - return {
|
| - "size" : s.st_size,
|
| - "uid" : s.st_uid,
|
| - "gid" : s.st_gid,
|
| - "permissions" : s.st_mode,
|
| - "atime" : int(s.st_atime),
|
| - "mtime" : int(s.st_mtime)
|
| - }
|
| -
|
| - def _absPath(self, path):
|
| - home = self.avatar.getHomeDir()
|
| - return os.path.abspath(os.path.join(home, path))
|
| -
|
| - def gotVersion(self, otherVersion, extData):
|
| - return {}
|
| -
|
| - def openFile(self, filename, flags, attrs):
|
| - return UnixSFTPFile(self, self._absPath(filename), flags, attrs)
|
| -
|
| - def removeFile(self, filename):
|
| - filename = self._absPath(filename)
|
| - return self.avatar._runAsUser(os.remove, filename)
|
| -
|
| - def renameFile(self, oldpath, newpath):
|
| - oldpath = self._absPath(oldpath)
|
| - newpath = self._absPath(newpath)
|
| - return self.avatar._runAsUser(os.rename, oldpath, newpath)
|
| -
|
| - def makeDirectory(self, path, attrs):
|
| - path = self._absPath(path)
|
| - return self.avatar._runAsUser([(os.mkdir, (path,)),
|
| - (self._setAttrs, (path, attrs))])
|
| -
|
| - def removeDirectory(self, path):
|
| - path = self._absPath(path)
|
| - self.avatar._runAsUser(os.rmdir, path)
|
| -
|
| - def openDirectory(self, path):
|
| - return UnixSFTPDirectory(self, self._absPath(path))
|
| -
|
| - def getAttrs(self, path, followLinks):
|
| - path = self._absPath(path)
|
| - if followLinks:
|
| - s = self.avatar._runAsUser(os.stat, path)
|
| - else:
|
| - s = self.avatar._runAsUser(os.lstat, path)
|
| - return self._getAttrs(s)
|
| -
|
| - def setAttrs(self, path, attrs):
|
| - path = self._absPath(path)
|
| - self.avatar._runAsUser(self._setAttrs, path, attrs)
|
| -
|
| - def readLink(self, path):
|
| - path = self._absPath(path)
|
| - return self.avatar._runAsUser(os.readlink, path)
|
| -
|
| - def makeLink(self, linkPath, targetPath):
|
| - linkPath = self._absPath(linkPath)
|
| - targetPath = self._absPath(targetPath)
|
| - return self.avatar._runAsUser(os.symlink, targetPath, linkPath)
|
| -
|
| - def realPath(self, path):
|
| - return os.path.realpath(self._absPath(path))
|
| -
|
| - def extendedRequest(self, extName, extData):
|
| - raise NotImplementedError
|
| -
|
| -class UnixSFTPFile:
|
| -
|
| - interface.implements(ISFTPFile)
|
| -
|
| - def __init__(self, server, filename, flags, attrs):
|
| - self.server = server
|
| - openFlags = 0
|
| - if flags & FXF_READ == FXF_READ and flags & FXF_WRITE == 0:
|
| - openFlags = os.O_RDONLY
|
| - if flags & FXF_WRITE == FXF_WRITE and flags & FXF_READ == 0:
|
| - openFlags = os.O_WRONLY
|
| - if flags & FXF_WRITE == FXF_WRITE and flags & FXF_READ == FXF_READ:
|
| - openFlags = os.O_RDWR
|
| - if flags & FXF_APPEND == FXF_APPEND:
|
| - openFlags |= os.O_APPEND
|
| - if flags & FXF_CREAT == FXF_CREAT:
|
| - openFlags |= os.O_CREAT
|
| - if flags & FXF_TRUNC == FXF_TRUNC:
|
| - openFlags |= os.O_TRUNC
|
| - if flags & FXF_EXCL == FXF_EXCL:
|
| - openFlags |= os.O_EXCL
|
| - if attrs.has_key("permissions"):
|
| - mode = attrs["permissions"]
|
| - del attrs["permissions"]
|
| - else:
|
| - mode = 0777
|
| - fd = server.avatar._runAsUser(os.open, filename, openFlags, mode)
|
| - if attrs:
|
| - server.avatar._runAsUser(server._setAttrs, filename, attrs)
|
| - self.fd = fd
|
| -
|
| - def close(self):
|
| - return self.server.avatar._runAsUser(os.close, self.fd)
|
| -
|
| - def readChunk(self, offset, length):
|
| - return self.server.avatar._runAsUser([ (os.lseek, (self.fd, offset, 0)),
|
| - (os.read, (self.fd, length)) ])
|
| -
|
| - def writeChunk(self, offset, data):
|
| - return self.server.avatar._runAsUser([(os.lseek, (self.fd, offset, 0)),
|
| - (os.write, (self.fd, data))])
|
| -
|
| - def getAttrs(self):
|
| - s = self.server.avatar._runAsUser(os.fstat, self.fd)
|
| - return self.server._getAttrs(s)
|
| -
|
| - def setAttrs(self, attrs):
|
| - raise NotImplementedError
|
| -
|
| -
|
| -class UnixSFTPDirectory:
|
| -
|
| - def __init__(self, server, directory):
|
| - self.server = server
|
| - self.files = server.avatar._runAsUser(os.listdir, directory)
|
| - self.dir = directory
|
| -
|
| - def __iter__(self):
|
| - return self
|
| -
|
| - def next(self):
|
| - try:
|
| - f = self.files.pop(0)
|
| - except IndexError:
|
| - raise StopIteration
|
| - else:
|
| - s = self.server.avatar._runAsUser(os.lstat, os.path.join(self.dir, f))
|
| - longname = lsLine(f, s)
|
| - attrs = self.server._getAttrs(s)
|
| - return (f, longname, attrs)
|
| -
|
| - def close(self):
|
| - self.files = []
|
| -
|
| -
|
| -components.registerAdapter(SFTPServerForUnixConchUser, UnixConchUser, filetransfer.ISFTPServer)
|
| -components.registerAdapter(SSHSessionForUnixConchUser, UnixConchUser, session.ISession)
|
|
|