1 /*
2    BAREOS® - Backup Archiving REcovery Open Sourced
3 
4    Copyright (C) 2000-2011 Free Software Foundation Europe e.V.
5    Copyright (C) 2011-2012 Planets Communications B.V.
6    Copyright (C) 2013-2016 Bareos GmbH & Co. KG
7 
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version three of the GNU Affero General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12 
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    Affero General Public License for more details.
17 
18    You should have received a copy of the GNU Affero General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22 */
23 /*
24  * Originally written by Kern Sibbald for inclusion in apcupsd,
25  * but heavily modified for BAREOS
26  */
27 /*
28  * @file
29  * tcp server code
30  */
31 
32 #include "include/bareos.h"
33 #include "lib/alist.h"
34 #include "lib/berrno.h"
35 #include "lib/bnet_server_tcp.h"
36 #include "lib/bsock_tcp.h"
37 #include "lib/bsys.h"
38 #include "lib/thread_list.h"
39 #include "lib/watchdog.h"
40 
41 #include <netinet/in.h>
42 #include <sys/socket.h>
43 #include <stdlib.h>
44 #include <arpa/inet.h>
45 #include <netdb.h>
46 #ifdef HAVE_ARPA_NAMESER_H
47 #include <arpa/nameser.h>
48 #endif
49 #ifdef HAVE_RESOLV_H
50 //#include <resolv.h>
51 #endif
52 
53 #ifdef HAVE_POLL_H
54 #include <poll.h>
55 #elif HAVE_SYS_POLL_H
56 #include <sys/poll.h>
57 #endif
58 #include <atomic>
59 
60 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
61 
62 #ifdef HAVE_LIBWRAP
63 #include "tcpd.h"
64 int allow_severity = LOG_NOTICE;
65 int deny_severity = LOG_WARNING;
66 #endif
67 
68 static std::atomic<bool> quit{false};
69 
70 struct s_sockfd {
71   int fd;
72   int port;
73 };
74 
75 /**
76  * Stop the Threaded Network Server if its realy running in a separate thread.
77  * e.g. set the quit flag and wait for the other thread to exit cleanly.
78  */
BnetStopAndWaitForThreadServerTcp(pthread_t tid)79 void BnetStopAndWaitForThreadServerTcp(pthread_t tid)
80 {
81   Dmsg0(100, "BnetThreadServer: Request Stop\n");
82   quit = true;
83   if (!pthread_equal(tid, pthread_self())) {
84     Dmsg0(100, "BnetThreadServer: Wait until finished\n");
85     pthread_join(tid, nullptr);
86     Dmsg0(100, "BnetThreadServer: finished\n");
87   }
88 }
89 
90 /**
91  * Perform a cleanup for the Threaded Network Server check if there is still
92  * something to do or that the cleanup already took place.
93  */
CleanupBnetThreadServerTcp(alist * sockfds,ThreadList & thread_list)94 static void CleanupBnetThreadServerTcp(alist* sockfds, ThreadList& thread_list)
95 {
96   Dmsg0(100, "CleanupBnetThreadServerTcp: start\n");
97 
98   if (sockfds && !sockfds->empty()) {
99     s_sockfd* fd_ptr = (s_sockfd*)sockfds->first();
100     while (fd_ptr) {
101       close(fd_ptr->fd);
102       fd_ptr = (s_sockfd*)sockfds->next();
103     }
104     sockfds->destroy();
105   }
106 
107   if (!thread_list.ShutdownAndWaitForThreadsToFinish()) {
108     Emsg1(M_ERROR, 0, _("Could not destroy thread list.\n"));
109   }
110   Dmsg0(100, "CleanupBnetThreadServerTcp: finish\n");
111 }
112 
113 class BNetThreadServerCleanupObject {
114  public:
BNetThreadServerCleanupObject(alist * sockfds,ThreadList & thread_list)115   BNetThreadServerCleanupObject(alist* sockfds, ThreadList& thread_list)
116       : sockfds_(sockfds), thread_list_(thread_list)
117   {
118   }
119 
~BNetThreadServerCleanupObject()120   ~BNetThreadServerCleanupObject()
121   {
122     CleanupBnetThreadServerTcp(sockfds_, thread_list_);
123   }
124 
125  private:
126   alist* sockfds_;
127   ThreadList& thread_list_;
128 };
129 
130 /**
131  * Become Threaded Network Server
132  *
133  * This function is able to handle multiple server ips in
134  * ipv4 and ipv6 style. The Addresse are give in a comma
135  * separated string in bind_addr
136  *
137  * At the moment it is impossible to bind to different ports.
138  */
BnetThreadServerTcp(dlist * addr_list,int max_clients,alist * sockfds,ThreadList & thread_list,bool nokeepalive,void * HandleConnectionRequest (ConfigurationParser * config,void * bsock),ConfigurationParser * config,std::atomic<BnetServerState> * const server_state,void * UserAgentShutdownCallback (void * bsock))139 void BnetThreadServerTcp(
140     dlist* addr_list,
141     int max_clients,
142     alist* sockfds,
143     ThreadList& thread_list,
144     bool nokeepalive,
145     void* HandleConnectionRequest(ConfigurationParser* config, void* bsock),
146     ConfigurationParser* config,
147     std::atomic<BnetServerState>* const server_state,
148     void* UserAgentShutdownCallback(void* bsock))
149 {
150   int newsockfd;
151   socklen_t clilen;
152   struct sockaddr_storage cli_addr; /* client's address */
153   int tlog;
154   int value;
155 #ifdef HAVE_LIBWRAP
156   struct request_info request;
157 #endif
158   IPADDR *ipaddr, *next, *to_free;
159   s_sockfd* fd_ptr = NULL;
160   char buf[128];
161 #ifdef HAVE_POLL
162   nfds_t nfds;
163   int events;
164   struct pollfd* pfds;
165 #endif
166 
167   char allbuf[256 * 10];
168 
169   BNetThreadServerCleanupObject cleanup_object(sockfds, thread_list);
170 
171   quit = false;
172   if (server_state) { server_state->store(BnetServerState::kStarting); }
173 
174   /*
175    * Remove any duplicate addresses.
176    */
177   for (ipaddr = (IPADDR*)addr_list->first(); ipaddr;
178        ipaddr = (IPADDR*)addr_list->next(ipaddr)) {
179     next = (IPADDR*)addr_list->next(ipaddr);
180     while (next) {
181       /*
182        * See if the addresses match.
183        */
184       if (ipaddr->GetSockaddrLen() == next->GetSockaddrLen() &&
185           memcmp(ipaddr->get_sockaddr(), next->get_sockaddr(),
186                  ipaddr->GetSockaddrLen()) == 0) {
187         to_free = next;
188         next = (IPADDR*)addr_list->next(next);
189         addr_list->remove(to_free);
190         delete to_free;
191       } else {
192         next = (IPADDR*)addr_list->next(next);
193       }
194     }
195   }
196 
197   Dmsg1(100, "Addresses %s\n",
198         BuildAddressesString(addr_list, allbuf, sizeof(allbuf)));
199 
200   if (nokeepalive) {
201     value = 0;
202   } else {
203     value = 1;
204   }
205 
206 #ifdef HAVE_POLL
207   nfds = 0;
208 #endif
209   foreach_dlist (ipaddr, addr_list) {
210     /*
211      * Allocate on stack from -- no need to free
212      */
213     fd_ptr = (s_sockfd*)alloca(sizeof(s_sockfd));
214     fd_ptr->port = ipaddr->GetPortNetOrder();
215 
216     /*
217      * Open a TCP socket
218      */
219     for (tlog = 60;
220          (fd_ptr->fd = socket(ipaddr->GetFamily(), SOCK_STREAM, 0)) < 0;
221          tlog -= 10) {
222       if (tlog <= 0) {
223         BErrNo be;
224         char curbuf[256];
225         Emsg3(M_ABORT, 0,
226               _("Cannot open stream socket. ERR=%s. Current %s All %s\n"),
227               be.bstrerror(), ipaddr->build_address_str(curbuf, sizeof(curbuf)),
228               BuildAddressesString(addr_list, allbuf, sizeof(allbuf)));
229       }
230       Bmicrosleep(10, 0);
231     }
232 
233     if (setsockopt(fd_ptr->fd, SOL_SOCKET, SO_REUSEADDR, (sockopt_val_t)&value,
234                    sizeof(value)) < 0) {
235       BErrNo be;
236       Emsg1(M_WARNING, 0, _("Cannot set SO_REUSEADDR on socket: %s\n"),
237             be.bstrerror());
238     }
239 
240     int tries = 3;
241     int wait_seconds = 5;
242     bool ok = false;
243 
244     do {
245       int ret =
246           bind(fd_ptr->fd, ipaddr->get_sockaddr(), ipaddr->GetSockaddrLen());
247       if (ret < 0) {
248         BErrNo be;
249         Emsg2(M_WARNING, 0, _("Cannot bind port %d: ERR=%s: Retrying ...\n"),
250               ntohs(fd_ptr->port), be.bstrerror());
251         Bmicrosleep(wait_seconds, 0);
252       } else {
253         ok = true;
254       }
255     } while (!ok && --tries);
256 
257     if (!ok) {
258       BErrNo be;
259       Emsg2(M_ERROR, 0, _("Cannot bind port %d: ERR=%s.\n"),
260             ntohs(fd_ptr->port), be.bstrerror());
261       if (server_state) { server_state->store(BnetServerState::kError); }
262       return;
263     }
264 
265     listen(fd_ptr->fd, 50); /* tell system we are ready */
266     sockfds->append(fd_ptr);
267 
268 #ifdef HAVE_POLL
269     nfds++;
270 #endif
271   }
272 
273   thread_list.Init(max_clients, HandleConnectionRequest,
274                    UserAgentShutdownCallback);
275 
276 #ifdef HAVE_POLL
277   /*
278    * Allocate on stack from -- no need to free
279    */
280   pfds = (struct pollfd*)alloca(sizeof(struct pollfd) * nfds);
281   memset(pfds, 0, sizeof(struct pollfd) * nfds);
282 
283   nfds = 0;
284   events = POLLIN;
285 #if defined(POLLRDNORM)
286   events |= POLLRDNORM;
287 #endif
288 #if defined(POLLRDBAND)
289   events |= POLLRDBAND;
290 #endif
291 #if defined(POLLPRI)
292   events |= POLLPRI;
293 #endif
294 
295   foreach_alist (fd_ptr, sockfds) {
296     pfds[nfds].fd = fd_ptr->fd;
297     pfds[nfds].events = events;
298     nfds++;
299   }
300 #endif
301 
302   if (server_state) { server_state->store(BnetServerState::kStarted); }
303 
304   while (!quit) {
305 #ifndef HAVE_POLL
306     unsigned int maxfd = 0;
307     fd_set sockset;
308     FD_ZERO(&sockset);
309 
310     foreach_alist (fd_ptr, sockfds) {
311       FD_SET((unsigned)fd_ptr->fd, &sockset);
312       if ((unsigned)fd_ptr->fd > maxfd) { maxfd = fd_ptr->fd; }
313     }
314 
315     struct timeval timeout {
316       .tv_sec = 1, .tv_usec = 0
317     };
318 
319     errno = 0;
320     int status = select(maxfd + 1, &sockset, NULL, NULL, &timeout);
321 
322     if (status == 0) {
323       continue;  // timeout: check if thread should quit
324     } else if (status < 0) {
325       BErrNo be; /* capture errno */
326       if (errno == EINTR) { continue; }
327       if (server_state) { server_state->store(BnetServerState::kError); }
328       Emsg1(M_FATAL, 0, _("Error in select: %s\n"), be.bstrerror());
329       break;
330     }
331 
332     foreach_alist (fd_ptr, sockfds) {
333       if (FD_ISSET(fd_ptr->fd, &sockset)) {
334 #else
335     static constexpr int timeout_ms{1000};
336 
337     errno = 0;
338     int status = poll(pfds, nfds, timeout_ms);
339 
340     if (status == 0) {
341       continue;  // timeout: check if thread should quit
342     } else if (status < 0) {
343       BErrNo be; /* capture errno */
344       if (errno == EINTR) { continue; }
345       Emsg1(M_FATAL, 0, _("Error in poll: %s\n"), be.bstrerror());
346 
347       break;
348     }
349 
350     int cnt = 0;
351     foreach_alist (fd_ptr, sockfds) {
352       if (pfds[cnt++].revents & events) {
353 #endif
354         /*
355          * Got a connection, now accept it.
356          */
357         do {
358           clilen = sizeof(cli_addr);
359           newsockfd = accept(fd_ptr->fd, reinterpret_cast<sockaddr*>(&cli_addr),
360                              &clilen);
361         } while (newsockfd < 0 && errno == EINTR);
362         if (newsockfd < 0) { continue; }
363 #ifdef HAVE_LIBWRAP
364         P(mutex); /* HostsAccess is not thread safe */
365         request_init(&request, RQ_DAEMON, my_name, RQ_FILE, newsockfd, 0);
366         fromhost(&request);
367         if (!HostsAccess(&request)) {
368           V(mutex);
369           Jmsg2(NULL, M_SECURITY, 0,
370                 _("Connection from %s:%d refused by hosts.access\n"),
371                 SockaddrToAscii(reinterpret_cast<sockaddr*>(&cli_addr), buf,
372                                 sizeof(buf)),
373                 SockaddrGetPort(reinterpret_cast<sockaddr*>(&cli_addr)));
374           close(newsockfd);
375           continue;
376         }
377         V(mutex);
378 #endif
379 
380         /*
381          * Receive notification when connection dies.
382          */
383         if (setsockopt(newsockfd, SOL_SOCKET, SO_KEEPALIVE,
384                        (sockopt_val_t)&value, sizeof(value)) < 0) {
385           BErrNo be;
386           Emsg1(M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"),
387                 be.bstrerror());
388         }
389 
390         /*
391          * See who client is. i.e. who connected to us.
392          */
393         P(mutex);
394         SockaddrToAscii(reinterpret_cast<sockaddr*>(&cli_addr), buf,
395                         sizeof(buf));
396         V(mutex);
397 
398         BareosSocket* bs;
399         bs = new BareosSocketTCP;
400         if (nokeepalive) { bs->ClearKeepalive(); }
401 
402         bs->fd_ = newsockfd;
403         bs->SetWho(strdup("client"));
404         bs->SetHost(strdup(buf));
405         bs->SetPort(ntohs(fd_ptr->port));
406         memset(&bs->peer_addr, 0, sizeof(bs->peer_addr));
407         memcpy(&bs->client_addr, &cli_addr, sizeof(bs->client_addr));
408 
409         if (!thread_list.CreateAndAddNewThread(config, bs)) {
410           Jmsg1(NULL, M_ABORT, 0, _("Could not add thread to list.\n"));
411         }
412       }
413     }
414   }
415   if (server_state) { server_state->store(BnetServerState::kEnded); }
416 }
417