1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  */
9 
10 #include <algorithm>
11 #include <vector>
12 
13 #include <officecfg/Office/Impress.hxx>
14 
15 #include <com/sun/star/container/XNameAccess.hpp>
16 #include <com/sun/star/container/XNameContainer.hpp>
17 #include <com/sun/star/uno/Sequence.hxx>
18 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
19 
20 #include <comphelper/processfactory.hxx>
21 #include <comphelper/configuration.hxx>
22 #include <comphelper/sequence.hxx>
23 #include <sal/log.hxx>
24 #include <vcl/svapp.hxx>
25 #include <osl/socket.hxx>
26 
27 #include <sddll.hxx>
28 
29 #include "DiscoveryService.hxx"
30 #include "Listener.hxx"
31 #include <RemoteServer.hxx>
32 #include "BluetoothServer.hxx"
33 #include "Communicator.hxx"
34 #include "BufferedStreamSocket.hxx"
35 
36 using namespace std;
37 using namespace sd;
38 using namespace ::com::sun::star;
39 using namespace ::com::sun::star::uno;
40 using namespace ::com::sun::star::beans;
41 using namespace ::com::sun::star::container;
42 using namespace ::com::sun::star::lang;
43 using namespace ::osl;
44 using namespace ::comphelper;
45 
46 namespace sd {
47     /**
48      * Used to keep track of clients that have attempted to connect, but haven't
49      * yet been approved.
50      */
51     struct ClientInfoInternal:
52         ClientInfo
53     {
54         BufferedStreamSocket * const mpStreamSocket;
55         OUString const mPin;
56 
ClientInfoInternalsd::ClientInfoInternal57         ClientInfoInternal( const OUString& rName,
58                             BufferedStreamSocket *pSocket,
59                             const OUString& rPin ):
60                 ClientInfo( rName, false ),
61                 mpStreamSocket( pSocket ),
62                 mPin( rPin ) {}
63     };
64 }
65 
RemoteServer()66 RemoteServer::RemoteServer() :
67     Thread( "RemoteServerThread" ),
68     mSocket(),
69     mAvailableClients()
70 {
71     SAL_INFO( "sdremote", "Instantiated RemoteServer" );
72 }
73 
~RemoteServer()74 RemoteServer::~RemoteServer()
75 {
76 }
77 
execute()78 void RemoteServer::execute()
79 {
80     SAL_INFO( "sdremote", "RemoteServer::execute called" );
81     uno::Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext();
82     if (!xContext.is()/* || !officecfg::Office::Common::Misc::ExperimentalMode::get(xContext)*/)
83     {
84         // SAL_INFO("sdremote", "not in experimental mode, disabling TCP server");
85         spServer = nullptr;
86         return;
87     }
88     osl::SocketAddr aAddr( "0.0.0.0", PORT );
89     if ( !mSocket.bind( aAddr ) )
90     {
91         SAL_WARN( "sdremote", "bind failed" << mSocket.getErrorAsString() );
92         spServer = nullptr;
93         return;
94     }
95 
96     if ( !mSocket.listen(3) )
97     {
98         SAL_WARN( "sdremote", "listen failed" << mSocket.getErrorAsString() );
99         spServer = nullptr;
100         return;
101     }
102     while ( true )
103     {
104         StreamSocket aSocket;
105         SAL_INFO( "sdremote", "waiting on accept" );
106         if ( mSocket.acceptConnection( aSocket ) == osl_Socket_Error )
107         {
108             SAL_WARN( "sdremote", "accept failed" << mSocket.getErrorAsString() );
109             spServer = nullptr;
110             return; // Closed, or other issue.
111         }
112         BufferedStreamSocket *pSocket = new BufferedStreamSocket( aSocket);
113         OString aLine;
114         if ( pSocket->readLine( aLine)
115             && aLine == "LO_SERVER_CLIENT_PAIR"
116             && pSocket->readLine( aLine ) )
117         {
118             OString aName( aLine );
119 
120             if ( ! pSocket->readLine( aLine ) )
121             {
122                 delete pSocket;
123                 continue;
124             }
125             OString aPin( aLine );
126 
127             SocketAddr aClientAddr;
128             pSocket->getPeerAddr( aClientAddr );
129 
130             MutexGuard aGuard( sDataMutex );
131             std::shared_ptr< ClientInfoInternal > pClient(
132                 new ClientInfoInternal(
133                     OStringToOUString( aName, RTL_TEXTENCODING_UTF8 ),
134                     pSocket, OStringToOUString( aPin, RTL_TEXTENCODING_UTF8 ) ) );
135             mAvailableClients.push_back( pClient );
136 
137             // Read off any additional non-empty lines
138             // We know that we at least have the empty termination line to read.
139             do
140             {
141                 pSocket->readLine( aLine );
142             }
143             while ( aLine.getLength() > 0 );
144 
145             // Check if we already have this server.
146             Reference< XNameAccess > const xConfig = officecfg::Office::Impress::Misc::AuthorisedRemotes::get();
147             const Sequence< OUString > aNames = xConfig->getElementNames();
148             bool aFound = false;
149             for ( const auto& rName : aNames )
150             {
151                 if ( rName == pClient->mName )
152                 {
153                     Reference<XNameAccess> xSetItem( xConfig->getByName(rName), UNO_QUERY );
154                     Any axPin(xSetItem->getByName("PIN"));
155                     OUString sPin;
156                     axPin >>= sPin;
157 
158                     if ( sPin == pClient->mPin ) {
159                         SAL_INFO( "sdremote", "client found on validated list -- connecting" );
160                         connectClient( pClient, sPin );
161                         aFound = true;
162                         break;
163                     }
164                 }
165             }
166             // Pin not found so inform the client.
167             if ( !aFound )
168             {
169                 SAL_INFO( "sdremote", "client not found on validated list" );
170                 pSocket->write( "LO_SERVER_VALIDATING_PIN\n\n",
171                             strlen( "LO_SERVER_VALIDATING_PIN\n\n" ) );
172             }
173         } else {
174             SAL_INFO( "sdremote", "client failed to send LO_SERVER_CLIENT_PAIR, ignoring" );
175             delete pSocket;
176         }
177     }
178     SAL_INFO( "sdremote", "shutting down RemoteServer" );
179     spServer = nullptr; // Object is destroyed when Thread::execute() ends.
180 }
181 
182 RemoteServer *sd::RemoteServer::spServer = nullptr;
183 ::osl::Mutex sd::RemoteServer::sDataMutex;
184 ::std::vector<Communicator*> sd::RemoteServer::sCommunicators;
185 
setup()186 void RemoteServer::setup()
187 {
188     if (spServer)
189         return;
190 
191     spServer = new RemoteServer();
192     spServer->launch();
193 
194 #ifdef ENABLE_SDREMOTE_BLUETOOTH
195     sd::BluetoothServer::setup( &sCommunicators );
196 #endif
197 }
198 
presentationStarted(const css::uno::Reference<css::presentation::XSlideShowController> & rController)199 void RemoteServer::presentationStarted( const css::uno::Reference<
200                 css::presentation::XSlideShowController > &rController )
201 {
202     if ( !spServer )
203         return;
204     MutexGuard aGuard( sDataMutex );
205     for ( const auto& rpCommunicator : sCommunicators )
206     {
207         rpCommunicator->presentationStarted( rController );
208     }
209 }
presentationStopped()210 void RemoteServer::presentationStopped()
211 {
212     if ( !spServer )
213         return;
214     MutexGuard aGuard( sDataMutex );
215     for ( const auto& rpCommunicator : sCommunicators )
216     {
217         rpCommunicator->disposeListener();
218     }
219 }
220 
removeCommunicator(Communicator const * mCommunicator)221 void RemoteServer::removeCommunicator( Communicator const * mCommunicator )
222 {
223     if ( !spServer )
224         return;
225     MutexGuard aGuard( sDataMutex );
226     auto aIt = std::find(sCommunicators.begin(), sCommunicators.end(), mCommunicator);
227     if (aIt != sCommunicators.end())
228         sCommunicators.erase( aIt );
229 }
230 
getClients()231 std::vector< std::shared_ptr< ClientInfo > > RemoteServer::getClients()
232 {
233     SAL_INFO( "sdremote", "RemoteServer::getClients() called" );
234     std::vector< std::shared_ptr< ClientInfo > > aClients;
235     if ( spServer )
236     {
237         MutexGuard aGuard( sDataMutex );
238         aClients.assign( spServer->mAvailableClients.begin(),
239                          spServer->mAvailableClients.end() );
240     }
241     else
242     {
243         SAL_INFO( "sdremote", "No remote server instance => no remote clients" );
244     }
245     // We also need to provide authorised clients (no matter whether or not
246     // they are actually available), so that they can be de-authorised if
247     // necessary. We specifically want these to be at the end of the list
248     // since the user is more likely to be trying to connect a new remote
249     // than removing an existing remote.
250     // We can also be sure that pre-authorised clients will not be on the
251     // available clients list, as they get automatically connected if seen.
252     // TODO: we should probably add some sort of extra labelling to mark
253     // authorised AND connected client.
254     Reference< XNameAccess > const xConfig = officecfg::Office::Impress::Misc::AuthorisedRemotes::get();
255     Sequence< OUString > aNames = xConfig->getElementNames();
256     std::transform(aNames.begin(), aNames.end(), std::back_inserter(aClients),
257         [](const OUString& rName) -> std::shared_ptr<ClientInfo> {
258             return std::make_shared<ClientInfo>(rName, true); });
259 
260     return aClients;
261 }
262 
connectClient(const std::shared_ptr<ClientInfo> & pClient,const OUString & aPin)263 bool RemoteServer::connectClient( const std::shared_ptr< ClientInfo >& pClient, const OUString& aPin )
264 {
265     SAL_INFO( "sdremote", "RemoteServer::connectClient called" );
266     if ( !spServer )
267         return false;
268 
269     ClientInfoInternal* apClient = dynamic_cast< ClientInfoInternal* >( pClient.get() );
270     if ( !apClient )
271     // could happen if we try to "connect" an already authorised client
272     {
273         return false;
274     }
275 
276     if ( apClient->mPin == aPin )
277     {
278         // Save in settings first
279         std::shared_ptr< ConfigurationChanges > aChanges = ConfigurationChanges::create();
280         Reference< XNameContainer > const xConfig = officecfg::Office::Impress::Misc::AuthorisedRemotes::get( aChanges );
281 
282         Reference<XSingleServiceFactory> xChildFactory (
283             xConfig, UNO_QUERY);
284         Reference<XNameReplace> xChild( xChildFactory->createInstance(), UNO_QUERY);
285         Any aValue;
286         if (xChild.is())
287         {
288             // Check whether the client is already saved
289             Sequence< OUString > aNames = xConfig->getElementNames();
290             if (comphelper::findValue(aNames, apClient->mName) != -1)
291                 xConfig->replaceByName( apClient->mName, makeAny( xChild ) );
292             else
293                 xConfig->insertByName( apClient->mName, makeAny( xChild ) );
294             aValue <<= apClient->mPin;
295             xChild->replaceByName("PIN", aValue);
296             aChanges->commit();
297         }
298 
299         Communicator* pCommunicator = new Communicator( std::unique_ptr<IBluetoothSocket>(apClient->mpStreamSocket) );
300         MutexGuard aGuard( sDataMutex );
301 
302         sCommunicators.push_back( pCommunicator );
303 
304         auto aIt = std::find(spServer->mAvailableClients.begin(), spServer->mAvailableClients.end(), pClient);
305         if (aIt != spServer->mAvailableClients.end())
306             spServer->mAvailableClients.erase( aIt );
307         pCommunicator->launch();
308         return true;
309     }
310     else
311     {
312         return false;
313     }
314 }
315 
deauthoriseClient(const std::shared_ptr<ClientInfo> & pClient)316 void RemoteServer::deauthoriseClient( const std::shared_ptr< ClientInfo >& pClient )
317 {
318     // TODO: we probably want to forcefully disconnect at this point too?
319     // But possibly via a separate function to allow just disconnecting from
320     // the UI.
321 
322     SAL_INFO( "sdremote", "RemoteServer::deauthoriseClient called" );
323 
324     if ( !pClient->mbIsAlreadyAuthorised )
325     // We can't remove unauthorised clients from the authorised list...
326     {
327         return;
328     }
329 
330     std::shared_ptr< ConfigurationChanges > aChanges = ConfigurationChanges::create();
331     Reference< XNameContainer > const xConfig =
332         officecfg::Office::Impress::Misc::AuthorisedRemotes::get( aChanges );
333 
334     xConfig->removeByName( pClient->mName );
335     aChanges->commit();
336 }
337 
RegisterRemotes()338 void SdDLL::RegisterRemotes()
339 {
340     SAL_INFO( "sdremote", "SdDLL::RegisterRemotes called" );
341 
342     // The remote server is likely of no use in headless mode. And as only
343     // one instance of the server can actually own the appropriate ports its
344     // probably best to not even try to do so from our headless instance
345     // (i.e. as to avoid blocking expected usage).
346     // It could perhaps be argued that we would still need the remote
347     // server for tiled rendering of presentations, but even then this
348     // implementation would not be of much use, i.e. would be controlling
349     // the purely imaginary headless presentation -- instead we'd need
350     // to have some sort of mechanism of plugging in our tiled rendering
351     // client to be controlled by the remote server, or provide an
352     // alternative implementation.
353     if ( Application::IsHeadlessModeEnabled() )
354         return;
355 
356     uno::Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext();
357     if ( xContext.is()  && !officecfg::Office::Impress::Misc::Start::EnableSdremote::get( xContext ) )
358         return;
359 
360     sd::RemoteServer::setup();
361     sd::DiscoveryService::setup();
362 }
363 
ensureDiscoverable()364 void RemoteServer::ensureDiscoverable()
365 {
366     // FIXME: we could also enable listening on our WiFi
367     // socket here to significantly reduce the attack surface.
368 #ifdef ENABLE_SDREMOTE_BLUETOOTH
369     BluetoothServer::ensureDiscoverable();
370 #endif
371 }
372 
restoreDiscoverable()373 void RemoteServer::restoreDiscoverable()
374 {
375 #ifdef ENABLE_SDREMOTE_BLUETOOTH
376     BluetoothServer::restoreDiscoverable();
377 #endif
378 }
379 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
380