1 /*
2    BAREOS® - Backup Archiving REcovery Open Sourced
3 
4    Copyright (C) 2011-2012 Planets Communications B.V.
5    Copyright (C) 2013-2019 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  * Marco van Wieringen, May 2012
24  */
25 /**
26  * @file
27  * ndmp_tape.c implements the NDMP TAPE service which interfaces to
28  * the internal Bareos infrastructure. This is implemented as a separate
29  * daemon protocol on a different port (10000 NDMP by default) which
30  * interfaces to the standard Bareos storage daemon at the record level.
31  *
32  * E.g. normal data from a FD comes via the 9103 port and then get turned
33  * into records for NDMP packets travel via the NDMP protocol library
34  * which is named libbareosndmp and the data gets turned into native Bareos
35  * tape records.
36  */
37 
38 #include "include/bareos.h"
39 
40 #if HAVE_NDMP
41 
42 #include "stored/stored.h"
43 #include "stored/stored_globals.h"
44 
45 #include "ndmp/ndmagents.h"
46 #include "stored/acquire.h"
47 #include "stored/bsr.h"
48 #include "stored/device.h"
49 #include "stored/jcr_private.h"
50 #include "stored/label.h"
51 #include "stored/mount.h"
52 #include "stored/read_record.h"
53 #include "stored/spool.h"
54 #include "lib/address_conf.h"
55 #include "lib/attribs.h"
56 #include "lib/berrno.h"
57 #include "lib/edit.h"
58 #include "lib/bpoll.h"
59 #include "lib/parse_conf.h"
60 #include "lib/thread_list.h"
61 #include "include/auth_types.h"
62 #include "include/jcr.h"
63 
64 #include <netinet/in.h>
65 #include <sys/socket.h>
66 #include <arpa/inet.h>
67 #include <netdb.h>
68 #ifdef HAVE_ARPA_NAMESER_H
69 #include <arpa/nameser.h>
70 #endif
71 
72 #ifdef HAVE_LIBWRAP
73 #include "tcpd.h"
74 #endif
75 
76 #ifdef HAVE_POLL_H
77 #include <poll.h>
78 #elif HAVE_SYS_POLL_H
79 #include <sys/poll.h>
80 #endif
81 #endif /* #if HAVE_NDMP */
82 
83 namespace storagedaemon {
84 #if HAVE_NDMP
85 
86 /**
87  * Structure used to pass arguments to the ndmp_thread_server thread
88  * via a void * argument. Things like the addresslist, maximum number
89  * of clients and the client thread list to use are passed using this
90  * structure.
91  */
92 struct ndmp_thread_server_args {
93   dlist* addr_list;
94   int max_clients;
95   ThreadList* thread_list;
96 };
97 
98 /**
99  * Internal structure to keep track of private data for a NDMP session.
100  * Referenced via (struct ndm_session)->session_handle.
101  */
102 struct ndmp_session_handle {
103   int fd;                       /* Socket file descriptor */
104   char* host;                   /* Host name/IP */
105   int port;                     /* Local port */
106   struct sockaddr client_addr;  /* Client's IP address */
107   struct sockaddr_in peer_addr; /* Peer's IP address */
108   JobControlRecord*
109       jcr; /* Internal JobControlRecord bound to this NDMP session */
110 };
111 
112 /**
113  * Internal structure to keep track of private data.
114  */
115 struct ndmp_internal_state {
116   uint32_t LogLevel;
117   JobControlRecord* jcr;
118 };
119 typedef struct ndmp_internal_state NIS;
120 
121 #if HAVE_NDMP
122 static ThreadList thread_list;
123 #endif
124 
125 /* Static globals */
126 static bool quit = false;
127 static bool ndmp_initialized = false;
128 static pthread_t ndmp_tid;
129 static struct ndmp_thread_server_args ndmp_thread_server_args;
130 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
131 
132 /* Forward referenced functions */
133 
NativeToNdmpLoglevel(int debuglevel,NIS * nis)134 static inline int NativeToNdmpLoglevel(int debuglevel, NIS* nis)
135 {
136   unsigned int level;
137 
138   memset(nis, 0, sizeof(NIS));
139 
140   /*
141    * Lookup the initial default log_level from the default StorageResource.
142    */
143   nis->LogLevel = me->ndmploglevel;
144 
145   /*
146    * NDMP loglevels run from 0 - 9 so we take a look at the
147    * current debug level and divide it by 100 to get a proper
148    * value. If the debuglevel is below the wanted initial level
149    * we set the loglevel to the wanted initial level. As the
150    * debug logging takes care of logging messages that are
151    * unwanted we can set the loglevel higher and still don't
152    * get debug messages.
153    */
154   level = debuglevel / 100;
155   if (level < nis->LogLevel) { level = nis->LogLevel; }
156 
157   /*
158    * Make sure the level is in the wanted range.
159    */
160   if (level > 9) { level = 9; }
161 
162   return level;
163 }
164 
165 /**
166  * Interface function which glues the logging infra of the NDMP lib with the
167  * daemon.
168  */
NdmpLoghandler(struct ndmlog * log,char * tag,int level,char * msg)169 void NdmpLoghandler(struct ndmlog* log, char* tag, int level, char* msg)
170 {
171   int internal_level;
172   NIS* nis;
173 
174   /*
175    * We don't want any trailing newline in log messages.
176    */
177   StripTrailingNewline(msg);
178 
179   /*
180    * Make sure if the logging system was setup properly.
181    */
182   nis = (NIS*)log->ctx;
183   if (!nis) { return; }
184 
185   /*
186    * If the log level of this message is under our logging treshold we
187    * log it as part of the Job.
188    */
189   if (level <= (int)nis->LogLevel) {
190     if (nis->jcr) {
191       /*
192        * Look at the tag field to see what is logged.
193        */
194       if (bstrncmp(tag + 1, "LM", 2)) {
195         /*
196          * *LM* messages. E.g. log message NDMP protocol msgs.
197          * First character of the tag is the agent sending the
198          * message e.g. 'D' == Data Agent
199          *              'T' == Tape Agent
200          *              'R' == Robot Agent
201          *              'C' == Control Agent (DMA)
202          *
203          * Last character is the type of message e.g.
204          * 'n' - normal message
205          * 'd' - debug message
206          * 'e' - error message
207          * 'w' - warning message
208          * '?' - unknown message level
209          */
210         switch (*(tag + 3)) {
211           case 'n':
212             Jmsg(nis->jcr, M_INFO, 0, "%s\n", msg);
213             break;
214           case 'e':
215             Jmsg(nis->jcr, M_ERROR, 0, "%s\n", msg);
216             break;
217           case 'w':
218             Jmsg(nis->jcr, M_WARNING, 0, "%s\n", msg);
219             break;
220           case '?':
221             Jmsg(nis->jcr, M_INFO, 0, "%s\n", msg);
222             break;
223           default:
224             break;
225         }
226       } else {
227         Jmsg(nis->jcr, M_INFO, 0, "%s\n", msg);
228       }
229     }
230   }
231 
232   /*
233    * Print any debug message we convert the NDMP level back to an internal
234    * level and let the normal debug logging handle if it needs to be printed
235    * or not.
236    */
237   internal_level = level * 100;
238   Dmsg3(internal_level, "NDMP: [%s] [%d] %s\n", tag, level, msg);
239 }
240 
241 /**
242  * Clear text authentication callback.
243  */
BndmpAuthClear(struct ndm_session * sess,char * name,char * pass)244 extern "C" int BndmpAuthClear(struct ndm_session* sess, char* name, char* pass)
245 {
246   NdmpResource* auth_config;
247 
248   foreach_res (auth_config, R_NDMP) {
249     /*
250      * Only consider entries for AT_CLEAR authentication type.
251      */
252     if (auth_config->AuthType != AT_CLEAR) { continue; }
253 
254     ASSERT(auth_config->password.encoding == p_encoding_clear);
255 
256     if (bstrcmp(name, auth_config->username) &&
257         bstrcmp(pass, auth_config->password.value)) {
258       /*
259        * See if we need to adjust the logging level.
260        */
261       if (sess->param->log.ctx) {
262         NIS* nis;
263 
264         nis = (NIS*)sess->param->log.ctx;
265         if (nis->LogLevel != auth_config->LogLevel) {
266           if (auth_config->LogLevel <= 9) {
267             nis->LogLevel = auth_config->LogLevel;
268           }
269         }
270       }
271 
272       return 1;
273     }
274   }
275   return 0;
276 }
277 
278 /**
279  * MD5 authentication callback.
280  */
bndmp_auth_md5(struct ndm_session * sess,char * name,char digest[16])281 extern "C" int bndmp_auth_md5(struct ndm_session* sess,
282                               char* name,
283                               char digest[16])
284 {
285   NdmpResource* auth_config;
286 
287   foreach_res (auth_config, R_NDMP) {
288     /*
289      * Only consider entries for AT_MD5 authentication type.
290      */
291     if (auth_config->AuthType != AT_MD5) { continue; }
292 
293     if (!bstrcmp(name, auth_config->username)) { continue; }
294 
295     ASSERT(auth_config->password.encoding == p_encoding_clear);
296 
297     if (!ndmmd5_ok_digest(sess->md5_challenge, auth_config->password.value,
298                           digest)) {
299       return 0;
300     }
301 
302     /*
303      * See if we need to adjust the logging level.
304      */
305     if (sess->param->log.ctx) {
306       NIS* nis;
307 
308       nis = (NIS*)sess->param->log.ctx;
309       if (nis->LogLevel != auth_config->LogLevel) {
310         if (auth_config->LogLevel <= 9) {
311           nis->LogLevel = auth_config->LogLevel;
312         }
313       }
314     }
315 
316     return 1;
317   }
318 
319   return 0;
320 }
321 
322 /**
323  * Save a record using the native routines.
324  */
bndmp_write_data_to_block(JobControlRecord * jcr,int stream,char * data,uint32_t data_length)325 static inline bool bndmp_write_data_to_block(JobControlRecord* jcr,
326                                              int stream,
327                                              char* data,
328                                              uint32_t data_length)
329 {
330   bool retval = false;
331   DeviceControlRecord* dcr = jcr->impl->dcr;
332   POOLMEM* rec_data;
333 
334   if (!dcr) {
335     Dmsg0(100, "No dcr defined, bailing out\n");
336     return retval;
337   }
338 
339   if (!dcr->rec) {
340     Dmsg0(100, "No dcr->rec defined, bailing out\n");
341     return retval;
342   }
343   /*
344    * Keep track of the original data buffer and restore it on exit from this
345    * function.
346    */
347   rec_data = dcr->rec->data;
348 
349   dcr->rec->VolSessionId = jcr->VolSessionId;
350   dcr->rec->VolSessionTime = jcr->VolSessionTime;
351   dcr->rec->FileIndex = dcr->FileIndex;
352   dcr->rec->Stream = stream;
353   dcr->rec->maskedStream = stream & STREAMMASK_TYPE; /* strip high bits */
354   dcr->rec->data = data;
355   dcr->rec->data_len = data_length;
356 
357   if (!dcr->WriteRecord()) { goto bail_out; }
358 
359   if (stream == STREAM_UNIX_ATTRIBUTES) {
360     dcr->DirUpdateFileAttributes(dcr->rec);
361   }
362 
363   retval = true;
364 
365 bail_out:
366   dcr->rec->data = rec_data;
367   return retval;
368 }
369 
370 /**
371  * Read a record using the native routines.
372  *
373  * data_length == 0 = EOF
374  */
bndmp_read_data_from_block(JobControlRecord * jcr,char * data,uint32_t wanted_data_length,uint32_t * data_length)375 static inline bool bndmp_read_data_from_block(JobControlRecord* jcr,
376                                               char* data,
377                                               uint32_t wanted_data_length,
378                                               uint32_t* data_length)
379 {
380   DeviceControlRecord* dcr = jcr->impl->read_dcr;
381   READ_CTX* rctx = jcr->impl->read_session.rctx;
382   bool done = false;
383   bool ok = true;
384 
385   if (!rctx) { return false; }
386 
387   while (!done) {
388     /*
389      * See if there are any records left to process.
390      */
391     if (!IsBlockEmpty(rctx->rec)) {
392       if (!ReadNextRecordFromBlock(dcr, rctx, &done)) {
393         /*
394          * When the done flag is set to true we are done reading all
395          * records or end of block read next block.
396          */
397         continue;
398       }
399     } else {
400       /*
401        * Read the next block into our buffers.
402        */
403       if (!ReadNextBlockFromDevice(dcr, &rctx->sessrec, NULL,
404                                    MountNextReadVolume, &ok)) {
405         return false;
406       }
407 
408       /*
409        * Get a new record for each Job as defined by VolSessionId and
410        * VolSessionTime
411        */
412       if (!rctx->rec || rctx->rec->VolSessionId != dcr->block->VolSessionId ||
413           rctx->rec->VolSessionTime != dcr->block->VolSessionTime) {
414         ReadContextSetRecord(dcr, rctx);
415       }
416 
417       rctx->records_processed = 0;
418       ClearAllBits(REC_STATE_MAX, rctx->rec->state_bits);
419       rctx->lastFileIndex = READ_NO_FILEINDEX;
420 
421       if (!ReadNextRecordFromBlock(dcr, rctx, &done)) {
422         /*
423          * When the done flag is set to true we are done reading all
424          * records or end of block read next block.
425          */
426         continue;
427       }
428     }
429 
430     /*
431      * See if we are processing some sort of label?
432      */
433     if (rctx->rec->FileIndex < 0) { continue; }
434 
435     /*
436      * Here we should have read a record from the block which contains some
437      * data. Its either:
438      *
439      * - STREAM_UNIX_ATTRIBUTES
440      *      Which is the start of the dump when we encounter that we just read
441      * the next record.
442      * - STREAM_FILE_DATA
443      *      Normal NDMP data.
444      * - STREAM_NDMP_SEPARATOR
445      *      End of NDMP data stream.
446      *
447      * anything other means a corrupted stream of records and means we give an
448      * EOF.
449      */
450     switch (rctx->rec->maskedStream) {
451       case STREAM_UNIX_ATTRIBUTES:
452         continue;
453       case STREAM_FILE_DATA:
454         if (wanted_data_length < rctx->rec->data_len) {
455           Jmsg0(jcr, M_FATAL, 0,
456                 _("Data read from volume bigger then NDMP databuffer, please "
457                   "increase the NDMP blocksize.\n"));
458           return false;
459         }
460         memcpy(data, rctx->rec->data, rctx->rec->data_len);
461         *data_length = rctx->rec->data_len;
462         return true;
463       case STREAM_NDMP_SEPARATOR:
464         *data_length = 0;
465         return true;
466       default:
467         Jmsg1(jcr, M_ERROR, 0, _("Encountered an unknown stream type %d\n"),
468               rctx->rec->maskedStream);
469         *data_length = 0;
470         return true;
471     }
472   }
473 
474   if (done) { *data_length = 0; }
475 
476   return true;
477 }
478 
479 /**
480  * Generate virtual file attributes for the whole NDMP stream.
481  */
BndmpCreateVirtualFile(JobControlRecord * jcr,char * filename)482 static inline bool BndmpCreateVirtualFile(JobControlRecord* jcr, char* filename)
483 {
484   DeviceControlRecord* dcr = jcr->impl->dcr;
485   struct stat statp;
486   time_t now = time(NULL);
487   PoolMem attribs(PM_NAME), data(PM_NAME);
488   int32_t size;
489 
490   memset(&statp, 0, sizeof(statp));
491   statp.st_mode = 0700 | S_IFREG;
492   statp.st_ctime = now;
493   statp.st_mtime = now;
494   statp.st_atime = now;
495   statp.st_size = -1;
496   statp.st_blksize = 4096;
497   statp.st_blocks = 1;
498 
499   /*
500    * Encode a stat structure into an ASCII string.
501    */
502   EncodeStat(attribs.c_str(), &statp, sizeof(statp), dcr->FileIndex,
503              STREAM_UNIX_ATTRIBUTES);
504 
505   /*
506    * Generate a file attributes stream.
507    *   File_index
508    *   File type
509    *   Filename (full path)
510    *   Encoded attributes
511    *   Link name (if type==FT_LNK or FT_LNKSAVED)
512    *   Encoded extended-attributes (for Win32)
513    *   Delta Sequence Number
514    */
515   size =
516       Mmsg(data, "%ld %d %s%c%s%c%s%c%s%c%d%c", dcr->FileIndex, /* File_index */
517            FT_REG,                                              /* File type */
518            filename,           /* Filename (full path) */
519            0, attribs.c_str(), /* Encoded attributes */
520            0, "",              /* Link name (if type==FT_LNK or FT_LNKSAVED) */
521            0, "",              /* Encoded extended-attributes (for Win32) */
522            0, 0,               /* Delta Sequence Number */
523            0);
524 
525   return bndmp_write_data_to_block(jcr, STREAM_UNIX_ATTRIBUTES, data.c_str(),
526                                    size);
527 }
528 
BndmpSimuFlushWeof(struct ndm_session * sess)529 static int BndmpSimuFlushWeof(struct ndm_session* sess)
530 {
531   struct ndm_tape_agent* ta = sess->tape_acb;
532 
533   if (ta->weof_on_close) {
534     /* best effort */
535     ndmos_tape_wfm(sess);
536   }
537   return 0;
538 }
539 
540 /**
541  * Search the JCRs for one with the given security key.
542  */
get_jcr_by_security_key(char * security_key)543 static inline JobControlRecord* get_jcr_by_security_key(char* security_key)
544 {
545   JobControlRecord* jcr;
546 
547   foreach_jcr (jcr) {
548     if (bstrcmp(jcr->sd_auth_key, security_key)) {
549       jcr->IncUseCount();
550       break;
551     }
552   }
553   endeach_jcr(jcr);
554   return jcr;
555 }
556 
bndmp_tape_open(struct ndm_session * sess,char * drive_name,int will_write)557 extern "C" ndmp9_error bndmp_tape_open(struct ndm_session* sess,
558                                        char* drive_name,
559                                        int will_write)
560 {
561   JobControlRecord* jcr;
562   DeviceControlRecord* dcr;
563   char* filesystem;
564   struct ndmp_session_handle* handle;
565   struct ndm_tape_agent* ta;
566 
567   /*
568    * The drive_name should be in the form <AuthKey>@<file_system>%<dumplevel>
569    */
570   if ((filesystem = strchr(drive_name, '@')) == NULL) {
571     return NDMP9_NO_DEVICE_ERR;
572   }
573 
574   /*
575    * Lookup the jobid the drive_name should contain a valid authentication key.
576    */
577   *filesystem++ = '\0';
578   if (!(jcr = get_jcr_by_security_key(drive_name))) {
579     Jmsg1(NULL, M_FATAL, 0,
580           _("NDMP tape open failed: Security Key not found: %s\n"), drive_name);
581     return NDMP9_NO_DEVICE_ERR;
582   }
583 
584   /*
585    * When we found a JobControlRecord with the wanted security key it also
586    * implictly means the authentication succeeded as the connecting NDMP session
587    * only knows the exact security key as it was inserted by the director.
588    */
589   jcr->authenticated = true;
590 
591   /*
592    * There is a native storage daemon session waiting for the FD to connect.
593    * In NDMP terms this is the same as a FD connecting so wake any waiting
594    * threads.
595    */
596   pthread_cond_signal(&jcr->impl->job_start_wait);
597 
598   /*
599    * Save the JobControlRecord to ndm_session binding so everything furher
600    * knows which JobControlRecord belongs to which NDMP session. We have
601    * a special ndmp_session_handle which we can use to track
602    * session specific information.
603    */
604   handle = (struct ndmp_session_handle*)sess->session_handle;
605 
606   /*
607    * If we already have a JobControlRecord binding for this connection we
608    * release it here as we are about to establish a new binding (e.g. second
609    * NDMP save for the same job) and we should end up with the same binding.
610    */
611   if (handle->jcr) { FreeJcr(handle->jcr); }
612   handle->jcr = jcr;
613 
614   /*
615    * Keep track of the JobControlRecord for logging purposes.
616    */
617   if (sess->param->log.ctx) {
618     NIS* nis;
619 
620     nis = (NIS*)sess->param->log.ctx;
621     nis->jcr = jcr;
622   }
623 
624   /*
625    * Depending on the open mode select the right DeviceControlRecord.
626    */
627   if (will_write) {
628     dcr = jcr->impl->dcr;
629   } else {
630     dcr = jcr->impl->read_dcr;
631   }
632 
633   if (!dcr) {
634     Jmsg0(jcr, M_FATAL, 0, _("DeviceControlRecord is NULL!!!\n"));
635     return NDMP9_NO_DEVICE_ERR;
636   }
637 
638   if (!dcr->dev) {
639     Jmsg0(jcr, M_FATAL, 0, _("Device is NULL!!!\n"));
640     return NDMP9_NO_DEVICE_ERR;
641   }
642 
643   /*
644    * See if need to setup for write or read.
645    */
646   if (will_write) {
647     PoolMem virtual_filename(PM_FNAME);
648 
649     /*
650      * Setup internal system for writing data.
651      */
652     Dmsg1(100, "Start append data. res=%d\n", dcr->dev->NumReserved());
653 
654     /*
655      * One NDMP backup Job can be one or more save sessions so we keep
656      * track if we already acquired the storage.
657      */
658     if (!jcr->impl->acquired_storage) {
659       /*
660        * Actually acquire the device which we reserved.
661        */
662       if (!AcquireDeviceForAppend(dcr)) { goto bail_out; }
663 
664       /*
665        * Let any SD plugin know now its time to setup the record translation
666        * infra.
667        */
668       if (GeneratePluginEvent(jcr, bsdEventSetupRecordTranslation, dcr) !=
669           bRC_OK) {
670         goto bail_out;
671       }
672 
673       /*
674        * Keep track that we acquired the storage.
675        */
676       jcr->impl->acquired_storage = true;
677 
678       Dmsg1(50, "Begin append device=%s\n", dcr->dev->print_name());
679 
680       /*
681        * Change the Job to running state.
682        */
683       jcr->sendJobStatus(JS_Running);
684 
685       /*
686        * As we only generate very limited attributes info e.g. one
687        * set per NDMP backup stream we only setup data spooling and not
688        * attribute spooling.
689        */
690 
691       if (!BeginDataSpool(dcr)) { goto bail_out; }
692 
693       /*
694        * Write Begin Session Record
695        */
696       if (!WriteSessionLabel(dcr, SOS_LABEL)) {
697         Jmsg1(jcr, M_FATAL, 0, _("Write session label failed. ERR=%s\n"),
698               dcr->dev->bstrerror());
699         goto bail_out;
700       }
701 
702       dcr->VolFirstIndex = dcr->VolLastIndex = 0;
703       jcr->run_time = time(NULL); /* start counting time for rates */
704 
705       /*
706        * The session is saved as one file stream.
707        */
708       dcr->FileIndex = 1;
709       jcr->JobFiles = 1;
710     } else {
711       /*
712        * The next session is saved as one file stream.
713        */
714       dcr->FileIndex++;
715       jcr->JobFiles++;
716     }
717 
718     /*
719      * Create a virtual file name @NDMP/<filesystem>%<dumplevel> or
720      * @NDMP/<filesystem> and save the attributes to the director.
721      */
722     Mmsg(virtual_filename, "/@NDMP%s", filesystem);
723     if (!BndmpCreateVirtualFile(jcr, virtual_filename.c_str())) {
724       Jmsg0(jcr, M_FATAL, 0, _("Creating virtual file attributes failed.\n"));
725       goto bail_out;
726     }
727   } else {
728     bool ok = true;
729     READ_CTX* rctx;
730 
731     /*
732      * Setup internal system for reading data (if not done before).
733      */
734     if (!jcr->impl->acquired_storage) {
735       Dmsg0(20, "Start read data.\n");
736 
737       if (jcr->impl->NumReadVolumes == 0) {
738         Jmsg(jcr, M_FATAL, 0, _("No Volume names found for restore.\n"));
739         goto bail_out;
740       }
741 
742       Dmsg2(200, "Found %d volumes names to restore. First=%s\n",
743             jcr->impl->NumReadVolumes, jcr->impl->VolList->VolumeName);
744 
745       /*
746        * Ready device for reading
747        */
748       if (!AcquireDeviceForRead(dcr)) { goto bail_out; }
749 
750       /*
751        * Let any SD plugin know now its time to setup the record translation
752        * infra.
753        */
754       if (GeneratePluginEvent(jcr, bsdEventSetupRecordTranslation, dcr) !=
755           bRC_OK) {
756         goto bail_out;
757       }
758 
759       /*
760        * Keep track that we acquired the storage.
761        */
762       jcr->impl->acquired_storage = true;
763 
764       /*
765        * Change the Job to running state.
766        */
767       jcr->sendJobStatus(JS_Running);
768 
769       Dmsg1(50, "Begin reading device=%s\n", dcr->dev->print_name());
770 
771       PositionDeviceToFirstFile(jcr, dcr);
772       jcr->impl->read_session.mount_next_volume = false;
773 
774       /*
775        * Allocate a new read context for this Job.
776        */
777       rctx = new_read_context();
778       jcr->impl->read_session.rctx = rctx;
779 
780       /*
781        * Read the first block and setup record processing.
782        */
783       if (!ReadNextBlockFromDevice(dcr, &rctx->sessrec, NULL,
784                                    MountNextReadVolume, &ok)) {
785         Jmsg1(jcr, M_FATAL, 0, _("Read session label failed. ERR=%s\n"),
786               dcr->dev->bstrerror());
787         goto bail_out;
788       }
789 
790       ReadContextSetRecord(dcr, rctx);
791       rctx->records_processed = 0;
792       ClearAllBits(REC_STATE_MAX, rctx->rec->state_bits);
793       rctx->lastFileIndex = READ_NO_FILEINDEX;
794     }
795   }
796 
797   /*
798    * Setup NDMP states.
799    */
800   ta = sess->tape_acb;
801   ta->tape_fd = 0; /* fake filedescriptor */
802   bzero(&ta->tape_state, sizeof ta->tape_state);
803   ta->tape_state.error = NDMP9_NO_ERR;
804   ta->tape_state.state = NDMP9_TAPE_STATE_OPEN;
805   ta->tape_state.open_mode =
806       will_write ? NDMP9_TAPE_RDWR_MODE : NDMP9_TAPE_READ_MODE;
807   ta->tape_state.file_num.valid = NDMP9_VALIDITY_VALID;
808   ta->tape_state.soft_errors.valid = NDMP9_VALIDITY_VALID;
809   ta->tape_state.block_size.valid = NDMP9_VALIDITY_VALID;
810   ta->tape_state.blockno.valid = NDMP9_VALIDITY_VALID;
811   ta->tape_state.total_space.valid = NDMP9_VALIDITY_INVALID;
812   ta->tape_state.space_remain.valid = NDMP9_VALIDITY_INVALID;
813 
814   return NDMP9_NO_ERR;
815 
816 bail_out:
817   jcr->setJobStatus(JS_ErrorTerminated);
818   return NDMP9_NO_DEVICE_ERR;
819 }
820 
BndmpTapeClose(struct ndm_session * sess)821 extern "C" ndmp9_error BndmpTapeClose(struct ndm_session* sess)
822 {
823   JobControlRecord* jcr;
824   ndmp9_error err;
825   struct ndmp_session_handle* handle;
826   struct ndm_tape_agent* ta = sess->tape_acb;
827   char ndmp_separator[] = {"NdMpSePaRaToR"};
828 
829   if (ta->tape_fd < 0) { return NDMP9_DEV_NOT_OPEN_ERR; }
830 
831   BndmpSimuFlushWeof(sess);
832 
833   /*
834    * Setup the glue between the NDMP layer and the Storage Daemon.
835    */
836   handle = (struct ndmp_session_handle*)sess->session_handle;
837 
838   jcr = handle->jcr;
839   if (!jcr) {
840     Jmsg0(NULL, M_FATAL, 0, _("JobControlRecord is NULL!!!\n"));
841     return NDMP9_DEV_NOT_OPEN_ERR;
842   }
843 
844   err = NDMP9_NO_ERR;
845   if (NDMTA_TAPE_IS_WRITABLE(ta)) {
846     /*
847      * Write a separator record so on restore we can recognize the different
848      * NDMP datastreams from each other.
849      */
850     if (!bndmp_write_data_to_block(jcr, STREAM_NDMP_SEPARATOR, ndmp_separator,
851                                    13)) {
852       err = NDMP9_IO_ERR;
853     }
854   }
855 
856   pthread_cond_signal(&jcr->impl->job_end_wait); /* wake any waiting thread */
857 
858   ndmos_tape_initialize(sess);
859 
860   return err;
861 }
862 
bndmp_tape_mtio(struct ndm_session * sess,ndmp9_tape_mtio_op op,uint32_t count,uint32_t * resid)863 extern "C" ndmp9_error bndmp_tape_mtio(struct ndm_session* sess,
864                                        ndmp9_tape_mtio_op op,
865                                        uint32_t count,
866                                        uint32_t* resid)
867 {
868   struct ndm_tape_agent* ta = sess->tape_acb;
869 
870   *resid = 0;
871 
872   if (ta->tape_fd < 0) { return NDMP9_DEV_NOT_OPEN_ERR; }
873 
874   /*
875    * audit for valid op and for tape mode
876    */
877   switch (op) {
878     case NDMP9_MTIO_FSF:
879       return NDMP9_NO_ERR;
880 
881     case NDMP9_MTIO_BSF:
882       return NDMP9_NO_ERR;
883 
884     case NDMP9_MTIO_FSR:
885       return NDMP9_NO_ERR;
886 
887     case NDMP9_MTIO_BSR:
888       return NDMP9_NO_ERR;
889 
890     case NDMP9_MTIO_REW:
891       BndmpSimuFlushWeof(sess);
892       *resid = 0;
893       ta->tape_state.file_num.value = 0;
894       ta->tape_state.blockno.value = 0;
895       break;
896 
897     case NDMP9_MTIO_OFF:
898       return NDMP9_NO_ERR;
899 
900     case NDMP9_MTIO_EOF: /* should be "WFM" write-file-mark */
901       return NDMP9_NO_ERR;
902 
903     default:
904       return NDMP9_ILLEGAL_ARGS_ERR;
905   }
906 
907   return NDMP9_NO_ERR;
908 }
909 
bndmp_tape_write(struct ndm_session * sess,char * buf,uint32_t count,uint32_t * done_count)910 extern "C" ndmp9_error bndmp_tape_write(struct ndm_session* sess,
911                                         char* buf,
912                                         uint32_t count,
913                                         uint32_t* done_count)
914 {
915   JobControlRecord* jcr;
916   ndmp9_error err;
917   struct ndmp_session_handle* handle;
918   struct ndm_tape_agent* ta = sess->tape_acb;
919 
920   if (ta->tape_fd < 0) { return NDMP9_DEV_NOT_OPEN_ERR; }
921 
922   if (!NDMTA_TAPE_IS_WRITABLE(ta)) { return NDMP9_PERMISSION_ERR; }
923 
924   /*
925    * Setup the glue between the NDMP layer and the Storage Daemon.
926    */
927   handle = (struct ndmp_session_handle*)sess->session_handle;
928 
929   jcr = handle->jcr;
930   if (!jcr) {
931     Jmsg0(NULL, M_FATAL, 0, _("JobControlRecord is NULL!!!\n"));
932     return NDMP9_DEV_NOT_OPEN_ERR;
933   }
934 
935   /*
936    * Turn the NDMP data into a internal record and save it.
937    */
938   if (bndmp_write_data_to_block(jcr, STREAM_FILE_DATA, buf, count)) {
939     ta->tape_state.blockno.value++;
940     *done_count = count;
941     err = NDMP9_NO_ERR;
942   } else {
943     jcr->setJobStatus(JS_ErrorTerminated);
944     err = NDMP9_IO_ERR;
945   }
946 
947   ta->weof_on_close = 1;
948 
949   return err;
950 }
951 
BndmpTapeWfm(struct ndm_session * sess)952 extern "C" ndmp9_error BndmpTapeWfm(struct ndm_session* sess)
953 {
954   ndmp9_error err;
955   struct ndm_tape_agent* ta = sess->tape_acb;
956 
957   ta->weof_on_close = 0;
958 
959   if (ta->tape_fd < 0) { return NDMP9_DEV_NOT_OPEN_ERR; }
960 
961   if (!NDMTA_TAPE_IS_WRITABLE(ta)) { return NDMP9_PERMISSION_ERR; }
962 
963   err = NDMP9_NO_ERR;
964 
965   return err;
966 }
967 
bndmp_tape_read(struct ndm_session * sess,char * buf,uint32_t count,uint32_t * done_count)968 extern "C" ndmp9_error bndmp_tape_read(struct ndm_session* sess,
969                                        char* buf,
970                                        uint32_t count,
971                                        uint32_t* done_count)
972 {
973   JobControlRecord* jcr;
974   ndmp9_error err;
975   struct ndmp_session_handle* handle;
976   struct ndm_tape_agent* ta = sess->tape_acb;
977 
978   if (ta->tape_fd < 0) { return NDMP9_DEV_NOT_OPEN_ERR; }
979 
980   /*
981    * Setup the glue between the NDMP layer and the Storage Daemon.
982    */
983   handle = (struct ndmp_session_handle*)sess->session_handle;
984 
985   jcr = handle->jcr;
986   if (!jcr) {
987     Jmsg0(NULL, M_FATAL, 0, _("JobControlRecord is NULL!!!\n"));
988     return NDMP9_DEV_NOT_OPEN_ERR;
989   }
990 
991   if (bndmp_read_data_from_block(jcr, buf, count, done_count)) {
992     ta->tape_state.blockno.value++;
993     if (*done_count == 0) {
994       err = NDMP9_EOF_ERR;
995     } else {
996       err = NDMP9_NO_ERR;
997     }
998   } else {
999     jcr->setJobStatus(JS_ErrorTerminated);
1000     err = NDMP9_IO_ERR;
1001   }
1002 
1003   return err;
1004 }
1005 
RegisterCallbackHooks(struct ndm_session * sess)1006 static inline void RegisterCallbackHooks(struct ndm_session* sess)
1007 {
1008   struct ndm_auth_callbacks auth_callbacks;
1009   struct ndm_tape_simulator_callbacks tape_callbacks;
1010 
1011   /*
1012    * Register the authentication callbacks.
1013    */
1014   auth_callbacks.validate_password = BndmpAuthClear;
1015   auth_callbacks.validate_md5 = bndmp_auth_md5;
1016   ndmos_auth_register_callbacks(sess, &auth_callbacks);
1017 
1018   /*
1019    * Register the tape simulator callbacks.
1020    */
1021   tape_callbacks.tape_open = bndmp_tape_open;
1022   tape_callbacks.tape_close = BndmpTapeClose;
1023   tape_callbacks.tape_mtio = bndmp_tape_mtio;
1024   tape_callbacks.tape_write = bndmp_tape_write;
1025   tape_callbacks.tape_wfm = BndmpTapeWfm;
1026   tape_callbacks.tape_read = bndmp_tape_read;
1027   ndmos_tape_register_callbacks(sess, &tape_callbacks);
1028 }
1029 
UnregisterCallbackHooks(struct ndm_session * sess)1030 static inline void UnregisterCallbackHooks(struct ndm_session* sess)
1031 {
1032   ndmos_tape_unregister_callbacks(sess);
1033   ndmos_auth_unregister_callbacks(sess);
1034 }
1035 
EndOfNdmpBackup(JobControlRecord * jcr)1036 void EndOfNdmpBackup(JobControlRecord* jcr)
1037 {
1038   DeviceControlRecord* dcr = jcr->impl->dcr;
1039   char ec[50];
1040 
1041   /*
1042    * Don't use time_t for job_elapsed as time_t can be 32 or 64 bits,
1043    * and the subsequent Jmsg() editing will break
1044    */
1045   int32_t job_elapsed = time(NULL) - jcr->run_time;
1046 
1047   if (job_elapsed <= 0) { job_elapsed = 1; }
1048 
1049   Jmsg(jcr, M_INFO, 0,
1050        _("Elapsed time=%02d:%02d:%02d, Transfer rate=%s Bytes/second\n"),
1051        job_elapsed / 3600, job_elapsed % 3600 / 60, job_elapsed % 60,
1052        edit_uint64_with_suffix(jcr->JobBytes / job_elapsed, ec));
1053 
1054   if (dcr) {
1055     /*
1056      * Check if we can still write. This may not be the case
1057      *  if we are at the end of the tape or we got a fatal I/O error.
1058      */
1059     if (dcr->dev && dcr->dev->CanWrite()) {
1060       Dmsg1(200, "Write EOS label JobStatus=%c\n", jcr->JobStatus);
1061 
1062       if (!WriteSessionLabel(dcr, EOS_LABEL)) {
1063         /*
1064          * Print only if JobStatus JS_Terminated and not cancelled to avoid
1065          * spurious messages
1066          */
1067         if (jcr->is_JobStatus(JS_Terminated) && !jcr->IsJobCanceled()) {
1068           Jmsg1(jcr, M_FATAL, 0, _("Error writing end session label. ERR=%s\n"),
1069                 dcr->dev->bstrerror());
1070         }
1071         jcr->setJobStatus(JS_ErrorTerminated);
1072       }
1073 
1074       Dmsg0(90, "back from write_end_session_label()\n");
1075 
1076       /*
1077        * Flush out final partial block of this session
1078        */
1079       if (!dcr->WriteBlockToDevice()) {
1080         /*
1081          * Print only if JobStatus JS_Terminated and not cancelled to avoid
1082          * spurious messages
1083          */
1084         if (jcr->is_JobStatus(JS_Terminated) && !jcr->IsJobCanceled()) {
1085           Jmsg2(jcr, M_FATAL, 0, _("Fatal append error on device %s: ERR=%s\n"),
1086                 dcr->dev->print_name(), dcr->dev->bstrerror());
1087         }
1088         jcr->setJobStatus(JS_ErrorTerminated);
1089       }
1090     }
1091 
1092     if (jcr->is_JobStatus(JS_Terminated)) {
1093       /*
1094        * Note: if commit is OK, the device will remain blocked
1095        */
1096       CommitDataSpool(dcr);
1097     } else {
1098       DiscardDataSpool(dcr);
1099     }
1100 
1101     /*
1102      * Release the device -- and send final Vol info to DIR and unlock it.
1103      */
1104     if (jcr->impl->acquired_storage) {
1105       ReleaseDevice(dcr);
1106       jcr->impl->acquired_storage = false;
1107     } else {
1108       dcr->UnreserveDevice();
1109     }
1110   }
1111 
1112   jcr->sendJobStatus(); /* update director */
1113 }
1114 
EndOfNdmpRestore(JobControlRecord * jcr)1115 void EndOfNdmpRestore(JobControlRecord* jcr)
1116 {
1117   if (jcr->impl->read_session.rctx) {
1118     FreeReadContext(jcr->impl->read_session.rctx);
1119     jcr->impl->read_session.rctx = NULL;
1120   }
1121 
1122   if (jcr->impl->acquired_storage) {
1123     ReleaseDevice(jcr->impl->read_dcr);
1124     jcr->impl->acquired_storage = false;
1125   } else {
1126     jcr->impl->read_dcr->UnreserveDevice();
1127   }
1128 }
1129 
HandleNdmpConnectionRequest(ConfigurationParser * config,void * arg)1130 extern "C" void* HandleNdmpConnectionRequest(ConfigurationParser* config,
1131                                              void* arg)
1132 {
1133   int status;
1134   struct ndmconn* conn;
1135   struct ndm_session* sess;
1136   struct ndmp_session_handle* handle;
1137   NIS* nis;
1138 
1139   handle = (struct ndmp_session_handle*)arg;
1140   if (!handle) {
1141     Emsg0(M_ABORT, 0,
1142           _("Illegal call to HandleNdmpConnectionRequest with NULL session "
1143             "handle\n"));
1144     return NULL;
1145   }
1146 
1147   /*
1148    * Initialize a new NDMP session
1149    */
1150   sess = (struct ndm_session*)malloc(sizeof(struct ndm_session));
1151   memset(sess, 0, sizeof(struct ndm_session));
1152 
1153   sess->param =
1154       (struct ndm_session_param*)malloc(sizeof(struct ndm_session_param));
1155   memset(sess->param, 0, sizeof(struct ndm_session_param));
1156   sess->param->log.deliver = storagedaemon::NdmpLoghandler;
1157   nis = (NIS*)malloc(sizeof(NIS));
1158   sess->param->log.ctx = nis;
1159   sess->param->log_level = NativeToNdmpLoglevel(debug_level, nis);
1160   sess->param->log_tag = strdup("SD-NDMP");
1161 
1162   RegisterCallbackHooks(sess);
1163 
1164   /*
1165    * We duplicate some of the code from the ndma server session handling
1166    * available in the NDMJOB NDMP library e.g. we do not enter via
1167    * ndma_daemon_session() and then continue to ndma_server_session() which is
1168    * the normal entry point into the library as the ndma_daemon_session()
1169    * function does things like creating a listen socket, fork and accept the
1170    * connection and the ndma_server_session() function tries to get peername and
1171    * socket names before eventually establishing the NDMP connection. We already
1172    * do all of that ourself via proven code implemented in ndmp_thread_server
1173    * which is calling us.
1174    */
1175 
1176   /*
1177    * Make the ndm_session usable for a new connection e.g. initialize and
1178    * commission.
1179    */
1180   sess->tape_agent_enabled = 1;
1181   sess->data_agent_enabled = 1;
1182 
1183   status = ndma_session_initialize(sess);
1184   if (status) {
1185     Emsg0(M_ABORT, 0, _("Cannot initialize new NDMA session\n"));
1186     goto bail_out;
1187   }
1188 
1189   status = ndma_session_commission(sess);
1190   if (status) {
1191     Emsg0(M_ABORT, 0, _("Cannot commission new NDMA session\n"));
1192     goto bail_out;
1193   }
1194 
1195   conn = ndmconn_initialize(0, (char*)"#C");
1196   if (!conn) {
1197     Emsg0(M_ABORT, 0, _("Cannot initialize new NDMA connection\n"));
1198     goto bail_out;
1199   }
1200 
1201   /*
1202    * Tell the lower levels which socket to use and setup snooping.
1203    */
1204   ndmos_condition_control_socket(sess, handle->fd);
1205   if (me->ndmp_snooping) {
1206     ndmconn_set_snoop(conn, &sess->param->log, sess->param->log_level);
1207   }
1208   ndmconn_accept(conn, handle->fd);
1209 
1210   /*
1211    * Initialize some members now that we have a initialized NDMP connection.
1212    */
1213   conn->call = ndma_call;
1214   conn->context = sess;
1215   sess->plumb.control = conn;
1216   sess->session_handle = handle;
1217 
1218   /*
1219    * This does the actual work e.g. run through the NDMP state machine.
1220    */
1221   while (!conn->chan.eof) { ndma_session_quantum(sess, 1000); }
1222 
1223   /*
1224    * Tear down the NDMP connection.
1225    */
1226   ndmconn_destruct(conn);
1227   ndma_session_decommission(sess);
1228 
1229 bail_out:
1230   UnregisterCallbackHooks(sess);
1231 
1232   free(sess->param->log.ctx);
1233   free(sess->param->log_tag);
1234   free(sess->param);
1235   free(sess);
1236 
1237   close(handle->fd);
1238   if (handle->jcr) FreeJcr(handle->jcr);
1239   if (handle->host) free(handle->host);
1240   free(handle);
1241 
1242   return NULL;
1243 }
1244 
1245 /**
1246  * Create a separate thread that accepts NDMP connections.
1247  * We don't use the Bareos native BnetThreadServerTcp which
1248  * uses the bsock class which is a bit to much overhead
1249  * for simple sockets which we need and has all kinds of
1250  * extra features likes TLS and keep-alive support etc.
1251  * which wouldn't work for NDMP anyhow.
1252  *
1253  * So this is a BnetThreadServerTcp put on a diet which
1254  * also contains the absolute minimum code needed to
1255  * have a robust connection handler.
1256  */
ndmp_thread_server(void * arg)1257 extern "C" void* ndmp_thread_server(void* arg)
1258 {
1259   struct ndmp_thread_server_args* ntsa;
1260   int new_sockfd, status;
1261   socklen_t clilen;
1262   struct sockaddr cli_addr; /* client's address */
1263   int tlog, tmax;
1264   int turnon = 1;
1265 #ifdef HAVE_LIBWRAP
1266   struct request_info request;
1267 #endif
1268   IPADDR *ipaddr, *next;
1269   struct s_sockfd {
1270     dlink link; /* this MUST be the first item */
1271     int fd;
1272     int port;
1273   }* fd_ptr = NULL;
1274   char buf[128];
1275   alist sockfds(10, not_owned_by_alist);
1276 #ifdef HAVE_POLL
1277   nfds_t nfds;
1278   struct pollfd* pfds;
1279 #endif
1280 
1281   ntsa = (struct ndmp_thread_server_args*)arg;
1282   if (!ntsa) { return NULL; }
1283 
1284   /*
1285    * Remove any duplicate addresses.
1286    */
1287   for (ipaddr = (IPADDR*)ntsa->addr_list->first(); ipaddr;
1288        ipaddr = (IPADDR*)ntsa->addr_list->next(ipaddr)) {
1289     for (next = (IPADDR*)ntsa->addr_list->next(ipaddr); next;
1290          next = (IPADDR*)ntsa->addr_list->next(next)) {
1291       if (ipaddr->GetSockaddrLen() == next->GetSockaddrLen() &&
1292           memcmp(ipaddr->get_sockaddr(), next->get_sockaddr(),
1293                  ipaddr->GetSockaddrLen()) == 0) {
1294         ntsa->addr_list->remove(next);
1295       }
1296     }
1297   }
1298 
1299   char allbuf[256 * 10];
1300   Dmsg1(100, "Addresses %s\n",
1301         BuildAddressesString(ntsa->addr_list, allbuf, sizeof(allbuf)));
1302 
1303 #ifdef HAVE_POLL
1304   nfds = 0;
1305 #endif
1306   foreach_dlist (ipaddr, ntsa->addr_list) {
1307     /*
1308      * Allocate on stack from -- no need to free
1309      */
1310     fd_ptr = (s_sockfd*)alloca(sizeof(s_sockfd));
1311     fd_ptr->port = ipaddr->GetPortNetOrder();
1312 
1313     /*
1314      * Open a TCP socket
1315      */
1316     for (tlog = 60;
1317          (fd_ptr->fd = socket(ipaddr->GetFamily(), SOCK_STREAM, 0)) < 0;
1318          tlog -= 10) {
1319       if (tlog <= 0) {
1320         BErrNo be;
1321         char curbuf[256];
1322         Emsg3(M_ABORT, 0,
1323               _("Cannot open stream socket. ERR=%s. Current %s All %s\n"),
1324               be.bstrerror(), ipaddr->build_address_str(curbuf, sizeof(curbuf)),
1325               BuildAddressesString(ntsa->addr_list, allbuf, sizeof(allbuf)));
1326       }
1327       Bmicrosleep(10, 0);
1328     }
1329 
1330     /*
1331      * Reuse old sockets
1332      */
1333     if (setsockopt(fd_ptr->fd, SOL_SOCKET, SO_REUSEADDR, (sockopt_val_t)&turnon,
1334                    sizeof(turnon)) < 0) {
1335       BErrNo be;
1336       Emsg1(M_WARNING, 0, _("Cannot set SO_REUSEADDR on socket: %s\n"),
1337             be.bstrerror());
1338     }
1339 
1340     tmax = 30 * (60 / 5); /* wait 30 minutes max */
1341     for (tlog = 0;
1342          bind(fd_ptr->fd, ipaddr->get_sockaddr(), ipaddr->GetSockaddrLen()) < 0;
1343          tlog -= 5) {
1344       BErrNo be;
1345       if (tlog <= 0) {
1346         tlog = 2 * 60; /* Complain every 2 minutes */
1347         Emsg2(M_WARNING, 0, _("Cannot bind port %d: ERR=%s: Retrying ...\n"),
1348               ntohs(fd_ptr->port), be.bstrerror());
1349       }
1350       Bmicrosleep(5, 0);
1351       if (--tmax <= 0) {
1352         Emsg2(M_ABORT, 0, _("Cannot bind port %d: ERR=%s.\n"),
1353               ntohs(fd_ptr->port), be.bstrerror());
1354       }
1355     }
1356     listen(fd_ptr->fd, me->MaxConnections); /* tell system we are ready */
1357     sockfds.append(fd_ptr);
1358 #ifdef HAVE_POLL
1359     nfds++;
1360 #endif
1361   }
1362 
1363   ntsa->thread_list->Init(ntsa->max_clients, HandleNdmpConnectionRequest);
1364 
1365 #ifdef HAVE_POLL
1366   /*
1367    * Allocate on stack from -- no need to free
1368    */
1369   pfds = (struct pollfd*)alloca(sizeof(struct pollfd) * nfds);
1370   memset(pfds, 0, sizeof(struct pollfd) * nfds);
1371 
1372   nfds = 0;
1373   foreach_alist_null(fd_ptr, &sockfds)
1374   {
1375     pfds[nfds].fd = fd_ptr->fd;
1376     pfds[nfds].events |= POLL_IN;
1377     nfds++;
1378   }
1379 #endif
1380 
1381   /*
1382    * Wait for a connection from the client process.
1383    */
1384   while (!quit) {
1385 #ifndef HAVE_POLL
1386     unsigned int maxfd = 0;
1387     fd_set sockset;
1388     FD_ZERO(&sockset);
1389 
1390     foreach_alist (fd_ptr, &sockfds) {
1391       FD_SET((unsigned)fd_ptr->fd, &sockset);
1392       maxfd = maxfd > (unsigned)fd_ptr->fd ? maxfd : fd_ptr->fd;
1393     }
1394 
1395     errno = 0;
1396     if ((status = select(maxfd + 1, &sockset, NULL, NULL, NULL)) < 0) {
1397       BErrNo be; /* capture errno */
1398       if (errno == EINTR) { continue; }
1399       Emsg1(M_FATAL, 0, _("Error in select: %s\n"), be.bstrerror());
1400       break;
1401     }
1402 
1403     foreach_alist (fd_ptr, &sockfds) {
1404       if (FD_ISSET(fd_ptr->fd, &sockset)) {
1405 #else
1406     int cnt;
1407 
1408     errno = 0;
1409     if ((status = poll(pfds, nfds, -1)) < 0) {
1410       BErrNo be; /* capture errno */
1411       if (errno == EINTR) { continue; }
1412       Emsg1(M_FATAL, 0, _("Error in poll: %s\n"), be.bstrerror());
1413       break;
1414     }
1415 
1416     cnt = 0;
1417     foreach_alist_null(fd_ptr, &sockfds)
1418     {
1419       if (pfds[cnt++].revents & POLLIN) {
1420 #endif
1421         /*
1422          * Got a connection, now accept it.
1423          */
1424         do {
1425           clilen = sizeof(cli_addr);
1426           new_sockfd = accept(fd_ptr->fd, &cli_addr, &clilen);
1427         } while (new_sockfd < 0 && errno == EINTR);
1428         if (new_sockfd < 0) { continue; }
1429 #ifdef HAVE_LIBWRAP
1430         P(mutex); /* HostsAccess is not thread safe */
1431         request_init(&request, RQ_DAEMON, my_name, RQ_FILE, new_sockfd, 0);
1432         fromhost(&request);
1433         if (!HostsAccess(&request)) {
1434           V(mutex);
1435           Jmsg2(NULL, M_SECURITY, 0,
1436                 _("Connection from %s:%d refused by hosts.access\n"),
1437                 SockaddrToAscii(&cli_addr, buf, sizeof(buf)),
1438                 SockaddrGetPort(&cli_addr));
1439           close(new_sockfd);
1440           continue;
1441         }
1442         V(mutex);
1443 #endif
1444 
1445         /*
1446          * Receive notification when connection dies.
1447          */
1448         if (setsockopt(new_sockfd, SOL_SOCKET, SO_KEEPALIVE,
1449                        (sockopt_val_t)&turnon, sizeof(turnon)) < 0) {
1450           BErrNo be;
1451           Emsg1(M_WARNING, 0, _("Cannot set SO_KEEPALIVE on socket: %s\n"),
1452                 be.bstrerror());
1453         }
1454 
1455         /*
1456          * See who client is. i.e. who connected to us.
1457          */
1458         P(mutex);
1459         SockaddrToAscii(&cli_addr, buf, sizeof(buf));
1460         V(mutex);
1461 
1462         struct ndmp_session_handle* new_handle;
1463         new_handle = (struct ndmp_session_handle*)malloc(
1464             sizeof(struct ndmp_session_handle));
1465         memset(new_handle, 0, sizeof(struct ndmp_session_handle));
1466         new_handle->fd = new_sockfd;
1467         new_handle->host = strdup(buf);
1468         memset(&new_handle->peer_addr, 0, sizeof(new_handle->peer_addr));
1469         memcpy(&new_handle->client_addr, &cli_addr,
1470                sizeof(new_handle->client_addr));
1471 
1472         if (!ntsa->thread_list->CreateAndAddNewThread(my_config, new_handle)) {
1473           Jmsg1(NULL, M_ABORT, 0,
1474                 _("Could not add job to ndmp thread list.\n"));
1475         }
1476       }
1477     }
1478   }
1479 
1480   /*
1481    * Cleanup open files.
1482    */
1483   fd_ptr = (s_sockfd*)sockfds.first();
1484   while (fd_ptr) {
1485     close(fd_ptr->fd);
1486     fd_ptr = (s_sockfd*)sockfds.next();
1487   }
1488 
1489   if (!ntsa->thread_list->ShutdownAndWaitForThreadsToFinish()) {
1490     Emsg1(M_FATAL, 0, _("Could not destroy ndmp thread list.\n"));
1491   }
1492 
1493   return NULL;
1494 }
1495 
1496 int StartNdmpThreadServer(dlist* addr_list, int max_clients)
1497 {
1498   int status;
1499 
1500   ndmp_thread_server_args.addr_list = addr_list;
1501   ndmp_thread_server_args.max_clients = max_clients;
1502   ndmp_thread_server_args.thread_list = &thread_list;
1503 
1504   if ((status = pthread_create(&ndmp_tid, NULL, ndmp_thread_server,
1505                                (void*)&ndmp_thread_server_args)) != 0) {
1506     return status;
1507   }
1508 
1509   ndmp_initialized = true;
1510 
1511   return 0;
1512 }
1513 
1514 void StopNdmpThreadServer()
1515 {
1516   if (!ndmp_initialized) { return; }
1517 
1518   quit = true;
1519   if (!pthread_equal(ndmp_tid, pthread_self())) {
1520     pthread_join(ndmp_tid, NULL);
1521   }
1522 }
1523 #else
1524 void EndOfNdmpBackup(JobControlRecord* jcr) {}
1525 
1526 void EndOfNdmpRestore(JobControlRecord* jcr) {}
1527 #endif /* HAVE_NDMP */
1528 } /* namespace storagedaemon */
1529