1
0
mirror of https://github.com/dkmstr/openuds.git synced 2025-01-10 01:17:59 +03:00

Added support for wallpaper on RDP if desired (all all user xperience in fact)

This commit is contained in:
Adolfo Gómez 2014-05-29 13:30:23 +00:00
parent 30fa98216e
commit 4b5f21b30e
4 changed files with 123 additions and 100 deletions

View File

@ -4,27 +4,27 @@
# Copyright (c) 2012 Virtual Cable S.L.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
@ -52,19 +52,20 @@ class RDPTransport(Transport):
typeName = _('RDP Transport (direct)')
typeType = 'RDPTransport'
typeDescription = _('RDP Transport for direct connection')
iconFile = 'rdp.png'
iconFile = 'rdp.png'
needsJava = True # If this transport needs java for rendering
useEmptyCreds = gui.CheckBoxField(label = _('Empty creds'), order = 1, tooltip = _('If checked, the credentials used to connect will be emtpy'))
fixedName = gui.TextField(label=_('Username'), order = 2, tooltip = _('If not empty, this username will be always used as credential'))
fixedPassword = gui.PasswordField(label=_('Password'), order = 3, tooltip = _('If not empty, this password will be always used as credential'))
fixedDomain = gui.TextField(label=_('Domain'), order = 4, tooltip = _('If not empty, this domain will be always used as credential (used as DOMAIN\\user)'))
allowSmartcards = gui.CheckBoxField(label = _('Allow Smartcards'), order = 5, tooltip = _('If checked, this transport will allow the use of smartcards'))
allowPrinters = gui.CheckBoxField(label = _('Allow Printers'), order = 6, tooltip = _('If checked, this transport will allow the use of user printers'))
allowDrives = gui.CheckBoxField(label = _('Allow Drives'), order = 7, tooltip = _('If checked, this transport will allow the use of user drives'))
allowSerials = gui.CheckBoxField(label = _('Allow Serials'), order = 8, tooltip = _('If checked, this transport will allow the use of user serial ports'))
def __init__(self, environment, values = None):
useEmptyCreds = gui.CheckBoxField(label=_('Empty creds'), order=1, tooltip=_('If checked, the credentials used to connect will be emtpy'))
fixedName = gui.TextField(label=_('Username'), order=2, tooltip=_('If not empty, this username will be always used as credential'))
fixedPassword = gui.PasswordField(label=_('Password'), order=3, tooltip=_('If not empty, this password will be always used as credential'))
fixedDomain = gui.TextField(label=_('Domain'), order=4, tooltip=_('If not empty, this domain will be always used as credential (used as DOMAIN\\user)'))
allowSmartcards = gui.CheckBoxField(label=_('Allow Smartcards'), order=5, tooltip=_('If checked, this transport will allow the use of smartcards'))
allowPrinters = gui.CheckBoxField(label=_('Allow Printers'), order=6, tooltip=_('If checked, this transport will allow the use of user printers'))
allowDrives = gui.CheckBoxField(label=_('Allow Drives'), order=7, tooltip=_('If checked, this transport will allow the use of user drives'))
allowSerials = gui.CheckBoxField(label=_('Allow Serials'), order=8, tooltip=_('If checked, this transport will allow the use of user serial ports'))
wallpaper = gui.CheckBoxField(label=_('Show wallpaper'), order=9, tooltip=_('If checked, the wallpaper and themes will be shown on machine (better user experience, more bandwidth)'))
def __init__(self, environment, values=None):
super(RDPTransport, self).__init__(environment, values)
if values != None:
self._useEmptyCreds = gui.strToBool(values['useEmptyCreds'])
@ -75,6 +76,7 @@ class RDPTransport(Transport):
self._allowPrinters = gui.strToBool(values['allowPrinters'])
self._allowDrives = gui.strToBool(values['allowDrives'])
self._allowSerials = gui.strToBool(values['allowSerials'])
self._wallPaper = gui.strToBool(values['wallpaper'])
else:
self._useEmptyCreds = False
self._fixedName = ''
@ -84,32 +86,40 @@ class RDPTransport(Transport):
self._allowPrinters = False
self._allowDrives = False
self._allowSerials = False
self._wallPaper = False
def marshal(self):
'''
Serializes the transport data so we can store it in database
'''
return str.join( '\t', [ 'v1', gui.boolToStr(self._useEmptyCreds), gui.boolToStr(self._allowSmartcards), gui.boolToStr(self._allowPrinters),
gui.boolToStr(self._allowDrives), gui.boolToStr(self._allowSerials),
self._fixedName, self._fixedPassword, self._fixedDomain ] )
return str.join('\t', [ 'v2', gui.boolToStr(self._useEmptyCreds), gui.boolToStr(self._allowSmartcards), gui.boolToStr(self._allowPrinters),
gui.boolToStr(self._allowDrives), gui.boolToStr(self._allowSerials), gui.boolToStr(self._wallPaper),
self._fixedName, self._fixedPassword, self._fixedDomain ])
def unmarshal(self, str_):
data = str_.split('\t')
if data[0] == 'v1':
if data[0] in ('v1', 'v2'):
self._useEmptyCreds = gui.strToBool(data[1])
self._allowSmartcards = gui.strToBool(data[2])
self._allowPrinters = gui.strToBool(data[3])
self._allowDrives = gui.strToBool(data[4])
self._allowSerials = gui.strToBool(data[5])
self._fixedName = data[6]
self._fixedPassword = data[7]
self._fixedDomain = data[8]
if data[0] == 'v1':
self._wallPaper = False
i = 0
elif data[0] == 'v2':
self._wallPaper = gui.strToBool(data[6])
i = 1
self._fixedName = data[6 + i]
self._fixedPassword = data[7 + i]
self._fixedDomain = data[8 + i]
def valuesDict(self):
return { 'allowSmartcards' : gui.boolToStr(self._allowSmartcards), 'allowPrinters' : gui.boolToStr(self._allowPrinters),
'allowDrives': gui.boolToStr(self._allowDrives), 'allowSerials': gui.boolToStr(self._allowSerials),
'fixedName' : self._fixedName, 'fixedPassword' : self._fixedPassword, 'fixedDomain' : self._fixedDomain,
'useEmptyCreds' : gui.boolToStr(self._useEmptyCreds) }
return { 'allowSmartcards' : gui.boolToStr(self._allowSmartcards), 'allowPrinters' : gui.boolToStr(self._allowPrinters),
'allowDrives': gui.boolToStr(self._allowDrives), 'allowSerials': gui.boolToStr(self._allowSerials),
'fixedName' : self._fixedName, 'fixedPassword' : self._fixedPassword, 'fixedDomain' : self._fixedDomain,
'useEmptyCreds' : gui.boolToStr(self._useEmptyCreds), 'wallpaper': self._wallPaper }
def isAvailableFor(self, ip):
'''
@ -126,18 +136,18 @@ class RDPTransport(Transport):
else:
self.cache().put(ip, 'N', READY_CACHE_TIMEOUT)
return ready == 'Y'
def getConnectionInfo(self, service, user, password):
from uds.core.transports import protocols
username = user.getUsernameForAuth()
proc = username.split('@')
if len(proc) > 1:
domain = proc[1]
else:
domain = ''
username = proc[0]
if self._fixedName is not '':
username = self._fixedName
@ -146,53 +156,53 @@ class RDPTransport(Transport):
if self._fixedDomain is not '':
domain = self._fixedDomain;
if self._useEmptyCreds is True:
username, password, domain = '','',''
username, password, domain = '', '', ''
username, password = service.processUserPassword(username, password)
return {'protocol': protocols.RDP, 'username': username, 'password': password, 'domain': domain}
def renderForHtml(self, userService, idUserService, idTransport, ip, os, user, password):
return {'protocol': protocols.RDP, 'username': username, 'password': password, 'domain': domain}
def renderForHtml(self, userService, idUserService, idTransport, ip, os, user, password):
# We use helper to keep this clean
username = user.getUsernameForAuth()
prefs = user.prefs('rdp')
if self._fixedName is not '':
username = self._fixedName
proc = username.split('@')
if len(proc) > 1:
domain = proc[1]
else:
domain = ''
username = proc[0]
if self._fixedPassword is not '':
password = self._fixedPassword
if self._fixedDomain is not '':
domain = self._fixedDomain;
if self._useEmptyCreds is True:
username, password, domain = '','',''
username, password, domain = '', '', ''
if domain != '':
if domain.find('.') == -1: # Dotter domain form
if domain.find('.') == -1: # Dotter domain form
username = username + '@' + domain
domain = ''
width, height = CommonPrefs.getWidthHeight(prefs)
depth = CommonPrefs.getDepth(prefs)
# Extra data
extra = { 'width': width, 'height' : height, 'depth' : depth,
'printers' : self._allowPrinters, 'smartcards' : self._allowSmartcards,
'drives' : self._allowDrives, 'serials' : self._allowSerials, 'compression':True }
extra = { 'width': width, 'height' : height, 'depth' : depth,
'printers' : self._allowPrinters, 'smartcards' : self._allowSmartcards,
'drives' : self._allowDrives, 'serials' : self._allowSerials, 'compression':True,
'wallpaper': self._wallPaper }
# Fix username/password acording to os manager
username, password = userService.processUserPassword(username, password)
return generateHtmlForRdp(self, idUserService, idTransport, os, ip, '3389', username, password, domain, extra)
def getHtmlComponent(self, id, os, componentId):
# We use helper to keep this clean
return getHtmlComponent(self.__module__, componentId)

View File

@ -67,6 +67,7 @@ class TSRDPTransport(Transport):
allowPrinters = gui.CheckBoxField(label=_('Allow Printers'), order=8, tooltip=_('If checked, this transport will allow the use of user printers'))
allowDrives = gui.CheckBoxField(label=_('Allow Drives'), order=9, tooltip=_('If checked, this transport will allow the use of user drives'))
allowSerials = gui.CheckBoxField(label=_('Allow Serials'), order=10, tooltip=_('If checked, this transport will allow the use of user serial ports'))
wallpaper = gui.CheckBoxField(label=_('Show wallpaper'), order=11, tooltip=_('If checked, the wallpaper and themes will be shown on machine (better user experience, more bandwidth)'))
def __init__(self, environment, values=None):
super(TSRDPTransport, self).__init__(environment, values)
@ -83,7 +84,7 @@ class TSRDPTransport(Transport):
self._allowPrinters = gui.strToBool(values['allowPrinters'])
self._allowDrives = gui.strToBool(values['allowDrives'])
self._allowSerials = gui.strToBool(values['allowSerials'])
self._wallPaper = gui.strToBool(values['wallpaper'])
else:
self._tunnelServer = ''
self._tunnelCheckServer = ''
@ -95,35 +96,43 @@ class TSRDPTransport(Transport):
self._allowPrinters = False
self._allowDrives = False
self._allowSerials = False
self._wallPaper = False
def marshal(self):
'''
Serializes the transport data so we can store it in database
'''
return str.join('\t', [ 'v1', gui.boolToStr(self._useEmptyCreds), gui.boolToStr(self._allowSmartcards), gui.boolToStr(self._allowPrinters),
gui.boolToStr(self._allowDrives), gui.boolToStr(self._allowSerials),
return str.join('\t', [ 'v2', gui.boolToStr(self._useEmptyCreds), gui.boolToStr(self._allowSmartcards), gui.boolToStr(self._allowPrinters),
gui.boolToStr(self._allowDrives), gui.boolToStr(self._allowSerials), gui.boolToStr(self._wallPaper),
self._fixedName, self._fixedPassword, self._fixedDomain, self._tunnelServer, self._tunnelCheckServer ])
def unmarshal(self, str_):
data = str_.split('\t')
if data[0] == 'v1':
if data[0] in ('v1', 'v2'):
self._useEmptyCreds = gui.strToBool(data[1])
self._allowSmartcards = gui.strToBool(data[2])
self._allowPrinters = gui.strToBool(data[3])
self._allowDrives = gui.strToBool(data[4])
self._allowSerials = gui.strToBool(data[5])
self._fixedName = data[6]
self._fixedPassword = data[7]
self._fixedDomain = data[8]
self._tunnelServer = data[9]
self._tunnelCheckServer = data[10]
if data[0] == 'v1':
self._wallPaper = False
i = 0
elif data[0] == 'v2':
self._wallPaper = gui.strToBool(data[6])
i = 1
self._fixedName = data[6 + i]
self._fixedPassword = data[7 + i]
self._fixedDomain = data[8 + i]
self._tunnelServer = data[9 + i]
self._tunnelCheckServer = data[10 + i]
def valuesDict(self):
return { 'allowSmartcards' : gui.boolToStr(self._allowSmartcards), 'allowPrinters' : gui.boolToStr(self._allowPrinters),
'allowDrives': gui.boolToStr(self._allowDrives), 'allowSerials': gui.boolToStr(self._allowSerials),
'fixedName' : self._fixedName, 'fixedPassword' : self._fixedPassword, 'fixedDomain' : self._fixedDomain,
'useEmptyCreds' : gui.boolToStr(self._useEmptyCreds), 'tunnelServer' : self._tunnelServer,
'tunnelCheckServer' : self._tunnelCheckServer }
'tunnelCheckServer' : self._tunnelCheckServer, 'wallpaper': self._wallPaper }
def isAvailableFor(self, ip):
'''
@ -185,7 +194,7 @@ class TSRDPTransport(Transport):
extra = { 'width': width, 'height' : height, 'depth' : depth,
'printers' : self._allowPrinters, 'smartcards' : self._allowSmartcards,
'drives' : self._allowDrives, 'serials' : self._allowSerials,
'tun': tun, 'compression':True }
'tun': tun, 'compression':True, 'wallpaper': self._wallPaper }
# Fix username/password acording to os manager
username, password = userService.processUserPassword(username, password)

View File

@ -4,27 +4,27 @@
# Copyright (c) 2012 Virtual Cable S.L.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
@ -46,15 +46,15 @@ def scramble(data):
res = []
n = 0x32
for c in data[::-1]:
res.append( chr(ord(c) ^ n) )
res.append(chr(ord(c) ^ n))
n = (n + ord(c)) & 0xFF
return "".join(res).encode('hex')
def generateHtmlForRdp(transport, idUserService, idTransport, os, ip, port, user, password, domain, extra):
isMac = os['OS'] == OsDetector.Macintosh
applet = reverse('uds.web.views.transcomp', kwargs = { 'idTransport' : idTransport, 'componentId' : '1' })
applet = reverse('uds.web.views.transcomp', kwargs={ 'idTransport' : idTransport, 'componentId' : '1' })
logger.debug('Applet: {0}'.format(applet))
# Gets the codebase, simply remove last char from applet
codebase = applet[:-1]
@ -68,29 +68,33 @@ def generateHtmlForRdp(transport, idUserService, idTransport, os, ip, port, user
'pr:' + (extra['printers'] and '1' or '0'),
'se:' + (extra['serials'] and '1' or '0'),
'dr:' + (extra['drives'] and '1' or '0'),
'au:' + '1', # Audio, 0 do not play, 1 play
'au:' + '1', # Audio, 0 do not play, 1 play
'w:' + str(extra['width']),
'h:' + str(extra['height']),
'c:' + str(extra['depth']),
'cr:' + (extra['compression'] and '1' or '0'),
'is:' + idUserService
'is:' + idUserService,
'sw:' + (extra['wallpaper'] and '1' or '0'),
]
logger.debug('Data: {0}'.format(data))
if extra.has_key('tun'):
data.append('tun:' + extra['tun'])
data = scramble('\t'.join(data))
res = '<div id="applet"><applet code="RdpApplet.class" codebase="%s" archive="%s" width="200" height="22"><param name="data" value="%s"/><param name="permissions" value="all-permissions"/></applet></div>' % (codebase, '1', data )
res = '<div id="applet"><applet code="RdpApplet.class" codebase="%s" archive="%s" width="200" height="22"><param name="data" value="%s"/><param name="permissions" value="all-permissions"/></applet></div>' % (codebase, '1', data)
if isMac is True:
res += ('<div><p>' + _('In order to use this service, you should first install CoRD.') + '</p>'
'<p>' + _('You can obtain it from') + ' <a href="http://cord.sourceforge.net/">' + _('CoRD Website') + '</a></p>'
'<p>' + _('You can obtain it from') + ' <a href="http://cord.sourceforge.net/">' + _('CoRD Website') + '</a></p>'
'</div>'
)
return res
return res
def getHtmlComponent(module, componentId):
filesDict = { '1' : ['rdp.jar', 'application/java-archive' ], '2' : ['rdppass.dll', 'application/x-msdos-program' ],
filesDict = { '1' : ['rdp.jar', 'application/java-archive' ], '2' : ['rdppass.dll', 'application/x-msdos-program' ],
'3' : ['launcher.jar', 'application/java-archive'] }
if filesDict.has_key(componentId) == False:
return ['text/plain', 'no component']
fname = os.path.dirname(sys.modules[module].__file__) + '/applet/' + filesDict[componentId][0]
@ -99,4 +103,4 @@ def getHtmlComponent(module, componentId):
f = open(fname, 'rb')
data = f.read()
f.close()
return [ filesDict[componentId][1], data ]
return [ filesDict[componentId][1], data ]