1 /*
2    BAREOS® - Backup Archiving REcovery Open Sourced
3 
4    Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
5    Copyright (C) 2014-2018 Bareos GmbH & Co. KG
6 
7    This program is Free Software; you can redistribute it and/or
8    modify it under the terms of version three of the GNU Affero General Public
9    License as published by the Free Software Foundation and included
10    in the file LICENSE.
11 
12    This program is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15    Affero General Public License for more details.
16 
17    You should have received a copy of the GNU Affero General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20    02110-1301, USA.
21 */
22 /*
23  * Kern Sibbald, August MM
24  * Extracted from other source files by Marco van Wieringen, October 2014
25  */
26 /**
27  * @file
28  * This file handles external connections made to the director.
29  */
30 
31 #include "include/bareos.h"
32 #include "dird.h"
33 #include "dird/dird_globals.h"
34 #include "dird/fd_cmds.h"
35 #include "dird/ua_server.h"
36 #include "lib/berrno.h"
37 #include "lib/bnet_server_tcp.h"
38 #include "lib/thread_list.h"
39 #include "lib/thread_specific_data.h"
40 #include "lib/try_tls_handshake_as_a_server.h"
41 
42 #include <atomic>
43 
44 namespace directordaemon {
45 
46 static char hello_client_with_version[] =
47     "Hello Client %127s FdProtocolVersion=%d calling";
48 
49 static char hello_client[] = "Hello Client %127s calling";
50 
51 /* Global variables */
52 static ThreadList thread_list;
53 static alist* sock_fds = NULL;
54 static pthread_t tcp_server_tid;
55 static ConnectionPool* client_connections = NULL;
56 
57 static std::atomic<BnetServerState> server_state(BnetServerState::kUndefined);
58 
59 struct s_addr_port {
60   char* addr;
61   char* port;
62 };
63 
64 /*
65  * Sanity check for the lengths of the Hello messages.
66  */
67 #define MIN_MSG_LEN 15
68 #define MAX_MSG_LEN (int)sizeof(name) + 25
69 
get_client_connections()70 ConnectionPool* get_client_connections() { return client_connections; }
71 
HandleConnectionRequest(ConfigurationParser * config,void * arg)72 static void* HandleConnectionRequest(ConfigurationParser* config, void* arg)
73 {
74   BareosSocket* bs = (BareosSocket*)arg;
75   char name[MAX_NAME_LENGTH];
76   char tbuf[MAX_TIME_LENGTH];
77   int fd_protocol_version = 0;
78 
79   if (!TryTlsHandshakeAsAServer(bs, config)) {
80     bs->signal(BNET_TERMINATE);
81     bs->close();
82     delete bs;
83     return nullptr;
84   }
85 
86   if (bs->recv() <= 0) {
87     Emsg1(M_ERROR, 0, _("Connection request from %s failed.\n"), bs->who());
88     Bmicrosleep(5, 0); /* make user wait 5 seconds */
89     bs->signal(BNET_TERMINATE);
90     bs->close();
91     delete bs;
92     return nullptr;
93   }
94 
95   /*
96    * Do a sanity check on the message received
97    */
98   if (bs->message_length < MIN_MSG_LEN || bs->message_length > MAX_MSG_LEN) {
99     Dmsg1(000, "<filed: %s", bs->msg);
100     Emsg2(M_ERROR, 0, _("Invalid connection from %s. Len=%d\n"), bs->who(),
101           bs->message_length);
102     Bmicrosleep(5, 0); /* make user wait 5 seconds */
103     bs->signal(BNET_TERMINATE);
104     bs->close();
105     delete bs;
106     return nullptr;
107   }
108 
109   Dmsg1(110, "Conn: %s", bs->msg);
110 
111   /*
112    * See if this is a File daemon connection. If so call FD handler.
113    */
114   if ((sscanf(bs->msg, hello_client_with_version, name, &fd_protocol_version) ==
115        2) ||
116       (sscanf(bs->msg, hello_client, name) == 1)) {
117     Dmsg1(110, "Got a FD connection at %s\n",
118           bstrftimes(tbuf, sizeof(tbuf), (utime_t)time(NULL)));
119     return HandleFiledConnection(client_connections, bs, name,
120                                  fd_protocol_version);
121   }
122   return HandleUserAgentClientRequest(bs);
123 }
124 
UserAgentShutdownCallback(void * bsock)125 static void* UserAgentShutdownCallback(void* bsock)
126 {
127   if (bsock) {
128     BareosSocket* b = reinterpret_cast<BareosSocket*>(bsock);
129     b->SetTerminated();
130   }
131   return nullptr;
132 }
133 
connect_thread(void * arg)134 extern "C" void* connect_thread(void* arg)
135 {
136   SetJcrInThreadSpecificData(nullptr);
137 
138   /*
139    * Permit MaxConnections connections.
140    */
141   sock_fds = new alist(10, not_owned_by_alist);
142   BnetThreadServerTcp((dlist*)arg, me->MaxConnections, sock_fds, thread_list,
143                       me->nokeepalive, HandleConnectionRequest, my_config,
144                       &server_state, UserAgentShutdownCallback);
145 
146   return NULL;
147 }
148 #include <errno.h>
149 /**
150  * Called here by Director daemon to start UA (user agent)
151  * command thread. This routine creates the thread and then
152  * returns.
153  */
StartSocketServer(dlist * addrs)154 bool StartSocketServer(dlist* addrs)
155 {
156   int status;
157 
158   if (client_connections == nullptr) {
159     client_connections = new ConnectionPool();
160   }
161 
162   server_state.store(BnetServerState::kUndefined);
163 
164   if ((status = pthread_create(&tcp_server_tid, nullptr, connect_thread,
165                                (void*)addrs)) != 0) {
166     BErrNo be;
167     Emsg1(M_ABORT, 0, _("Cannot create UA thread: %s\n"), be.bstrerror(status));
168   }
169 
170   int tries = 200; /* consider bind() tries in BnetThreadServerTcp */
171   int wait_ms = 100;
172   do {
173     Bmicrosleep(0, wait_ms * 1000);
174     if (server_state.load() != BnetServerState::kUndefined) { break; }
175   } while (--tries);
176 
177   if (server_state != BnetServerState::kStarted) {
178     if (client_connections) {
179       delete (client_connections);
180       client_connections = nullptr;
181     }
182     return false;
183   }
184   return true;
185 }
186 
StopSocketServer()187 void StopSocketServer()
188 {
189   if (sock_fds) {
190     BnetStopAndWaitForThreadServerTcp(tcp_server_tid);
191     delete sock_fds;
192     sock_fds = nullptr;
193   }
194   if (client_connections) {
195     delete (client_connections);
196     client_connections = nullptr;
197   }
198 }
199 } /* namespace directordaemon */
200