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