]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/filed_conf.c
ebl Add more tests in migration time test (like for copy time test)
[bacula/bacula] / bacula / src / filed / filed_conf.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU 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    General Public License for more details.
17
18    You should have received a copy of the GNU 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    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  *   Main configuration file parser for Bacula File Daemon (Client)
30  *    some parts may be split into separate files such as
31  *    the schedule configuration (sch_config.c).
32  *
33  *   Note, the configuration file parser consists of three parts
34  *
35  *   1. The generic lexical scanner in lib/lex.c and lib/lex.h
36  *
37  *   2. The generic config  scanner in lib/parse_config.c and
38  *      lib/parse_config.h.
39  *      These files contain the parser code, some utility
40  *      routines, and the common store routines (name, int,
41  *      string).
42  *
43  *   3. The daemon specific file, which contains the Resource
44  *      definitions as well as any specific store routines
45  *      for the resource records.
46  *
47  *     Kern Sibbald, September MM
48  *
49  *   Version $Id$
50  */
51
52 #include "bacula.h"
53 #include "filed.h"
54
55 /* Define the first and last resource ID record
56  * types. Note, these should be unique for each
57  * daemon though not a requirement.
58  */
59 int32_t r_first = R_FIRST;
60 int32_t r_last  = R_LAST;
61 static RES *sres_head[R_LAST - R_FIRST + 1];
62 RES **res_head = sres_head;
63
64
65 /* Forward referenced subroutines */
66
67
68 /* We build the current resource here as we are
69  * scanning the resource configuration definition,
70  * then move it to allocated memory when the resource
71  * scan is complete.
72  */
73 #if defined(_MSC_VER)
74 extern "C" { // work around visual compiler mangling variables
75    URES res_all;
76 }
77 #else
78 URES res_all;
79 #endif
80 int32_t res_all_size = sizeof(res_all);
81
82 /* Definition of records permitted within each
83  * resource with the routine to process the record
84  * information.
85  */
86
87 /* Client or File daemon "Global" resources */
88 static RES_ITEM cli_items[] = {
89    {"name",        store_name,  ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
90    {"description", store_str,   ITEM(res_client.hdr.desc), 0, 0, 0},
91    {"fdport",      store_addresses_port,    ITEM(res_client.FDaddrs),  0, ITEM_DEFAULT, 9102},
92    {"fdaddress",   store_addresses_address, ITEM(res_client.FDaddrs),  0, ITEM_DEFAULT, 9102},
93    {"fdaddresses", store_addresses,         ITEM(res_client.FDaddrs),  0, ITEM_DEFAULT, 9102},
94
95    {"workingdirectory",  store_dir, ITEM(res_client.working_directory), 0, ITEM_REQUIRED, 0},
96    {"piddirectory",  store_dir,     ITEM(res_client.pid_directory),     0, ITEM_REQUIRED, 0},
97    {"subsysdirectory",  store_dir,  ITEM(res_client.subsys_directory),  0, 0, 0},
98    {"plugindirectory",  store_dir,  ITEM(res_client.plugin_directory),  0, 0, 0},
99    {"scriptsdirectory", store_dir,  ITEM(res_client.scripts_directory),  0, 0, 0},
100    {"maximumconcurrentjobs", store_pint32,  ITEM(res_client.MaxConcurrentJobs), 0, ITEM_DEFAULT, 20},
101    {"messages",      store_res, ITEM(res_client.messages), R_MSGS, 0, 0},
102    {"sdconnecttimeout", store_time,ITEM(res_client.SDConnectTimeout), 0, ITEM_DEFAULT, 60 * 30},
103    {"heartbeatinterval", store_time, ITEM(res_client.heartbeat_interval), 0, ITEM_DEFAULT, 0},
104    {"maximumnetworkbuffersize", store_pint32, ITEM(res_client.max_network_buffer_size), 0, 0, 0},
105 #ifdef DATA_ENCRYPTION
106    {"pkisignatures",         store_bool,    ITEM(res_client.pki_sign), 0, ITEM_DEFAULT, 0},
107    {"pkiencryption",         store_bool,    ITEM(res_client.pki_encrypt), 0, ITEM_DEFAULT, 0},
108    {"pkikeypair",            store_dir,       ITEM(res_client.pki_keypair_file), 0, 0, 0},
109    {"pkisigner",             store_alist_str, ITEM(res_client.pki_signing_key_files), 0, 0, 0},
110    {"pkimasterkey",          store_alist_str, ITEM(res_client.pki_master_key_files), 0, 0, 0},
111 #endif
112    {"tlsauthenticate",       store_bool,    ITEM(res_client.tls_authenticate),  0, 0, 0},
113    {"tlsenable",             store_bool,    ITEM(res_client.tls_enable),  0, 0, 0},
114    {"tlsrequire",            store_bool,    ITEM(res_client.tls_require), 0, 0, 0},
115    {"tlscacertificatefile",  store_dir,       ITEM(res_client.tls_ca_certfile), 0, 0, 0},
116    {"tlscacertificatedir",   store_dir,       ITEM(res_client.tls_ca_certdir), 0, 0, 0},
117    {"tlscertificate",        store_dir,       ITEM(res_client.tls_certfile), 0, 0, 0},
118    {"tlskey",                store_dir,       ITEM(res_client.tls_keyfile), 0, 0, 0},
119    {"verid",                 store_str,       ITEM(res_client.verid), 0, 0, 0},
120    {NULL, NULL, {0}, 0, 0, 0}
121 };
122
123 /* Directors that can use our services */
124 static RES_ITEM dir_items[] = {
125    {"name",        store_name,     ITEM(res_dir.hdr.name),  0, ITEM_REQUIRED, 0},
126    {"description", store_str,      ITEM(res_dir.hdr.desc),  0, 0, 0},
127    {"password",    store_password, ITEM(res_dir.password),  0, ITEM_REQUIRED, 0},
128    {"address",     store_str,      ITEM(res_dir.address),   0, 0, 0},
129    {"monitor",     store_bool,   ITEM(res_dir.monitor),   0, ITEM_DEFAULT, 0},
130    {"tlsauthenticate",      store_bool,    ITEM(res_dir.tls_authenticate), 0, 0, 0},
131    {"tlsenable",            store_bool,    ITEM(res_dir.tls_enable), 0, 0, 0},
132    {"tlsrequire",           store_bool,    ITEM(res_dir.tls_require), 0, 0, 0},
133    {"tlsverifypeer",        store_bool,    ITEM(res_dir.tls_verify_peer), 0, ITEM_DEFAULT, 1},
134    {"tlscacertificatefile", store_dir,       ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
135    {"tlscacertificatedir",  store_dir,       ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
136    {"tlscertificate",       store_dir,       ITEM(res_dir.tls_certfile), 0, 0, 0},
137    {"tlskey",               store_dir,       ITEM(res_dir.tls_keyfile), 0, 0, 0},
138    {"tlsdhfile",            store_dir,       ITEM(res_dir.tls_dhfile), 0, 0, 0},
139    {"tlsallowedcn",         store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
140    {NULL, NULL, {0}, 0, 0, 0}
141 };
142
143 /* Message resource */
144 extern RES_ITEM msgs_items[];
145
146 /*
147  * This is the master resource definition.
148  * It must have one item for each of the resources.
149  */
150 RES_TABLE resources[] = {
151    {"director",      dir_items,   R_DIRECTOR},
152    {"filedaemon",    cli_items,   R_CLIENT},
153    {"client",        cli_items,   R_CLIENT},     /* alias for filedaemon */
154    {"messages",      msgs_items,  R_MSGS},
155    {NULL,            NULL,        0}
156 };
157
158
159 /* Dump contents of resource */
160 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
161 {
162    URES *res = (URES *)reshdr;
163    int recurse = 1;
164
165    if (res == NULL) {
166       sendit(sock, "No record for %d %s\n", type, res_to_str(type));
167       return;
168    }
169    if (type < 0) {                    /* no recursion */
170       type = - type;
171       recurse = 0;
172    }
173    switch (type) {
174    case R_DIRECTOR:
175       sendit(sock, "Director: name=%s password=%s\n", reshdr->name,
176               res->res_dir.password);
177       break;
178    case R_CLIENT:
179       sendit(sock, "Client: name=%s FDport=%d\n", reshdr->name,
180               get_first_port_host_order(res->res_client.FDaddrs));
181       break;
182    case R_MSGS:
183       sendit(sock, "Messages: name=%s\n", res->res_msgs.hdr.name);
184       if (res->res_msgs.mail_cmd)
185          sendit(sock, "      mailcmd=%s\n", res->res_msgs.mail_cmd);
186       if (res->res_msgs.operator_cmd)
187          sendit(sock, "      opcmd=%s\n", res->res_msgs.operator_cmd);
188       break;
189    default:
190       sendit(sock, "Unknown resource type %d\n", type);
191    }
192    if (recurse && res->res_dir.hdr.next) {
193       dump_resource(type, res->res_dir.hdr.next, sendit, sock);
194    }
195 }
196
197 /*
198  * Free memory of resource.
199  * NB, we don't need to worry about freeing any references
200  * to other resources as they will be freed when that
201  * resource chain is traversed.  Mainly we worry about freeing
202  * allocated strings (names).
203  */
204 void free_resource(RES *sres, int type)
205 {
206    RES *nres;
207    URES *res = (URES *)sres;
208
209    if (res == NULL) {
210       return;
211    }
212
213    /* common stuff -- free the resource name */
214    nres = (RES *)res->res_dir.hdr.next;
215    if (res->res_dir.hdr.name) {
216       free(res->res_dir.hdr.name);
217    }
218    if (res->res_dir.hdr.desc) {
219       free(res->res_dir.hdr.desc);
220    }
221    switch (type) {
222    case R_DIRECTOR:
223       if (res->res_dir.password) {
224          free(res->res_dir.password);
225       }
226       if (res->res_dir.address) {
227          free(res->res_dir.address);
228       }
229       if (res->res_dir.tls_ctx) { 
230          free_tls_context(res->res_dir.tls_ctx);
231       }
232       if (res->res_dir.tls_ca_certfile) {
233          free(res->res_dir.tls_ca_certfile);
234       }
235       if (res->res_dir.tls_ca_certdir) {
236          free(res->res_dir.tls_ca_certdir);
237       }
238       if (res->res_dir.tls_certfile) {
239          free(res->res_dir.tls_certfile);
240       }
241       if (res->res_dir.tls_keyfile) {
242          free(res->res_dir.tls_keyfile);
243       }
244       if (res->res_dir.tls_dhfile) {
245          free(res->res_dir.tls_dhfile);
246       }
247       if (res->res_dir.tls_allowed_cns) {
248          delete res->res_dir.tls_allowed_cns;
249       }
250       break;
251    case R_CLIENT:
252       if (res->res_client.working_directory) {
253          free(res->res_client.working_directory);
254       }
255       if (res->res_client.pid_directory) {
256          free(res->res_client.pid_directory);
257       }
258       if (res->res_client.subsys_directory) {
259          free(res->res_client.subsys_directory);
260       }
261       if (res->res_client.scripts_directory) {
262          free(res->res_client.scripts_directory);
263       }
264       if (res->res_client.plugin_directory) {
265          free(res->res_client.plugin_directory);
266       }
267       if (res->res_client.FDaddrs) {
268          free_addresses(res->res_client.FDaddrs);
269       }
270
271       if (res->res_client.pki_keypair_file) { 
272          free(res->res_client.pki_keypair_file);
273       }
274       if (res->res_client.pki_keypair) {
275          crypto_keypair_free(res->res_client.pki_keypair);
276       }
277
278       if (res->res_client.pki_signing_key_files) {
279          delete res->res_client.pki_signing_key_files;
280       }
281       if (res->res_client.pki_signers) {
282          X509_KEYPAIR *keypair;
283          foreach_alist(keypair, res->res_client.pki_signers) {
284             crypto_keypair_free(keypair);
285          }
286          delete res->res_client.pki_signers;
287       }
288
289       if (res->res_client.pki_master_key_files) {
290          delete res->res_client.pki_master_key_files;
291       }
292
293       if (res->res_client.pki_recipients) {
294          X509_KEYPAIR *keypair;
295          foreach_alist(keypair, res->res_client.pki_recipients) {
296             crypto_keypair_free(keypair);
297          }
298          delete res->res_client.pki_recipients;
299       }
300
301       if (res->res_client.tls_ctx) { 
302          free_tls_context(res->res_client.tls_ctx);
303       }
304       if (res->res_client.tls_ca_certfile) {
305          free(res->res_client.tls_ca_certfile);
306       }
307       if (res->res_client.tls_ca_certdir) {
308          free(res->res_client.tls_ca_certdir);
309       }
310       if (res->res_client.tls_certfile) {
311          free(res->res_client.tls_certfile);
312       }
313       if (res->res_client.tls_keyfile) {
314          free(res->res_client.tls_keyfile);
315       }
316       if (res->res_client.verid) {
317          free(res->res_client.verid);
318       }
319       break;
320    case R_MSGS:
321       if (res->res_msgs.mail_cmd)
322          free(res->res_msgs.mail_cmd);
323       if (res->res_msgs.operator_cmd)
324          free(res->res_msgs.operator_cmd);
325       free_msgs_res((MSGS *)res);  /* free message resource */
326       res = NULL;
327       break;
328    default:
329       printf(_("Unknown resource type %d\n"), type);
330    }
331    /* Common stuff again -- free the resource, recurse to next one */
332    if (res) {
333       free(res);
334    }
335    if (nres) {
336       free_resource(nres, type);
337    }
338 }
339
340 /* Save the new resource by chaining it into the head list for
341  * the resource. If this is pass 2, we update any resource
342  * pointers (currently only in the Job resource).
343  */
344 void save_resource(int type, RES_ITEM *items, int pass)
345 {
346    URES *res;
347    int rindex = type - r_first;
348    int i, size;
349    int error = 0;
350
351    /*
352     * Ensure that all required items are present
353     */
354    for (i=0; items[i].name; i++) {
355       if (items[i].flags & ITEM_REQUIRED) {
356             if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
357                Emsg2(M_ABORT, 0, _("%s item is required in %s resource, but not found.\n"),
358                  items[i].name, resources[rindex]);
359              }
360       }
361    }
362
363    /* During pass 2, we looked up pointers to all the resources
364     * referrenced in the current resource, , now we
365     * must copy their address from the static record to the allocated
366     * record.
367     */
368    if (pass == 2) {
369       switch (type) {
370          /* Resources not containing a resource */
371          case R_MSGS:
372             break;
373
374          /* Resources containing another resource */
375          case R_DIRECTOR:
376             if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
377                Emsg1(M_ABORT, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
378             }
379             res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
380             break;
381          case R_CLIENT:
382             if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_dir.hdr.name)) == NULL) {
383                Emsg1(M_ABORT, 0, _("Cannot find Client resource %s\n"), res_all.res_dir.hdr.name);
384             }
385             res->res_client.pki_signing_key_files = res_all.res_client.pki_signing_key_files;
386             res->res_client.pki_master_key_files = res_all.res_client.pki_master_key_files;
387
388             res->res_client.pki_signers = res_all.res_client.pki_signers;
389             res->res_client.pki_recipients = res_all.res_client.pki_recipients;
390
391             res->res_client.messages = res_all.res_client.messages;
392             break;
393          default:
394             Emsg1(M_ERROR, 0, _("Unknown resource type %d\n"), type);
395             error = 1;
396             break;
397       }
398       /* Note, the resoure name was already saved during pass 1,
399        * so here, we can just release it.
400        */
401       if (res_all.res_dir.hdr.name) {
402          free(res_all.res_dir.hdr.name);
403          res_all.res_dir.hdr.name = NULL;
404       }
405       if (res_all.res_dir.hdr.desc) {
406          free(res_all.res_dir.hdr.desc);
407          res_all.res_dir.hdr.desc = NULL;
408       }
409       return;
410    }
411
412    /* The following code is only executed on pass 1 */
413    switch (type) {
414       case R_DIRECTOR:
415          size = sizeof(DIRRES);
416          break;
417       case R_CLIENT:
418          size = sizeof(CLIENT);
419          break;
420       case R_MSGS:
421          size = sizeof(MSGS);
422          break;
423       default:
424          printf(_("Unknown resource type %d\n"), type);
425          error = 1;
426          size = 1;
427          break;
428    }
429    /* Common */
430    if (!error) {
431       res = (URES *)malloc(size);
432       memcpy(res, &res_all, size);
433       if (!res_head[rindex]) {
434          res_head[rindex] = (RES *)res; /* store first entry */
435       } else {
436          RES *next, *last;
437          /* Add new res to end of chain */
438          for (last=next=res_head[rindex]; next; next=next->next) {
439             last = next;
440             if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
441                Emsg2(M_ERROR_TERM, 0,
442                   _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
443                   resources[rindex].name, res->res_dir.hdr.name);
444             }
445          }
446          last->next = (RES *)res;
447          Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type),
448                res->res_dir.hdr.name);
449       }
450    }
451 }
452
453 bool parse_fd_config(CONFIG *config, const char *configfile, int exit_code)
454 {
455    config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
456       r_first, r_last, resources, res_head);
457    return config->parse_config();
458 }