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