1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2011-2015 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 2015
24 */
25 /**
26 * @file
27 * Generic NDMP Data Management Application (DMA) routines
28 */
29
30 #include "include/bareos.h"
31 #include "dird.h"
32 #include "dird/jcr_private.h"
33 #include "dird/dird_globals.h"
34 #include "include/auth_protocol_types.h"
35 #include "include/auth_types.h"
36
37 #if HAVE_NDMP
38 # define SMTAPE_MIN_BLOCKSIZE 4096 /**< 4 Kb */
39 # define SMTAPE_MAX_BLOCKSIZE 262144 /**< 256 Kb */
40 # define SMTAPE_BLOCKSIZE_INCREMENTS 4096 /**< 4 Kb */
41
42 # include "ndmp/ndmagents.h"
43 # include "ndmp_dma_priv.h"
44 #endif /* HAVE_NDMP */
45
46 namespace directordaemon {
47
48 #if HAVE_NDMP
49 /* Imported variables */
50
51 /* Forward referenced functions */
52
53 /**
54 * Per NDMP format specific options.
55 */
56 static ndmp_backup_format_option ndmp_backup_format_options[] = {
57 /* format uses_file_history uses_level restore_prefix_relative
58 needs_namelist */
59 {(char*)"dump", true, true, true, true},
60 {(char*)"tar", true, false, true, true},
61 {(char*)"smtape", false, true, false, true},
62 {(char*)"zfs", false, true, false, true},
63 {(char*)"vbb", false, true, false, true},
64 {(char*)"image", false, true, false, true},
65 {NULL, false, false, false}};
66
67 /**
68 * find ndmp_backup_format_option for given format
69 * @param [in] backup_format string specifying the backup format
70 * @return returns a pointer to the ndmp_backup_format_option
71 */
ndmp_lookup_backup_format_options(const char * backup_format)72 ndmp_backup_format_option* ndmp_lookup_backup_format_options(
73 const char* backup_format)
74 {
75 int i = 0;
76
77 while (ndmp_backup_format_options[i].format) {
78 if (Bstrcasecmp(backup_format, ndmp_backup_format_options[i].format)) {
79 break;
80 }
81 i++;
82 }
83
84 if (ndmp_backup_format_options[i].format) {
85 return &ndmp_backup_format_options[i];
86 }
87
88 return (ndmp_backup_format_option*)NULL;
89 }
90
91 /**
92 * Validation functions.
93 */
NdmpValidateClient(JobControlRecord * jcr)94 bool NdmpValidateClient(JobControlRecord* jcr)
95 {
96 switch (jcr->impl->res.client->Protocol) {
97 case APT_NDMPV2:
98 case APT_NDMPV3:
99 case APT_NDMPV4:
100 if (jcr->impl->res.client->password_.encoding != p_encoding_clear) {
101 Jmsg(jcr, M_FATAL, 0,
102 _("Client %s, has incompatible password encoding for running NDMP "
103 "backup.\n"),
104 jcr->impl->res.client->resource_name_);
105 return false;
106 }
107 break;
108 default:
109 Jmsg(jcr, M_FATAL, 0,
110 _("Client %s, with backup protocol %s not compatible for running "
111 "NDMP backup.\n"),
112 jcr->impl->res.client->resource_name_,
113 AuthenticationProtocolTypeToString(jcr->impl->res.client->Protocol));
114 return false;
115 }
116
117 return true;
118 }
119
NdmpValidateStorage(JobControlRecord * jcr,StorageResource * store)120 static inline bool NdmpValidateStorage(JobControlRecord* jcr,
121 StorageResource* store)
122 {
123 switch (store->Protocol) {
124 case APT_NDMPV2:
125 case APT_NDMPV3:
126 case APT_NDMPV4:
127 if (store->password_.encoding != p_encoding_clear) {
128 Jmsg(jcr, M_FATAL, 0,
129 _("Storage %s, has incompatible password encoding for running "
130 "NDMP backup.\n"),
131 store->resource_name_);
132 return false;
133 }
134 break;
135 default:
136 Jmsg(jcr, M_FATAL, 0,
137 _("Storage %s has illegal backup protocol %s for NDMP backup\n"),
138 store->resource_name_,
139 AuthenticationProtocolTypeToString(store->Protocol));
140 return false;
141 }
142
143 return true;
144 }
145
NdmpValidateStorage(JobControlRecord * jcr)146 bool NdmpValidateStorage(JobControlRecord* jcr)
147 {
148 StorageResource* store = nullptr;
149
150 if (jcr->impl->res.write_storage_list) {
151 foreach_alist (store, jcr->impl->res.write_storage_list) {
152 if (!NdmpValidateStorage(jcr, store)) { return false; }
153 }
154 } else {
155 foreach_alist (store, jcr->impl->res.read_storage_list) {
156 if (!NdmpValidateStorage(jcr, store)) { return false; }
157 }
158 }
159
160 return true;
161 }
162
NdmpValidateJob(JobControlRecord * jcr,struct ndm_job_param * job)163 bool NdmpValidateJob(JobControlRecord* jcr, struct ndm_job_param* job)
164 {
165 int n_err, i;
166 char audit_buffer[256];
167
168 /*
169 * Audit the job so we only submit a valid NDMP job.
170 */
171 n_err = 0;
172 i = 0;
173 do {
174 n_err = ndma_job_audit(job, audit_buffer, i);
175 if (n_err) {
176 Jmsg(jcr, M_ERROR, 0, _("NDMP Job validation error = %s\n"),
177 audit_buffer);
178 }
179 i++;
180 } while (i < n_err);
181
182 if (n_err) { return false; }
183
184 return true;
185 }
186
187 /**
188 * Fill a ndmagent structure with the correct info. Instead of calling
189 * ndmagent_from_str we fill the structure ourself from info provides in a
190 * resource.
191 */
fill_ndmp_agent_config(JobControlRecord * jcr,struct ndmagent * agent,uint32_t protocol,uint32_t authtype,char * address,uint32_t port,char * username,char * password)192 static inline bool fill_ndmp_agent_config(JobControlRecord* jcr,
193 struct ndmagent* agent,
194 uint32_t protocol,
195 uint32_t authtype,
196 char* address,
197 uint32_t port,
198 char* username,
199 char* password)
200 {
201 agent->conn_type = NDMCONN_TYPE_REMOTE;
202 switch (protocol) {
203 case APT_NDMPV2:
204 agent->protocol_version = 2;
205 break;
206 case APT_NDMPV3:
207 agent->protocol_version = 3;
208 break;
209 case APT_NDMPV4:
210 agent->protocol_version = 4;
211 break;
212 default:
213 Jmsg(jcr, M_FATAL, 0, _("Illegal protocol %d for NDMP Job\n"), protocol);
214 return false;
215 }
216
217 switch (authtype) {
218 case AT_NONE:
219 agent->auth_type = 'n';
220 break;
221 case AT_CLEAR:
222 agent->auth_type = 't';
223 break;
224 case AT_MD5:
225 agent->auth_type = 'm';
226 break;
227 case AT_VOID:
228 agent->auth_type = 'v';
229 break;
230 default:
231 Jmsg(jcr, M_FATAL, 0, _("Illegal authtype %d for NDMP Job\n"), authtype);
232 return false;
233 }
234 /*
235 * sanity checks
236 */
237 if (!address) {
238 Jmsg(jcr, M_FATAL, 0, _("fill_ndmp_agent_config: address is missing\n"));
239 return false;
240 }
241
242 if (!username) {
243 Jmsg(jcr, M_FATAL, 0, _("fill_ndmp_agent_config: username is missing\n"));
244 return false;
245 }
246
247 if (!password) {
248 Jmsg(jcr, M_FATAL, 0, _("fill_ndmp_agent_config: password is missing\n"));
249 return false;
250 }
251
252 if (!port) {
253 Jmsg(jcr, M_FATAL, 0, _("fill_ndmp_agent_config: port is missing\n"));
254 return false;
255 }
256
257 agent->port = port;
258 bstrncpy(agent->host, address, sizeof(agent->host));
259 bstrncpy(agent->account, username, sizeof(agent->account));
260 bstrncpy(agent->password, password, sizeof(agent->password));
261
262 return true;
263 }
264
265 /**
266 * Parse a meta-tag and convert it into a ndmp_pval
267 */
NdmpParseMetaTag(struct ndm_env_table * env_tab,char * meta_tag)268 void NdmpParseMetaTag(struct ndm_env_table* env_tab, char* meta_tag)
269 {
270 char* p;
271 ndmp9_pval pv;
272
273 /*
274 * See if the meta-tag is parseable.
275 */
276 if ((p = strchr(meta_tag, '=')) == NULL) { return; }
277
278 /*
279 * Split the tag on the '='
280 */
281 *p = '\0';
282 pv.name = meta_tag;
283 pv.value = p + 1;
284 ndma_update_env_list(env_tab, &pv);
285
286 /*
287 * Restore the '='
288 */
289 *p = '=';
290 }
291
292 /**
293 * Calculate the wanted NDMP loglevel from the current debug level and
294 * any configure minimum level.
295 */
NativeToNdmpLoglevel(int NdmpLoglevel,int debuglevel,NIS * nis)296 int NativeToNdmpLoglevel(int NdmpLoglevel, int debuglevel, NIS* nis)
297 {
298 unsigned int level;
299
300 nis->LogLevel = NdmpLoglevel;
301
302 /*
303 * NDMP loglevels run from 0 - 9 so we take a look at the
304 * current debug level and divide it by 100 to get a proper
305 * value. If the debuglevel is below the wanted initial level
306 * we set the loglevel to the wanted initial level. As the
307 * debug logging takes care of logging messages that are
308 * unwanted we can set the loglevel higher and still don't
309 * get debug messages.
310 */
311 level = debuglevel / 100;
312 if (level < nis->LogLevel) { level = nis->LogLevel; }
313
314 /*
315 * Make sure the level is in the wanted range.
316 */
317 if (level > 9) { level = 9; }
318
319 return level;
320 }
321
NdmpBuildClientJob(JobControlRecord * jcr,ClientResource * client,StorageResource * store,int operation,struct ndm_job_param * job)322 bool NdmpBuildClientJob(JobControlRecord* jcr,
323 ClientResource* client,
324 StorageResource* store,
325 int operation,
326 struct ndm_job_param* job)
327 {
328 memset(job, 0, sizeof(struct ndm_job_param));
329
330 job->operation = operation;
331 job->bu_type = jcr->impl->backup_format;
332
333 /*
334 * For NDMP the backupformat is a prerequite abort the backup job when
335 * it is not supplied in the config definition.
336 */
337 if (!job->bu_type) {
338 Jmsg(jcr, M_FATAL, 0, _("No backup type specified in NDMP job\n"));
339 goto bail_out;
340 }
341
342 /*
343 * The data_agent is the client being backed up or restored using NDMP.
344 */
345 ASSERT(client->password_.encoding == p_encoding_clear);
346 if (!fill_ndmp_agent_config(jcr, &job->data_agent, client->Protocol,
347 client->AuthType, client->address, client->FDport,
348 client->username, client->password_.value)) {
349 goto bail_out;
350 }
351
352 /*
353 * The tape_agent is the storage daemon via the NDMP protocol.
354 */
355 ASSERT(store->password_.encoding == p_encoding_clear);
356 if (!fill_ndmp_agent_config(jcr, &job->tape_agent, store->Protocol,
357 store->AuthType, store->address, store->SDport,
358 store->username, store->password_.value)) {
359 goto bail_out;
360 }
361
362 if (Bstrcasecmp(jcr->impl->backup_format, "smtape")) {
363 /*
364 * SMTAPE only wants certain blocksizes.
365 */
366 if (jcr->impl->res.client->ndmp_blocksize < SMTAPE_MIN_BLOCKSIZE
367 || jcr->impl->res.client->ndmp_blocksize > SMTAPE_MAX_BLOCKSIZE) {
368 Jmsg(jcr, M_FATAL, 0,
369 _("For SMTAPE NDMP jobs the NDMP blocksize needs to be between %d "
370 "and %d, but is set to %d\n"),
371 SMTAPE_MIN_BLOCKSIZE, SMTAPE_MAX_BLOCKSIZE,
372 jcr->impl->res.client->ndmp_blocksize);
373 goto bail_out;
374 }
375
376 if ((jcr->impl->res.client->ndmp_blocksize % SMTAPE_BLOCKSIZE_INCREMENTS)
377 != 0) {
378 Jmsg(jcr, M_FATAL, 0,
379 _("For SMTAPE NDMP jobs the NDMP blocksize needs to be in "
380 "increments of %d bytes, but is set to %d\n"),
381 SMTAPE_BLOCKSIZE_INCREMENTS, jcr->impl->res.client->ndmp_blocksize);
382 goto bail_out;
383 }
384
385 job->record_size = jcr->impl->res.client->ndmp_blocksize;
386 } else {
387 job->record_size = jcr->impl->res.client->ndmp_blocksize;
388 }
389
390 return true;
391
392 bail_out:
393 return false;
394 }
395
396
NdmpBuildStorageJob(JobControlRecord * jcr,StorageResource * store,bool init_tape,bool init_robot,int operation,struct ndm_job_param * job)397 bool NdmpBuildStorageJob(JobControlRecord* jcr,
398 StorageResource* store,
399 bool init_tape,
400 bool init_robot,
401 int operation,
402 struct ndm_job_param* job)
403 {
404 memset(job, 0, sizeof(struct ndm_job_param));
405
406 job->operation = operation;
407 job->bu_type = jcr->impl->backup_format;
408
409 if (!fill_ndmp_agent_config(jcr, &job->data_agent, store->Protocol,
410 store->AuthType, store->address, store->SDport,
411 store->username, store->password_.value)) {
412 goto bail_out;
413 }
414
415
416 if (init_tape) {
417 /*
418 * Setup the TAPE agent of the NDMP job.
419 */
420 ASSERT(store->password_.encoding == p_encoding_clear);
421 if (!fill_ndmp_agent_config(jcr, &job->tape_agent, store->Protocol,
422 store->AuthType, store->address, store->SDport,
423 store->username, store->password_.value)) {
424 goto bail_out;
425 }
426 }
427
428 if (init_robot) {
429 /*
430 * Setup the ROBOT agent of the NDMP job.
431 */
432 if (!fill_ndmp_agent_config(jcr, &job->robot_agent, store->Protocol,
433 store->AuthType, store->address, store->SDport,
434 store->username, store->password_.value)) {
435 goto bail_out;
436 }
437 }
438
439
440 return true;
441
442 bail_out:
443 return false;
444 }
445
NdmpBuildClientAndStorageJob(JobControlRecord * jcr,StorageResource * store,ClientResource * client,bool init_tape,bool init_robot,int operation,struct ndm_job_param * job)446 bool NdmpBuildClientAndStorageJob(JobControlRecord* jcr,
447 StorageResource* store,
448 ClientResource* client,
449 bool init_tape,
450 bool init_robot,
451 int operation,
452 struct ndm_job_param* job)
453 {
454 /*
455 * setup storage job
456 * i.e. setup tape_agent and robot_agent
457 */
458 if (!NdmpBuildStorageJob(jcr, store, init_tape, init_robot, operation, job)) {
459 goto bail_out;
460 }
461
462 /*
463 * now configure client job
464 * i.e. setup data_agent
465 */
466 if (!fill_ndmp_agent_config(jcr, &job->data_agent, client->Protocol,
467 client->AuthType, client->address, client->FDport,
468 client->username, client->password_.value)) {
469 goto bail_out;
470 }
471
472 return true;
473
474 bail_out:
475 return false;
476 }
477
478 /**
479 * Interface function which glues the logging infra of the NDMP lib with the
480 * daemon.
481 */
NdmpLoghandler(struct ndmlog * log,char * tag,int level,char * msg)482 void NdmpLoghandler(struct ndmlog* log, char* tag, int level, char* msg)
483 {
484 int internal_level;
485 NIS* nis;
486
487 /*
488 * We don't want any trailing newline in log messages.
489 */
490 StripTrailingNewline(msg);
491
492 /*
493 * Make sure if the logging system was setup properly.
494 */
495 nis = (NIS*)log->ctx;
496 if (!nis) { return; }
497
498 /*
499 * If the log level of this message is under our logging treshold we
500 * log it as part of the Job.
501 */
502 if (level <= (int)nis->LogLevel) {
503 if (nis->jcr) {
504 /*
505 * Look at the tag field to see what is logged.
506 */
507 if (bstrncmp(tag + 1, "LM", 2)) {
508 /*
509 * *LM* messages. E.g. log message NDMP protocol msgs.
510 * First character of the tag is the agent sending the
511 * message e.g. 'D' == Data Agent
512 * 'T' == Tape Agent
513 * 'R' == Robot Agent
514 * 'C' == Control Agent (DMA)
515 *
516 * Last character is the type of message e.g.
517 * 'n' - normal message
518 * 'd' - debug message
519 * 'e' - error message
520 * 'w' - warning message
521 * '?' - unknown message level
522 */
523 switch (*(tag + 3)) {
524 case 'n':
525 Jmsg(nis->jcr, M_INFO, 0, "%s\n", msg);
526 break;
527 case 'e':
528 Jmsg(nis->jcr, M_ERROR, 0, "%s\n", msg);
529 break;
530 case 'w':
531 Jmsg(nis->jcr, M_WARNING, 0, "%s\n", msg);
532 break;
533 case '?':
534 Jmsg(nis->jcr, M_INFO, 0, "%s\n", msg);
535 break;
536 default:
537 break;
538 }
539 } else {
540 Jmsg(nis->jcr, M_INFO, 0, "%s\n", msg);
541 }
542 }
543 }
544
545 /*
546 * Print any debug message we convert the NDMP level back to an internal
547 * level and let the normal debug logging handle if it needs to be printed
548 * or not.
549 */
550 internal_level = level * 100;
551 Dmsg3(internal_level, "NDMP: [%s] [%d] %s\n", tag, level, msg);
552 }
553
554 /**
555 * Interface function which glues the logging infra of the NDMP lib to Dmsg
556 * output
557 */
ndmp_log_delivery_cb_to_dmsg(struct ndmlog * log,char * tag,int lev,char * msg)558 extern "C" void ndmp_log_delivery_cb_to_dmsg(struct ndmlog* log,
559 char* tag,
560 int lev,
561 char* msg)
562 {
563 NIS* nis;
564
565 /*
566 * Make sure if the logging system was setup properly.
567 */
568 nis = (NIS*)log->ctx;
569 if (!nis || !nis->jcr) { return; }
570
571 Dmsg1((int)nis->LogLevel, "%s\n", msg);
572 }
573
574
575 /**
576 * Interface function which glues the logging infra of the NDMP lib to Jmsg
577 * output
578 */
ndmp_log_delivery_cb_to_jmsg(struct ndmlog * log,char * tag,int lev,char * msg)579 extern "C" void ndmp_log_delivery_cb_to_jmsg(struct ndmlog* log,
580 char* tag,
581 int lev,
582 char* msg)
583 {
584 NIS* nis;
585
586 /*
587 * Make sure if the logging system was setup properly.
588 */
589 nis = (NIS*)log->ctx;
590 if (!nis || !nis->jcr) { return; }
591
592 Jmsg(nis->jcr, M_INFO, 0, "%s\n", msg);
593 }
594
595 /**
596 * Interface function which glues the logging infra of the NDMP lib with the
597 * user agent
598 */
ndmp_log_delivery_cb_to_ua(struct ndmlog * log,char * tag,int lev,char * msg)599 extern "C" void ndmp_log_delivery_cb_to_ua(struct ndmlog* log,
600 char* tag,
601 int lev,
602 char* msg)
603 {
604 NIS* nis;
605
606 /*
607 * Make sure if the logging system was setup properly.
608 */
609 nis = (NIS*)log->ctx;
610 if (!nis) { return; }
611
612 nis->ua->SendMsg("%s\n", msg);
613 }
614
615 /**
616 * Generic function to query the NDMP server using the NDM_JOB_OP_QUERY_AGENTS
617 * operation. Callback is the above NdmpClientStatusHandler which prints
618 * the data to the user context.
619 */
NdmpDoQuery(UaContext * ua,JobControlRecord * jcr,ndm_job_param * ndmp_job,int NdmpLoglevel,ndmca_query_callbacks * query_cbs)620 void NdmpDoQuery(UaContext* ua,
621 JobControlRecord* jcr,
622 ndm_job_param* ndmp_job,
623 int NdmpLoglevel,
624 ndmca_query_callbacks* query_cbs)
625 {
626 NIS* nis;
627 struct ndm_session ndmp_sess;
628 JobControlRecord* local_jcr = nullptr;
629 /*
630 * Initialize a new NDMP session
631 */
632 memset(&ndmp_sess, 0, sizeof(ndmp_sess));
633 ndmp_sess.param
634 = (struct ndm_session_param*)malloc(sizeof(struct ndm_session_param));
635 memset(ndmp_sess.param, 0, sizeof(struct ndm_session_param));
636 ndmp_sess.param->log.deliver = NdmpLoghandler;
637 nis = (NIS*)malloc(sizeof(NIS));
638 memset(nis, 0, sizeof(NIS));
639 ndmp_sess.param->log_level
640 = NativeToNdmpLoglevel(NdmpLoglevel, debug_level, nis);
641 nis->ua = ua;
642 ndmp_sess.param->log.ctx = nis;
643 ndmp_sess.conn_snooping = (me->ndmp_snooping) ? 1 : 0;
644 ndmp_sess.control_agent_enabled = 1;
645
646 if (ua) {
647 nis->ua = ua;
648 local_jcr = ua->jcr;
649 ndmp_sess.param->log.deliver = ndmp_log_delivery_cb_to_ua;
650
651 } else if (jcr) {
652 nis->jcr = jcr;
653 local_jcr = jcr;
654 ndmp_sess.param->log.deliver = ndmp_log_delivery_cb_to_dmsg;
655
656 } else {
657 goto bail_out;
658 }
659 /*
660 * Register the query callbacks that give us the query results
661 */
662 ndmca_query_register_callbacks(&ndmp_sess, query_cbs);
663
664 /*
665 * Initialize the session structure.
666 */
667 if (ndma_session_initialize(&ndmp_sess)) { goto bail_out; }
668
669 /*
670 * Copy the actual job to perform.
671 */
672 memcpy(&ndmp_sess.control_acb->job, ndmp_job, sizeof(struct ndm_job_param));
673 if (!NdmpValidateJob(local_jcr, &ndmp_sess.control_acb->job)) {
674 goto cleanup;
675 }
676
677 /*
678 * Commission the session for a run.
679 */
680 if (ndma_session_commission(&ndmp_sess)) { goto cleanup; }
681
682 /*
683 * Setup the DMA.
684 */
685 if (ndmca_connect_control_agent(&ndmp_sess)) { goto cleanup; }
686
687 ndmp_sess.conn_open = 1;
688 ndmp_sess.conn_authorized = 1;
689
690 /*
691 * Let the DMA perform its magic.
692 */
693 if (ndmca_control_agent(&ndmp_sess) != 0) { goto cleanup; }
694
695 cleanup:
696 /*
697 * Destroy the session.
698 */
699 ndma_session_destroy(&ndmp_sess);
700
701 bail_out:
702
703 ndmca_query_unregister_callbacks(&ndmp_sess);
704 /*
705 * Free the param block.
706 */
707 if (ndmp_sess.param->log_tag) { free(ndmp_sess.param->log_tag); }
708 free(ndmp_sess.param);
709 free(nis);
710 ndmp_sess.param = NULL;
711 }
712
713 /**
714 * Output the status of a NDMP client. Query the DATA agent of a
715 * native NDMP server to give some info.
716 */
DoNdmpClientStatus(UaContext * ua,ClientResource * client,char * cmd)717 void DoNdmpClientStatus(UaContext* ua, ClientResource* client, char* cmd)
718 {
719 struct ndm_job_param ndmp_job;
720
721 memset(&ndmp_job, 0, sizeof(struct ndm_job_param));
722 ndmp_job.operation = NDM_JOB_OP_QUERY_AGENTS;
723
724 /*
725 * Query the DATA agent of the NDMP server.
726 */
727 ASSERT(client->password_.encoding == p_encoding_clear);
728 if (!fill_ndmp_agent_config(ua->jcr, &ndmp_job.data_agent, client->Protocol,
729 client->AuthType, client->address, client->FDport,
730 client->username, client->password_.value)) {
731 return;
732 }
733
734 ndmca_query_callbacks* query_cbs = nullptr;
735 NdmpDoQuery(ua, NULL, &ndmp_job,
736 (client->ndmp_loglevel > me->ndmp_loglevel)
737 ? client->ndmp_loglevel
738 : me->ndmp_loglevel,
739 query_cbs);
740 }
741 #else
742 void DoNdmpClientStatus(UaContext* ua, ClientResource* client, char* cmd)
743 {
744 Jmsg(ua->jcr, M_FATAL, 0, _("NDMP protocol not supported\n"));
745 }
746
747 #endif /* HAVE_NDMP */
748 } /* namespace directordaemon */
749