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