1 /*
2    BAREOS® - Backup Archiving REcovery Open Sourced
3 
4    Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
5    Copyright (C) 2011-2012 Planets Communications B.V.
6    Copyright (C) 2013-2020 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  * Kern Sibbald, March MM
25  */
26 /**
27  * @file
28  * Configuration file parser for Bareos Storage daemon
29  */
30 
31 #include "include/bareos.h"
32 #include "stored/stored_conf.h"
33 #include "stored/autochanger_resource.h"
34 #include "stored/device_resource.h"
35 #include "stored/stored.h"
36 #include "stored/stored_globals.h"
37 #include "stored/sd_backends.h"
38 #include "lib/address_conf.h"
39 #include "lib/bareos_resource.h"
40 #include "lib/berrno.h"
41 #include "lib/messages_resource.h"
42 #include "lib/resource_item.h"
43 #include "lib/parse_conf.h"
44 #include "lib/tls_resource_items.h"
45 #define NEED_JANSSON_NAMESPACE 1
46 #include "lib/output_formatter.h"
47 #include "lib/json.h"
48 #include "include/auth_types.h"
49 #include "include/jcr.h"
50 
51 namespace storagedaemon {
52 
53 static BareosResource* sres_head[R_LAST - R_FIRST + 1];
54 static BareosResource** res_head = sres_head;
55 
56 static void FreeResource(BareosResource* sres, int type);
57 static bool SaveResource(int type, ResourceItem* items, int pass);
58 static void DumpResource(int type,
59                          BareosResource* reshdr,
60                          void sendit(void* sock, const char* fmt, ...),
61                          void* sock,
62                          bool hide_sensitive_data,
63                          bool verbose);
64 
65 /* the first configuration pass uses this static memory */
66 static DirectorResource* res_dir;
67 static NdmpResource* res_ndmp;
68 static StorageResource* res_store;
69 static DeviceResource* res_dev;
70 static AutochangerResource* res_changer;
71 
72 static MessagesResource* res_msgs;
73 #include "lib/messages_resource_items.h"
74 
75 /* clang-format off */
76 
77 static ResourceItem store_items[] = {
78   {"Name", CFG_TYPE_NAME, ITEM(res_store, resource_name_), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL},
79   {"Description", CFG_TYPE_STR, ITEM(res_store, description_), 0, 0, NULL, NULL, NULL},
80   {"SdPort", CFG_TYPE_ADDRESSES_PORT, ITEM(res_store, SDaddrs), 0, CFG_ITEM_DEFAULT, SD_DEFAULT_PORT, NULL, NULL},
81   {"SdAddress", CFG_TYPE_ADDRESSES_ADDRESS, ITEM(res_store, SDaddrs), 0, CFG_ITEM_DEFAULT, SD_DEFAULT_PORT, NULL, NULL},
82   {"SdAddresses", CFG_TYPE_ADDRESSES, ITEM(res_store, SDaddrs), 0, CFG_ITEM_DEFAULT, SD_DEFAULT_PORT, NULL, NULL},
83   {"SdSourceAddress", CFG_TYPE_ADDRESSES_ADDRESS, ITEM(res_store, SDsrc_addr), 0, CFG_ITEM_DEFAULT, "0", NULL, NULL},
84   {"WorkingDirectory", CFG_TYPE_DIR, ITEM(res_store, working_directory), 0,
85       CFG_ITEM_DEFAULT | CFG_ITEM_PLATFORM_SPECIFIC, _PATH_BAREOS_WORKINGDIR, NULL, NULL},
86   {"PidDirectory", CFG_TYPE_DIR, ITEM(res_store, pid_directory), 0,
87       CFG_ITEM_DEFAULT | CFG_ITEM_PLATFORM_SPECIFIC, _PATH_BAREOS_PIDDIR, NULL, NULL},
88   {"SubSysDirectory", CFG_TYPE_DIR, ITEM(res_store, subsys_directory), CFG_ITEM_DEPRECATED, 0, NULL, NULL, NULL},
89 #if defined(HAVE_DYNAMIC_SD_BACKENDS)
90   {"BackendDirectory", CFG_TYPE_STR_VECTOR_OF_DIRS, ITEM(res_store, backend_directories), 0,
91       CFG_ITEM_DEFAULT | CFG_ITEM_PLATFORM_SPECIFIC, _PATH_BAREOS_BACKENDDIR, NULL, NULL},
92 #endif
93   {"PluginDirectory", CFG_TYPE_DIR, ITEM(res_store, plugin_directory), 0, 0, NULL, NULL, NULL},
94   {"PluginNames", CFG_TYPE_PLUGIN_NAMES, ITEM(res_store, plugin_names), 0, 0, NULL, NULL, NULL},
95   {"ScriptsDirectory", CFG_TYPE_DIR, ITEM(res_store, scripts_directory), 0, 0, NULL, NULL, NULL},
96   {"MaximumConcurrentJobs", CFG_TYPE_PINT32, ITEM(res_store, MaxConcurrentJobs), 0, CFG_ITEM_DEFAULT, "20", NULL, NULL},
97   {"MaximumConnections", CFG_TYPE_PINT32, ITEM(res_store, MaxConnections), 0, CFG_ITEM_DEFAULT, "42", "15.2.3-", NULL},
98   {"Messages", CFG_TYPE_RES, ITEM(res_store, messages), R_MSGS, 0, NULL, NULL, NULL},
99   {"SdConnectTimeout", CFG_TYPE_TIME, ITEM(res_store, SDConnectTimeout), 0, CFG_ITEM_DEFAULT, "1800" /* 30 minutes */, NULL, NULL},
100   {"FdConnectTimeout", CFG_TYPE_TIME, ITEM(res_store, FDConnectTimeout), 0, CFG_ITEM_DEFAULT, "1800" /* 30 minutes */, NULL, NULL},
101   {"HeartbeatInterval", CFG_TYPE_TIME, ITEM(res_store, heartbeat_interval), 0, CFG_ITEM_DEFAULT, "0", NULL, NULL},
102   {"MaximumNetworkBufferSize", CFG_TYPE_PINT32, ITEM(res_store, max_network_buffer_size), 0, 0, NULL, NULL, NULL},
103   {"ClientConnectWait", CFG_TYPE_TIME, ITEM(res_store, client_wait), 0, CFG_ITEM_DEFAULT, "1800" /* 30 minutes */, NULL, NULL},
104   {"VerId", CFG_TYPE_STR, ITEM(res_store, verid), 0, 0, NULL, NULL, NULL},
105   {"Compatible", CFG_TYPE_BOOL, ITEM(res_store, compatible), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL},
106   {"MaximumBandwidthPerJob", CFG_TYPE_SPEED, ITEM(res_store, max_bandwidth_per_job), 0, 0, NULL, NULL, NULL},
107   {"AllowBandwidthBursting", CFG_TYPE_BOOL, ITEM(res_store, allow_bw_bursting), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL},
108   {"NdmpEnable", CFG_TYPE_BOOL, ITEM(res_store, ndmp_enable), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL},
109   {"NdmpSnooping", CFG_TYPE_BOOL, ITEM(res_store, ndmp_snooping), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL},
110   {"NdmpLogLevel", CFG_TYPE_PINT32, ITEM(res_store, ndmploglevel), 0, CFG_ITEM_DEFAULT, "4", NULL, NULL},
111   {"NdmpAddress", CFG_TYPE_ADDRESSES_ADDRESS, ITEM(res_store, NDMPaddrs), 0, CFG_ITEM_DEFAULT, "10000", NULL, NULL},
112   {"NdmpAddresses", CFG_TYPE_ADDRESSES, ITEM(res_store, NDMPaddrs), 0, CFG_ITEM_DEFAULT, "10000", NULL, NULL},
113   {"NdmpPort", CFG_TYPE_ADDRESSES_PORT, ITEM(res_store, NDMPaddrs), 0, CFG_ITEM_DEFAULT, "10000", NULL, NULL},
114   {"AutoXFlateOnReplication", CFG_TYPE_BOOL, ITEM(res_store, autoxflateonreplication), 0, CFG_ITEM_DEFAULT, "false", "13.4.0-", NULL},
115   {"AbsoluteJobTimeout", CFG_TYPE_PINT32, ITEM(res_store, jcr_watchdog_time), 0, 0, NULL, NULL, NULL},
116   {"CollectDeviceStatistics", CFG_TYPE_BOOL, ITEM(res_store, collect_dev_stats), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL},
117   {"CollectJobStatistics", CFG_TYPE_BOOL, ITEM(res_store, collect_job_stats), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL},
118   {"StatisticsCollectInterval", CFG_TYPE_PINT32, ITEM(res_store, stats_collect_interval), 0, CFG_ITEM_DEFAULT, "30", NULL, NULL},
119   {"DeviceReserveByMediaType", CFG_TYPE_BOOL, ITEM(res_store, device_reserve_by_mediatype), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL},
120   {"FileDeviceConcurrentRead", CFG_TYPE_BOOL, ITEM(res_store, filedevice_concurrent_read), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL},
121   {"SecureEraseCommand", CFG_TYPE_STR, ITEM(res_store, secure_erase_cmdline), 0, 0, NULL, "15.2.1-",
122       "Specify command that will be called when bareos unlinks files."},
123   {"LogTimestampFormat", CFG_TYPE_STR, ITEM(res_store, log_timestamp_format), 0, 0, NULL, "15.2.3-", NULL},
124     TLS_COMMON_CONFIG(res_store),
125     TLS_CERT_CONFIG(res_store),
126   {nullptr, 0, 0, nullptr, 0, 0, nullptr, nullptr, nullptr}
127 };
128 
129 static ResourceItem dir_items[] = {
130   {"Name", CFG_TYPE_NAME, ITEM(res_dir, resource_name_), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL},
131   {"Description", CFG_TYPE_STR, ITEM(res_dir, description_), 0, 0, NULL, NULL, NULL},
132   {"Password", CFG_TYPE_AUTOPASSWORD, ITEM(res_dir, password_), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL},
133   {"Monitor", CFG_TYPE_BOOL, ITEM(res_dir, monitor), 0, 0, NULL, NULL, NULL},
134   {"MaximumBandwidthPerJob", CFG_TYPE_SPEED, ITEM(res_dir, max_bandwidth_per_job), 0, 0, NULL, NULL, NULL},
135   {"KeyEncryptionKey", CFG_TYPE_AUTOPASSWORD, ITEM(res_dir, keyencrkey), 1, 0, NULL, NULL, NULL},
136     TLS_COMMON_CONFIG(res_dir),
137     TLS_CERT_CONFIG(res_dir),
138   {nullptr, 0, 0, nullptr, 0, 0, nullptr, nullptr, nullptr}
139 };
140 
141 static ResourceItem ndmp_items[] = {
142   {"Name", CFG_TYPE_NAME, ITEM(res_ndmp, resource_name_), 0, CFG_ITEM_REQUIRED, 0, NULL, NULL},
143   {"Description", CFG_TYPE_STR, ITEM(res_ndmp, description_), 0, 0, 0, NULL, NULL},
144   {"Username", CFG_TYPE_STR, ITEM(res_ndmp, username), 0, CFG_ITEM_REQUIRED, 0, NULL, NULL},
145   {"Password", CFG_TYPE_AUTOPASSWORD, ITEM(res_ndmp, password), 0, CFG_ITEM_REQUIRED, 0, NULL, NULL},
146   {"AuthType", CFG_TYPE_AUTHTYPE, ITEM(res_ndmp, AuthType), 0, CFG_ITEM_DEFAULT, "None", NULL, NULL},
147   {"LogLevel", CFG_TYPE_PINT32, ITEM(res_ndmp, LogLevel), 0, CFG_ITEM_DEFAULT, "4", NULL, NULL},
148   {nullptr, 0, 0, nullptr, 0, 0, nullptr, nullptr, nullptr}
149 };
150 
151 static ResourceItem dev_items[] = {
152   {"Name", CFG_TYPE_NAME, ITEM(res_dev, resource_name_), 0, CFG_ITEM_REQUIRED, NULL, NULL, "Unique identifier of the resource."},
153   {"Description", CFG_TYPE_STR, ITEM(res_dev, description_), 0, 0, NULL, NULL,
154       "The Description directive provides easier human recognition, but is not used by Bareos directly."},
155   {"MediaType", CFG_TYPE_STRNAME, ITEM(res_dev, media_type), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL},
156   {"DeviceType", CFG_TYPE_DEVTYPE, ITEM(res_dev, dev_type), 0, 0, NULL, NULL, NULL},
157   {"ArchiveDevice", CFG_TYPE_STRNAME, ITEM(res_dev, device_name), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL},
158   {"DeviceOptions", CFG_TYPE_STR, ITEM(res_dev, device_options), 0, 0, NULL, "15.2.0-", NULL},
159   {"DiagnosticDevice", CFG_TYPE_STRNAME, ITEM(res_dev, diag_device_name), 0, 0, NULL, NULL, NULL},
160   {"HardwareEndOfFile", CFG_TYPE_BIT, ITEM(res_dev, cap_bits), CAP_EOF, CFG_ITEM_DEFAULT, "on", NULL, NULL},
161   {"HardwareEndOfMedium", CFG_TYPE_BIT, ITEM(res_dev, cap_bits), CAP_EOM, CFG_ITEM_DEFAULT, "on", NULL, NULL},
162   {"BackwardSpaceRecord", CFG_TYPE_BIT, ITEM(res_dev, cap_bits), CAP_BSR, CFG_ITEM_DEFAULT, "on", NULL, NULL},
163   {"BackwardSpaceFile", CFG_TYPE_BIT, ITEM(res_dev, cap_bits), CAP_BSF, CFG_ITEM_DEFAULT, "on", NULL, NULL},
164   {"BsfAtEom", CFG_TYPE_BIT, ITEM(res_dev, cap_bits), CAP_BSFATEOM, CFG_ITEM_DEFAULT, "off", NULL, NULL},
165   {"TwoEof", CFG_TYPE_BIT, ITEM(res_dev, cap_bits), CAP_TWOEOF, CFG_ITEM_DEFAULT, "off", NULL, NULL},
166   {"ForwardSpaceRecord", CFG_TYPE_BIT, ITEM(res_dev, cap_bits), CAP_FSR, CFG_ITEM_DEFAULT, "on", NULL, NULL},
167   {"ForwardSpaceFile", CFG_TYPE_BIT, ITEM(res_dev, cap_bits), CAP_FSF, CFG_ITEM_DEFAULT, "on", NULL, NULL},
168   {"FastForwardSpaceFile", CFG_TYPE_BIT, ITEM(res_dev, cap_bits), CAP_FASTFSF, CFG_ITEM_DEFAULT, "on", NULL, NULL},
169   {"RemovableMedia", CFG_TYPE_BIT, ITEM(res_dev, cap_bits), CAP_REM, CFG_ITEM_DEFAULT, "on", NULL, NULL},
170   {"RandomAccess", CFG_TYPE_BIT, ITEM(res_dev, cap_bits), CAP_RACCESS, CFG_ITEM_DEFAULT, "off", NULL, NULL},
171   {"AutomaticMount", CFG_TYPE_BIT, ITEM(res_dev, cap_bits), CAP_AUTOMOUNT, CFG_ITEM_DEFAULT, "off", NULL, NULL},
172   {"LabelMedia", CFG_TYPE_BIT, ITEM(res_dev, cap_bits), CAP_LABEL, CFG_ITEM_DEFAULT, "off", NULL, NULL},
173   {"AlwaysOpen", CFG_TYPE_BIT, ITEM(res_dev, cap_bits), CAP_ALWAYSOPEN, CFG_ITEM_DEFAULT, "on", NULL, NULL},
174   {"Autochanger", CFG_TYPE_BIT, ITEM(res_dev, cap_bits), CAP_AUTOCHANGER, CFG_ITEM_DEFAULT, "off", NULL, NULL},
175   {"CloseOnPoll", CFG_TYPE_BIT, ITEM(res_dev, cap_bits), CAP_CLOSEONPOLL, CFG_ITEM_DEFAULT, "off", NULL, NULL},
176   {"BlockPositioning", CFG_TYPE_BIT, ITEM(res_dev, cap_bits), CAP_POSITIONBLOCKS, CFG_ITEM_DEFAULT, "on", NULL, NULL},
177   {"UseMtiocget", CFG_TYPE_BIT, ITEM(res_dev, cap_bits), CAP_MTIOCGET, CFG_ITEM_DEFAULT, "on", NULL, NULL},
178   {"CheckLabels", CFG_TYPE_BIT, ITEM(res_dev, cap_bits), CAP_CHECKLABELS, CFG_ITEM_DEFAULT, "off", NULL, NULL},
179   {"RequiresMount", CFG_TYPE_BIT, ITEM(res_dev, cap_bits), CAP_REQMOUNT, CFG_ITEM_DEFAULT, "off", NULL, NULL},
180   {"OfflineOnUnmount", CFG_TYPE_BIT, ITEM(res_dev, cap_bits), CAP_OFFLINEUNMOUNT, CFG_ITEM_DEFAULT, "off", NULL, NULL},
181   {"BlockChecksum", CFG_TYPE_BIT, ITEM(res_dev, cap_bits), CAP_BLOCKCHECKSUM, CFG_ITEM_DEFAULT, "on", NULL, NULL},
182   {"AutoSelect", CFG_TYPE_BOOL, ITEM(res_dev, autoselect), 0, CFG_ITEM_DEFAULT, "true", NULL, NULL},
183   {"ChangerDevice", CFG_TYPE_STRNAME, ITEM(res_dev, changer_name), 0, 0, NULL, NULL, NULL},
184   {"ChangerCommand", CFG_TYPE_STRNAME, ITEM(res_dev, changer_command), 0, 0, NULL, NULL, NULL},
185   {"AlertCommand", CFG_TYPE_STRNAME, ITEM(res_dev, alert_command), 0, 0, NULL, NULL, NULL},
186   {"MaximumChangerWait", CFG_TYPE_TIME, ITEM(res_dev, max_changer_wait), 0, CFG_ITEM_DEFAULT,
187       "300" /* 5 minutes */, NULL, NULL},
188   {"MaximumOpenWait", CFG_TYPE_TIME, ITEM(res_dev, max_open_wait), 0, CFG_ITEM_DEFAULT, "300" /* 5 minutes */, NULL, NULL},
189   {"MaximumOpenVolumes", CFG_TYPE_PINT32, ITEM(res_dev, max_open_vols), 0, CFG_ITEM_DEFAULT, "1", NULL, NULL},
190   {"MaximumNetworkBufferSize", CFG_TYPE_PINT32, ITEM(res_dev, max_network_buffer_size), 0, 0, NULL, NULL, NULL},
191   {"VolumePollInterval", CFG_TYPE_TIME, ITEM(res_dev, vol_poll_interval), 0, CFG_ITEM_DEFAULT, "300" /* 5 minutes */, NULL, NULL},
192   {"MaximumRewindWait", CFG_TYPE_TIME, ITEM(res_dev, max_rewind_wait), 0, CFG_ITEM_DEFAULT,
193       "300" /* 5 minutes */, NULL, NULL},
194   {"LabelBlockSize", CFG_TYPE_PINT32, ITEM(res_dev, label_block_size), 0, CFG_ITEM_DEFAULT,
195       "64512" /* DEFAULT_BLOCK_SIZE */, NULL, NULL},
196   {"MinimumBlockSize", CFG_TYPE_PINT32, ITEM(res_dev, min_block_size), 0, 0, NULL, NULL, NULL},
197   {"MaximumBlockSize", CFG_TYPE_MAXBLOCKSIZE, ITEM(res_dev, max_block_size), 0, 0, NULL, NULL, NULL},
198   {"MaximumVolumeSize", CFG_TYPE_SIZE64, ITEM(res_dev, max_volume_size), 0, CFG_ITEM_DEPRECATED, NULL, NULL, NULL},
199   {"MaximumFileSize", CFG_TYPE_SIZE64, ITEM(res_dev, max_file_size), 0, CFG_ITEM_DEFAULT, "1000000000", NULL, NULL},
200   {"VolumeCapacity", CFG_TYPE_SIZE64, ITEM(res_dev, volume_capacity), 0, 0, NULL, NULL, NULL},
201   {"MaximumConcurrentJobs", CFG_TYPE_PINT32, ITEM(res_dev, max_concurrent_jobs), 0, 0, NULL, NULL, NULL},
202   {"SpoolDirectory", CFG_TYPE_DIR, ITEM(res_dev, spool_directory), 0, 0, NULL, NULL, NULL},
203   {"MaximumSpoolSize", CFG_TYPE_SIZE64, ITEM(res_dev, max_spool_size), 0, 0, NULL, NULL, NULL},
204   {"MaximumJobSpoolSize", CFG_TYPE_SIZE64, ITEM(res_dev, max_job_spool_size), 0, 0, NULL, NULL, NULL},
205   {"DriveIndex", CFG_TYPE_PINT16, ITEM(res_dev, drive_index), 0, 0, NULL, NULL, NULL},
206   {"MaximumPartSize", CFG_TYPE_SIZE64, ITEM(res_dev, max_part_size), 0, CFG_ITEM_DEPRECATED, NULL, NULL, NULL},
207   {"MountPoint", CFG_TYPE_STRNAME, ITEM(res_dev, mount_point), 0, 0, NULL, NULL, NULL},
208   {"MountCommand", CFG_TYPE_STRNAME, ITEM(res_dev, mount_command), 0, 0, NULL, NULL, NULL},
209   {"UnmountCommand", CFG_TYPE_STRNAME, ITEM(res_dev, unmount_command), 0, 0, NULL, NULL, NULL},
210   {"WritePartCommand", CFG_TYPE_STRNAME, ITEM(res_dev, write_part_command), 0, CFG_ITEM_DEPRECATED, NULL, NULL, NULL},
211   {"FreeSpaceCommand", CFG_TYPE_STRNAME, ITEM(res_dev, free_space_command), 0, CFG_ITEM_DEPRECATED, NULL, NULL, NULL},
212   {"LabelType", CFG_TYPE_LABEL, ITEM(res_dev, label_type), 0, 0, NULL, NULL, NULL},
213   {"NoRewindOnClose", CFG_TYPE_BOOL, ITEM(res_dev, norewindonclose), 0, CFG_ITEM_DEFAULT, "true", NULL, NULL},
214   {"DriveTapeAlertEnabled", CFG_TYPE_BOOL, ITEM(res_dev, drive_tapealert_enabled), 0, 0, NULL, NULL, NULL},
215   {"DriveCryptoEnabled", CFG_TYPE_BOOL, ITEM(res_dev, drive_crypto_enabled), 0, 0, NULL, NULL, NULL},
216   {"QueryCryptoStatus", CFG_TYPE_BOOL, ITEM(res_dev, query_crypto_status), 0, 0, NULL, NULL, NULL},
217   {"AutoDeflate", CFG_TYPE_IODIRECTION, ITEM(res_dev, autodeflate), 0, 0, NULL, "13.4.0-", NULL},
218   {"AutoDeflateAlgorithm", CFG_TYPE_CMPRSALGO, ITEM(res_dev, autodeflate_algorithm), 0, 0, NULL, "13.4.0-", NULL},
219   {"AutoDeflateLevel", CFG_TYPE_PINT16, ITEM(res_dev, autodeflate_level), 0, CFG_ITEM_DEFAULT, "6", "13.4.0-",NULL},
220   {"AutoInflate", CFG_TYPE_IODIRECTION, ITEM(res_dev, autoinflate), 0, 0, NULL, "13.4.0-", NULL},
221   {"CollectStatistics", CFG_TYPE_BOOL, ITEM(res_dev, collectstats), 0, CFG_ITEM_DEFAULT, "true", NULL, NULL},
222   {"EofOnErrorIsEot", CFG_TYPE_BOOL, ITEM(res_dev, eof_on_error_is_eot), 0, CFG_ITEM_DEFAULT, NULL, "18.2.4-",
223       "If Yes, Bareos will treat any read error at an end-of-file mark as end-of-tape. You should only set "
224       "this option if your tape-drive fails to detect end-of-tape while reading."},
225   {"Count", CFG_TYPE_PINT32, ITEM(res_dev, count), 0, CFG_ITEM_DEFAULT, "1", NULL, "If Count is set to (1 < Count < 10000), "
226   "this resource will be multiplied Count times. The names of multiplied resources will have a serial number (0001, 0002, ...) attached. "
227   "If set to 1 only this single resource will be used and its name will not be altered."},
228   {nullptr, 0, 0, nullptr, 0, 0, nullptr, nullptr, nullptr}
229 };
230 
231 static ResourceItem autochanger_items[] = {
232   {"Name", CFG_TYPE_NAME, ITEM(res_changer, resource_name_), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL},
233   {"Description", CFG_TYPE_STR, ITEM(res_changer, description_), 0, 0, NULL, NULL, NULL},
234   {"Device", CFG_TYPE_ALIST_RES, ITEM(res_changer, device), R_DEVICE, CFG_ITEM_REQUIRED, NULL, NULL, NULL},
235   {"ChangerDevice", CFG_TYPE_STRNAME, ITEM(res_changer, changer_name), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL},
236   {"ChangerCommand", CFG_TYPE_STRNAME, ITEM(res_changer, changer_command), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL},
237   {nullptr, 0, 0, nullptr, 0, 0, nullptr, nullptr, nullptr}
238 };
239 
240 static ResourceTable resources[] = {
241   {"Director", dir_items, R_DIRECTOR, sizeof(DirectorResource),
__anon7447261b0102() 242       []() { res_dir = new DirectorResource(); }, reinterpret_cast<BareosResource**>(&res_dir)},
243   {"Ndmp", ndmp_items, R_NDMP, sizeof(NdmpResource),
__anon7447261b0202() 244       []() { res_ndmp = new NdmpResource(); }, reinterpret_cast<BareosResource**>(&res_ndmp)},
245   {"Storage", store_items, R_STORAGE, sizeof(StorageResource),
__anon7447261b0302() 246       []() { res_store = new StorageResource(); }, reinterpret_cast<BareosResource**>(&res_store)},
247   {"Device", dev_items, R_DEVICE, sizeof(DeviceResource),
__anon7447261b0402() 248       []() { res_dev = new DeviceResource(); }, reinterpret_cast<BareosResource**>(&res_dev)},
249   {"Messages", msgs_items, R_MSGS, sizeof(MessagesResource),
__anon7447261b0502() 250       []() { res_msgs = new MessagesResource(); }, reinterpret_cast<BareosResource**>(&res_msgs)},
251   {"Autochanger", autochanger_items, R_AUTOCHANGER, sizeof(AutochangerResource),
__anon7447261b0602() 252       []() { res_changer = new AutochangerResource(); }, reinterpret_cast<BareosResource**>(&res_changer)},
253   {nullptr, nullptr, 0, 0, nullptr, nullptr}};
254 
255 /* clang-format on */
256 
257 static struct s_kw authentication_methods[] = {{"None", AT_NONE},
258                                                {"Clear", AT_CLEAR},
259                                                {"MD5", AT_MD5},
260                                                {NULL, 0}};
261 
262 static s_kw device_types[] = {
263     {"file", B_FILE_DEV},
264     {"tape", B_TAPE_DEV},
265     {"fifo", B_FIFO_DEV},
266     {"vtl", B_VTL_DEV},
267     {"gfapi", B_GFAPI_DEV},
268     /* compatibility: object have been renamed to droplet */
269     {"object", B_DROPLET_DEV},
270     {"droplet", B_DROPLET_DEV},
271     {"rados", B_RADOS_DEV},
272     {"cephfs", B_CEPHFS_DEV},
273     {"elasto", B_ELASTO_DEV},
274     {NULL, 0}};
275 
276 static s_kw io_directions[] = {{"in", IO_DIRECTION_IN},
277                                {"out", IO_DIRECTION_OUT},
278                                {"both", IO_DIRECTION_INOUT},
279                                {NULL, 0}};
280 
281 static s_kw compression_algorithms[] = {
282     {"gzip", COMPRESS_GZIP},   {"lzo", COMPRESS_LZO1X},
283     {"lzfast", COMPRESS_FZFZ}, {"lz4", COMPRESS_FZ4L},
284     {"lz4hc", COMPRESS_FZ4H},  {NULL, 0}};
285 
StoreAuthenticationType(LEX * lc,ResourceItem * item,int index,int pass)286 static void StoreAuthenticationType(LEX* lc,
287                                     ResourceItem* item,
288                                     int index,
289                                     int pass)
290 {
291   int i;
292 
293   LexGetToken(lc, BCT_NAME);
294   /*
295    * Store the type both pass 1 and pass 2
296    */
297   for (i = 0; authentication_methods[i].name; i++) {
298     if (Bstrcasecmp(lc->str, authentication_methods[i].name)) {
299       SetItemVariable<uint32_t>(*item, authentication_methods[i].token);
300       i = 0;
301       break;
302     }
303   }
304   if (i != 0) {
305     scan_err1(lc, _("Expected a Authentication Type keyword, got: %s"),
306               lc->str);
307   }
308   ScanToEol(lc);
309   SetBit(index, (*item->allocated_resource)->item_present_);
310   ClearBit(index, (*item->allocated_resource)->inherit_content_);
311 }
312 
313 /**
314  * Store password either clear if for NDMP or MD5 hashed for native.
315  */
StoreAutopassword(LEX * lc,ResourceItem * item,int index,int pass)316 static void StoreAutopassword(LEX* lc, ResourceItem* item, int index, int pass)
317 {
318   switch ((*item->allocated_resource)->rcode_) {
319     case R_DIRECTOR:
320       /*
321        * As we need to store both clear and MD5 hashed within the same
322        * resource class we use the item->code as a hint default is 0
323        * and for clear we need a code of 1.
324        */
325       switch (item->code) {
326         case 1:
327           my_config->StoreResource(CFG_TYPE_CLEARPASSWORD, lc, item, index,
328                                    pass);
329           break;
330         default:
331           my_config->StoreResource(CFG_TYPE_MD5PASSWORD, lc, item, index, pass);
332           break;
333       }
334       break;
335     case R_NDMP:
336       my_config->StoreResource(CFG_TYPE_CLEARPASSWORD, lc, item, index, pass);
337       break;
338     default:
339       my_config->StoreResource(CFG_TYPE_MD5PASSWORD, lc, item, index, pass);
340       break;
341   }
342 }
343 
StoreDeviceType(LEX * lc,ResourceItem * item,int index,int pass)344 static void StoreDeviceType(LEX* lc, ResourceItem* item, int index, int pass)
345 {
346   int i;
347 
348   LexGetToken(lc, BCT_NAME);
349   /*
350    * Store the label pass 2 so that type is defined
351    */
352   for (i = 0; device_types[i].name; i++) {
353     if (Bstrcasecmp(lc->str, device_types[i].name)) {
354       SetItemVariable<uint32_t>(*item, device_types[i].token);
355       i = 0;
356       break;
357     }
358   }
359   if (i != 0) {
360     scan_err1(lc, _("Expected a Device Type keyword, got: %s"), lc->str);
361   }
362   ScanToEol(lc);
363   SetBit(index, (*item->allocated_resource)->item_present_);
364   ClearBit(index, (*item->allocated_resource)->inherit_content_);
365 }
366 
367 /**
368  * Store Maximum Block Size, and check it is not greater than MAX_BLOCK_LENGTH
369  */
StoreMaxblocksize(LEX * lc,ResourceItem * item,int index,int pass)370 static void StoreMaxblocksize(LEX* lc, ResourceItem* item, int index, int pass)
371 {
372   my_config->StoreResource(CFG_TYPE_SIZE32, lc, item, index, pass);
373   if (GetItemVariable<uint32_t>(*item) > MAX_BLOCK_LENGTH) {
374     scan_err2(lc,
375               _("Maximum Block Size configured value %u is greater than "
376                 "allowed maximum: %u"),
377               GetItemVariable<uint32_t>(*item), MAX_BLOCK_LENGTH);
378   }
379 }
380 
381 /**
382  * Store the IO direction on a certain device.
383  */
StoreIoDirection(LEX * lc,ResourceItem * item,int index,int pass)384 static void StoreIoDirection(LEX* lc, ResourceItem* item, int index, int pass)
385 {
386   int i;
387 
388   LexGetToken(lc, BCT_NAME);
389   for (i = 0; io_directions[i].name; i++) {
390     if (Bstrcasecmp(lc->str, io_directions[i].name)) {
391       SetItemVariable<uint16_t>(*item, io_directions[i].token & 0xffff);
392       i = 0;
393       break;
394     }
395   }
396   if (i != 0) {
397     scan_err1(lc, _("Expected a IO direction keyword, got: %s"), lc->str);
398   }
399   ScanToEol(lc);
400   SetBit(index, (*item->allocated_resource)->item_present_);
401   ClearBit(index, (*item->allocated_resource)->inherit_content_);
402 }
403 
404 /**
405  * Store the compression algorithm to use on a certain device.
406  */
StoreCompressionalgorithm(LEX * lc,ResourceItem * item,int index,int pass)407 static void StoreCompressionalgorithm(LEX* lc,
408                                       ResourceItem* item,
409                                       int index,
410                                       int pass)
411 {
412   int i;
413 
414   LexGetToken(lc, BCT_NAME);
415   for (i = 0; compression_algorithms[i].name; i++) {
416     if (Bstrcasecmp(lc->str, compression_algorithms[i].name)) {
417       SetItemVariable<uint32_t>(*item,
418                                 compression_algorithms[i].token & 0xffffffff);
419       i = 0;
420       break;
421     }
422   }
423   if (i != 0) {
424     scan_err1(lc, _("Expected a Compression algorithm keyword, got: %s"),
425               lc->str);
426   }
427   ScanToEol(lc);
428   SetBit(index, (*item->allocated_resource)->item_present_);
429   ClearBit(index, (*item->allocated_resource)->inherit_content_);
430 }
431 
432 /**
433  * callback function for init_resource
434  * See ../lib/parse_conf.c, function InitResource, for more generic handling.
435  */
InitResourceCb(ResourceItem * item,int pass)436 static void InitResourceCb(ResourceItem* item, int pass)
437 {
438   switch (pass) {
439     case 1:
440       switch (item->type) {
441         case CFG_TYPE_AUTHTYPE:
442           for (int i = 0; authentication_methods[i].name; i++) {
443             if (Bstrcasecmp(item->default_value,
444                             authentication_methods[i].name)) {
445               SetItemVariable<uint32_t>(*item, authentication_methods[i].token);
446             }
447           }
448           break;
449         default:
450           break;
451       }
452       break;
453     default:
454       break;
455   }
456 }
457 
ParseConfigCb(LEX * lc,ResourceItem * item,int index,int pass)458 static void ParseConfigCb(LEX* lc, ResourceItem* item, int index, int pass)
459 {
460   switch (item->type) {
461     case CFG_TYPE_AUTOPASSWORD:
462       StoreAutopassword(lc, item, index, pass);
463       break;
464     case CFG_TYPE_AUTHTYPE:
465       StoreAuthenticationType(lc, item, index, pass);
466       break;
467     case CFG_TYPE_DEVTYPE:
468       StoreDeviceType(lc, item, index, pass);
469       break;
470     case CFG_TYPE_MAXBLOCKSIZE:
471       StoreMaxblocksize(lc, item, index, pass);
472       break;
473     case CFG_TYPE_IODIRECTION:
474       StoreIoDirection(lc, item, index, pass);
475       break;
476     case CFG_TYPE_CMPRSALGO:
477       StoreCompressionalgorithm(lc, item, index, pass);
478       break;
479     default:
480       break;
481   }
482 }
483 
MultiplyDevice(DeviceResource & multiplied_device_resource)484 static void MultiplyDevice(DeviceResource& multiplied_device_resource)
485 {
486   /* append 0001 to the name of the existing resource */
487   multiplied_device_resource.CreateAndAssignSerialNumber(1);
488 
489   multiplied_device_resource.multiplied_device_resource =
490       std::addressof(multiplied_device_resource);
491 
492   uint32_t count = multiplied_device_resource.count - 1;
493 
494   /* create the copied devices */
495   for (uint32_t i = 0; i < count; i++) {
496     DeviceResource* copied_device_resource =
497         new DeviceResource(multiplied_device_resource);
498 
499     /* append 0002, 0003, ... */
500     copied_device_resource->CreateAndAssignSerialNumber(i + 2);
501 
502     copied_device_resource->multiplied_device_resource =
503         std::addressof(multiplied_device_resource);
504     copied_device_resource->count = 0;
505 
506     my_config->AppendToResourcesChain(copied_device_resource,
507                                       copied_device_resource->rcode_);
508 
509     if (copied_device_resource->changer_res) {
510       if (copied_device_resource->changer_res->device) {
511         copied_device_resource->changer_res->device->append(
512             copied_device_resource);
513       }
514     }
515   }
516 }
517 
MultiplyConfiguredDevices(ConfigurationParser & my_config)518 static void MultiplyConfiguredDevices(ConfigurationParser& my_config)
519 {
520   BareosResource* p = nullptr;
521   while ((p = my_config.GetNextRes(R_DEVICE, p))) {
522     DeviceResource& d = dynamic_cast<DeviceResource&>(*p);
523     if (d.count > 1) { MultiplyDevice(d); }
524   }
525 }
526 
ConfigBeforeCallback(ConfigurationParser & my_config)527 static void ConfigBeforeCallback(ConfigurationParser& my_config)
528 {
529   std::map<int, std::string> map{
530       {R_DIRECTOR, "R_DIRECTOR"},
531       {R_JOB, "R_JOB"}, /* needed for client name conversion */
532       {R_NDMP, "R_NDMP"},
533       {R_STORAGE, "R_STORAGE"},
534       {R_MSGS, "R_MSGS"},
535       {R_DEVICE, "R_DEVICE"},
536       {R_AUTOCHANGER, "R_AUTOCHANGER"},
537       {R_CLIENT, "R_CLIENT"}}; /* needed for network dump */
538   my_config.InitializeQualifiedResourceNameTypeConverter(map);
539 }
540 
CheckDropletDevices(ConfigurationParser & my_config)541 static void CheckDropletDevices(ConfigurationParser& my_config)
542 {
543   BareosResource* p = nullptr;
544 
545   while ((p = my_config.GetNextRes(R_DEVICE, p)) != nullptr) {
546     DeviceResource* device = dynamic_cast<DeviceResource*>(p);
547     if (device && device->dev_type == B_DROPLET_DEV) {
548       if (device->max_concurrent_jobs == 0) {
549         /*
550          * 0 is the general default. However, for this dev_type, only 1 works.
551          * So we set it to this value.
552          */
553         Jmsg1(nullptr, M_WARNING, 0,
554               _("device %s is set to the default 'Maximum Concurrent Jobs' = "
555                 "1.\n"),
556               device->device_name);
557         device->max_concurrent_jobs = 1;
558       } else if (device->max_concurrent_jobs > 1) {
559         Jmsg2(nullptr, M_ERROR_TERM, 0,
560               _("device %s is configured with 'Maximum Concurrent Jobs' = %d, "
561                 "however only 1 is supported.\n"),
562               device->device_name, device->max_concurrent_jobs);
563       }
564     }
565   }
566 }
567 
ConfigReadyCallback(ConfigurationParser & my_config)568 static void ConfigReadyCallback(ConfigurationParser& my_config)
569 {
570   MultiplyConfiguredDevices(my_config);
571   CheckDropletDevices(my_config);
572 }
573 
InitSdConfig(const char * configfile,int exit_code)574 ConfigurationParser* InitSdConfig(const char* configfile, int exit_code)
575 {
576   ConfigurationParser* config = new ConfigurationParser(
577       configfile, nullptr, nullptr, InitResourceCb, ParseConfigCb, nullptr,
578       exit_code, R_FIRST, R_LAST, resources, res_head,
579       default_config_filename.c_str(), "bareos-sd.d", ConfigBeforeCallback,
580       ConfigReadyCallback, SaveResource, DumpResource, FreeResource);
581   if (config) { config->r_own_ = R_STORAGE; }
582   return config;
583 }
584 
ParseSdConfig(const char * configfile,int exit_code)585 bool ParseSdConfig(const char* configfile, int exit_code)
586 {
587   bool retval;
588 
589   retval = my_config->ParseConfig();
590 
591   if (retval) {
592     me = (StorageResource*)my_config->GetNextRes(R_STORAGE, NULL);
593     my_config->own_resource_ = me;
594     if (!me) {
595       Emsg1(exit_code, 0,
596             _("No Storage resource defined in %s. Cannot continue.\n"),
597             configfile);
598       return retval;
599     }
600 
601 #if defined(HAVE_DYNAMIC_SD_BACKENDS)
602     SdSetBackendDirs(std::move(me->backend_directories));
603 #endif
604   }
605 
606   return retval;
607 }
608 
609 /**
610  * Print configuration file schema in json format
611  */
612 #ifdef HAVE_JANSSON
PrintConfigSchemaJson(PoolMem & buffer)613 bool PrintConfigSchemaJson(PoolMem& buffer)
614 {
615   ResourceTable* resources = my_config->resources_;
616 
617   InitializeJson();
618 
619   json_t* json = json_object();
620   json_object_set_new(json, "format-version", json_integer(2));
621   json_object_set_new(json, "component", json_string("bareos-sd"));
622   json_object_set_new(json, "version", json_string(kBareosVersionStrings.Full));
623 
624   /*
625    * Resources
626    */
627   json_t* resource = json_object();
628   json_object_set(json, "resource", resource);
629   json_t* bareos_sd = json_object();
630   json_object_set(resource, "bareos-sd", bareos_sd);
631 
632   for (int r = 0; resources[r].name; r++) {
633     ResourceTable resource = my_config->resources_[r];
634     json_object_set(bareos_sd, resource.name, json_items(resource.items));
635   }
636 
637   PmStrcat(buffer, json_dumps(json, JSON_INDENT(2)));
638   json_decref(json);
639 
640   return true;
641 }
642 #else
PrintConfigSchemaJson(PoolMem & buffer)643 bool PrintConfigSchemaJson(PoolMem& buffer)
644 {
645   PmStrcat(buffer, "{ \"success\": false, \"message\": \"not available\" }");
646   return false;
647 }
648 #endif
649 
650 #include <cassert>
651 
DumpResource_(int type,BareosResource * res,void sendit (void * sock,const char * fmt,...),void * sock,bool hide_sensitive_data,bool verbose)652 static bool DumpResource_(int type,
653                           BareosResource* res,
654                           void sendit(void* sock, const char* fmt, ...),
655                           void* sock,
656                           bool hide_sensitive_data,
657                           bool verbose)
658 {
659   PoolMem buf;
660   bool recurse = true;
661 
662   if (!res) {
663     sendit(sock, _("Warning: no \"%s\" resource (%d) defined.\n"),
664            my_config->ResToStr(type), type);
665     return false;
666   }
667 
668   if (type < 0) { /* no recursion */
669     type = -type;
670     recurse = false;
671   }
672 
673   bool buffer_is_valid = true;
674 
675   switch (type) {
676     case R_MSGS: {
677       MessagesResource* resclass = dynamic_cast<MessagesResource*>(res);
678       assert(resclass);
679       resclass->PrintConfig(buf, *my_config);
680       break;
681     }
682     case R_DEVICE: {
683       DeviceResource* dev = dynamic_cast<DeviceResource*>(res);
684       assert(dev);
685       buffer_is_valid = dev->PrintConfig(buf, *my_config);
686       break;
687     }
688     case R_AUTOCHANGER: {
689       AutochangerResource* autochanger =
690           dynamic_cast<AutochangerResource*>(res);
691       assert(autochanger);
692       autochanger->PrintConfigToBuffer(buf);
693       break;
694     }
695     default:
696       BareosResource* p = dynamic_cast<BareosResource*>(res);
697       assert(p);
698       p->PrintConfig(buf, *my_config);
699       break;
700   }
701 
702   if (buffer_is_valid) { sendit(sock, "%s", buf.c_str()); }
703 
704   return recurse;
705 }
706 
DumpResource(int type,BareosResource * res,void sendit (void * sock,const char * fmt,...),void * sock,bool hide_sensitive_data,bool verbose)707 static void DumpResource(int type,
708                          BareosResource* res,
709                          void sendit(void* sock, const char* fmt, ...),
710                          void* sock,
711                          bool hide_sensitive_data,
712                          bool verbose)
713 {
714   bool recurse = true;
715   BareosResource* p = res;
716 
717   while (recurse && p) {
718     recurse =
719         DumpResource_(type, p, sendit, sock, hide_sensitive_data, verbose);
720     p = p->next_;
721   }
722 }
723 
SaveResource(int type,ResourceItem * items,int pass)724 static bool SaveResource(int type, ResourceItem* items, int pass)
725 {
726   int rindex = type - R_FIRST;
727   int i;
728   int error = 0;
729 
730   // Ensure that all required items are present
731   for (i = 0; items[i].name; i++) {
732     if (items[i].flags & CFG_ITEM_REQUIRED) {
733       if (!BitIsSet(i, (*items[i].allocated_resource)->item_present_)) {
734         Emsg2(M_ERROR_TERM, 0,
735               _("\"%s\" item is required in \"%s\" resource, but not found.\n"),
736               items[i].name, resources[rindex].name);
737       }
738     }
739 
740     if (i >= MAX_RES_ITEMS) {
741       Emsg1(M_ERROR_TERM, 0, _("Too many items in \"%s\" resource\n"),
742             resources[rindex].name);
743     }
744   }
745 
746   // save previously discovered pointers into dynamic memory
747   if (pass == 2) {
748     switch (type) {
749       case R_DEVICE:
750       case R_MSGS:
751       case R_NDMP:
752         // Resources not containing a resource
753         break;
754       case R_DIRECTOR: {
755         DirectorResource* p = dynamic_cast<DirectorResource*>(
756             my_config->GetResWithName(R_DIRECTOR, res_dir->resource_name_));
757         if (!p) {
758           Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"),
759                 res_dir->resource_name_);
760         } else {
761           p->tls_cert_.allowed_certificate_common_names_ =
762               std::move(res_dir->tls_cert_.allowed_certificate_common_names_);
763         }
764         break;
765       }
766       case R_STORAGE: {
767         StorageResource* p = dynamic_cast<StorageResource*>(
768             my_config->GetResWithName(R_STORAGE, res_store->resource_name_));
769         if (!p) {
770           Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
771                 res_store->resource_name_);
772         } else {
773           p->plugin_names = res_store->plugin_names;
774           p->messages = res_store->messages;
775           p->backend_directories = res_store->backend_directories;
776           p->tls_cert_.allowed_certificate_common_names_ =
777               std::move(res_store->tls_cert_.allowed_certificate_common_names_);
778         }
779         break;
780       }
781       case R_AUTOCHANGER: {
782         AutochangerResource* p =
783             dynamic_cast<AutochangerResource*>(my_config->GetResWithName(
784                 R_AUTOCHANGER, res_changer->resource_name_));
785 
786         if (!p) {
787           Emsg1(M_ERROR_TERM, 0, _("Cannot find AutoChanger resource %s\n"),
788                 res_changer->resource_name_);
789         } else {
790           p->device = res_changer->device;
791 
792           DeviceResource* q = nullptr;
793           foreach_alist (q, p->device) {
794             q->changer_res = p;
795           }
796 
797           int errstat;
798           if ((errstat = RwlInit(&p->changer_lock, PRIO_SD_ACH_ACCESS)) != 0) {
799             BErrNo be;
800             Jmsg1(NULL, M_ERROR_TERM, 0, _("Unable to init lock: ERR=%s\n"),
801                   be.bstrerror(errstat));
802           }
803         }
804         break;
805       }
806       default:
807         printf(_("Unknown resource type %d\n"), type);
808         error = 1;
809         break;
810     }
811 
812     /* resource_name_ was already deep copied during 1. pass
813      * as matter of fact the remaining allocated memory is
814      * redundant and would not be freed in the dynamic resources;
815      *
816      * currently, this is the best place to free that */
817 
818     BareosResource* res = *items[0].allocated_resource;
819 
820     if (res) {
821       if (res->resource_name_) {
822         free(res->resource_name_);
823         res->resource_name_ = nullptr;
824       }
825       if (res->description_) {
826         free(res->description_);
827         res->description_ = nullptr;
828       }
829     }
830     return (error == 0);
831   }
832 
833   if (!error) {
834     BareosResource* new_resource = nullptr;
835     switch (resources[rindex].rcode) {
836       case R_DIRECTOR:
837         new_resource = res_dir;
838         res_dir = nullptr;
839         break;
840       case R_NDMP:
841         new_resource = res_ndmp;
842         res_ndmp = nullptr;
843         break;
844       case R_STORAGE:
845         new_resource = res_store;
846         res_store = nullptr;
847         break;
848       case R_DEVICE:
849         new_resource = res_dev;
850         res_dev = nullptr;
851         break;
852       case R_MSGS:
853         new_resource = res_msgs;
854         res_msgs = nullptr;
855         break;
856       case R_AUTOCHANGER:
857         new_resource = res_changer;
858         res_changer = nullptr;
859         break;
860       default:
861         ASSERT(false);
862         break;
863     }
864     error = my_config->AppendToResourcesChain(new_resource, type) ? 0 : 1;
865   }
866   return (error == 0);
867 }  // namespace storagedaemon
868 
FreeResource(BareosResource * res,int type)869 static void FreeResource(BareosResource* res, int type)
870 {
871   if (!res) return;
872 
873   if (res->resource_name_) {
874     free(res->resource_name_);
875     res->resource_name_ = nullptr;
876   }
877   if (res->description_) {
878     free(res->description_);
879     res->description_ = nullptr;
880   }
881 
882   BareosResource* next_ressource = (BareosResource*)res->next_;
883 
884   switch (type) {
885     case R_DIRECTOR: {
886       DirectorResource* p = dynamic_cast<DirectorResource*>(res);
887       assert(p);
888       if (p->password_.value) { free(p->password_.value); }
889       if (p->address) { free(p->address); }
890       if (p->keyencrkey.value) { free(p->keyencrkey.value); }
891       delete p;
892       break;
893     }
894     case R_NDMP: {
895       NdmpResource* p = dynamic_cast<NdmpResource*>(res);
896       assert(p);
897       if (p->username) { free(p->username); }
898       if (p->password.value) { free(p->password.value); }
899       delete p;
900       break;
901     }
902     case R_AUTOCHANGER: {
903       AutochangerResource* p = dynamic_cast<AutochangerResource*>(res);
904       assert(p);
905       if (p->changer_name) { free(p->changer_name); }
906       if (p->changer_command) { free(p->changer_command); }
907       if (p->device) { delete p->device; }
908       RwlDestroy(&p->changer_lock);
909       delete p;
910       break;
911     }
912     case R_STORAGE: {
913       StorageResource* p = dynamic_cast<StorageResource*>(res);
914       assert(p);
915       if (p->SDaddrs) { FreeAddresses(p->SDaddrs); }
916       if (p->SDsrc_addr) { FreeAddresses(p->SDsrc_addr); }
917       if (p->NDMPaddrs) { FreeAddresses(p->NDMPaddrs); }
918       if (p->working_directory) { free(p->working_directory); }
919       if (p->pid_directory) { free(p->pid_directory); }
920       if (p->subsys_directory) { free(p->subsys_directory); }
921       if (p->plugin_directory) { free(p->plugin_directory); }
922       if (p->plugin_names) { delete p->plugin_names; }
923       if (p->scripts_directory) { free(p->scripts_directory); }
924       if (p->verid) { free(p->verid); }
925       if (p->secure_erase_cmdline) { free(p->secure_erase_cmdline); }
926       if (p->log_timestamp_format) { free(p->log_timestamp_format); }
927       delete p;
928       break;
929     }
930     case R_DEVICE: {
931       DeviceResource* p = dynamic_cast<DeviceResource*>(res);
932       assert(p);
933       if (p->media_type) { free(p->media_type); }
934       if (p->device_name) { free(p->device_name); }
935       if (p->device_options) { free(p->device_options); }
936       if (p->diag_device_name) { free(p->diag_device_name); }
937       if (p->changer_name) { free(p->changer_name); }
938       if (p->changer_command) { free(p->changer_command); }
939       if (p->alert_command) { free(p->alert_command); }
940       if (p->spool_directory) { free(p->spool_directory); }
941       if (p->mount_point) { free(p->mount_point); }
942       if (p->mount_command) { free(p->mount_command); }
943       if (p->unmount_command) { free(p->unmount_command); }
944       if (p->write_part_command) { free(p->write_part_command); }
945       if (p->free_space_command) { free(p->free_space_command); }
946       delete p;
947       break;
948     }
949     case R_MSGS: {
950       MessagesResource* p = dynamic_cast<MessagesResource*>(res);
951       assert(p);
952       delete p;
953       break;
954     }
955     default:
956       Dmsg1(0, _("Unknown resource type %d\n"), type);
957       break;
958   }
959   if (next_ressource) { my_config->FreeResourceCb_(next_ressource, type); }
960 }
961 
962 } /* namespace storagedaemon  */
963