]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/filed_conf.c
Convert to pure GPL v2 license.
[bacula/bacula] / bacula / src / filed / filed_conf.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2007 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 John Walker.
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 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    {"sdconnecttimeout", store_time,ITEM(res_client.SDConnectTimeout), 0, ITEM_DEFAULT, 60 * 30},
102    {"heartbeatinterval", store_time, ITEM(res_client.heartbeat_interval), 0, ITEM_DEFAULT, 0},
103    {"maximumnetworkbuffersize", store_pint, ITEM(res_client.max_network_buffer_size), 0, 0, 0},
104 #ifdef DATA_ENCRYPTION
105    {"pkisignatures",         store_bool,    ITEM(res_client.pki_sign), 0, ITEM_DEFAULT, 0},
106    {"pkiencryption",         store_bool,    ITEM(res_client.pki_encrypt), 0, ITEM_DEFAULT, 0},
107    {"pkikeypair",            store_dir,       ITEM(res_client.pki_keypair_file), 0, 0, 0},
108    {"pkisigner",             store_alist_str, ITEM(res_client.pki_signing_key_files), 0, 0, 0},
109    {"pkimasterkey",          store_alist_str, ITEM(res_client.pki_master_key_files), 0, 0, 0},
110 #endif
111    {"tlsenable",             store_bool,    ITEM(res_client.tls_enable),  0, 0, 0},
112    {"tlsrequire",            store_bool,    ITEM(res_client.tls_require), 0, 0, 0},
113    {"tlscacertificatefile",  store_dir,       ITEM(res_client.tls_ca_certfile), 0, 0, 0},
114    {"tlscacertificatedir",   store_dir,       ITEM(res_client.tls_ca_certdir), 0, 0, 0},
115    {"tlscertificate",        store_dir,       ITEM(res_client.tls_certfile), 0, 0, 0},
116    {"tlskey",                store_dir,       ITEM(res_client.tls_keyfile), 0, 0, 0},
117    {NULL, NULL, {0}, 0, 0, 0}
118 };
119
120 /* Directors that can use our services */
121 static RES_ITEM dir_items[] = {
122    {"name",        store_name,     ITEM(res_dir.hdr.name),  0, ITEM_REQUIRED, 0},
123    {"description", store_str,      ITEM(res_dir.hdr.desc),  0, 0, 0},
124    {"password",    store_password, ITEM(res_dir.password),  0, ITEM_REQUIRED, 0},
125    {"address",     store_str,      ITEM(res_dir.address),   0, 0, 0},
126    {"monitor",     store_bool,   ITEM(res_dir.monitor),   0, ITEM_DEFAULT, 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    {NULL, NULL, {0}, 0, 0, 0}
137 };
138
139 /* Message resource */
140 extern RES_ITEM msgs_items[];
141
142 /*
143  * This is the master resource definition.
144  * It must have one item for each of the resources.
145  */
146 RES_TABLE resources[] = {
147    {"director",      dir_items,   R_DIRECTOR},
148    {"filedaemon",    cli_items,   R_CLIENT},
149    {"client",        cli_items,   R_CLIENT},     /* alias for filedaemon */
150    {"messages",      msgs_items,  R_MSGS},
151    {NULL,            NULL,        0}
152 };
153
154
155 /* Dump contents of resource */
156 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
157 {
158    URES *res = (URES *)reshdr;
159    int recurse = 1;
160
161    if (res == NULL) {
162       sendit(sock, "No record for %d %s\n", type, res_to_str(type));
163       return;
164    }
165    if (type < 0) {                    /* no recursion */
166       type = - type;
167       recurse = 0;
168    }
169    switch (type) {
170    case R_DIRECTOR:
171       sendit(sock, "Director: name=%s password=%s\n", reshdr->name,
172               res->res_dir.password);
173       break;
174    case R_CLIENT:
175       sendit(sock, "Client: name=%s FDport=%d\n", reshdr->name,
176               get_first_port_host_order(res->res_client.FDaddrs));
177       break;
178    case R_MSGS:
179       sendit(sock, "Messages: name=%s\n", res->res_msgs.hdr.name);
180       if (res->res_msgs.mail_cmd)
181          sendit(sock, "      mailcmd=%s\n", res->res_msgs.mail_cmd);
182       if (res->res_msgs.operator_cmd)
183          sendit(sock, "      opcmd=%s\n", res->res_msgs.operator_cmd);
184       break;
185    default:
186       sendit(sock, "Unknown resource type %d\n", type);
187    }
188    if (recurse && res->res_dir.hdr.next) {
189       dump_resource(type, res->res_dir.hdr.next, sendit, sock);
190    }
191 }
192
193 /*
194  * Free memory of resource.
195  * NB, we don't need to worry about freeing any references
196  * to other resources as they will be freed when that
197  * resource chain is traversed.  Mainly we worry about freeing
198  * allocated strings (names).
199  */
200 void free_resource(RES *sres, int type)
201 {
202    RES *nres;
203    URES *res = (URES *)sres;
204
205    if (res == NULL) {
206       return;
207    }
208
209    /* common stuff -- free the resource name */
210    nres = (RES *)res->res_dir.hdr.next;
211    if (res->res_dir.hdr.name) {
212       free(res->res_dir.hdr.name);
213    }
214    if (res->res_dir.hdr.desc) {
215       free(res->res_dir.hdr.desc);
216    }
217    switch (type) {
218    case R_DIRECTOR:
219       if (res->res_dir.password) {
220          free(res->res_dir.password);
221       }
222       if (res->res_dir.address) {
223          free(res->res_dir.address);
224       }
225       if (res->res_dir.tls_ctx) { 
226          free_tls_context(res->res_dir.tls_ctx);
227       }
228       if (res->res_dir.tls_ca_certfile) {
229          free(res->res_dir.tls_ca_certfile);
230       }
231       if (res->res_dir.tls_ca_certdir) {
232          free(res->res_dir.tls_ca_certdir);
233       }
234       if (res->res_dir.tls_certfile) {
235          free(res->res_dir.tls_certfile);
236       }
237       if (res->res_dir.tls_keyfile) {
238          free(res->res_dir.tls_keyfile);
239       }
240       if (res->res_dir.tls_dhfile) {
241          free(res->res_dir.tls_dhfile);
242       }
243       if (res->res_dir.tls_allowed_cns) {
244          delete res->res_dir.tls_allowed_cns;
245       }
246       break;
247    case R_CLIENT:
248       if (res->res_client.working_directory) {
249          free(res->res_client.working_directory);
250       }
251       if (res->res_client.pid_directory) {
252          free(res->res_client.pid_directory);
253       }
254       if (res->res_client.subsys_directory) {
255          free(res->res_client.subsys_directory);
256       }
257       if (res->res_client.scripts_directory) {
258          free(res->res_client.scripts_directory);
259       }
260       if (res->res_client.FDaddrs) {
261          free_addresses(res->res_client.FDaddrs);
262       }
263
264       if (res->res_client.pki_keypair_file) { 
265          free(res->res_client.pki_keypair_file);
266       }
267       if (res->res_client.pki_keypair) {
268          crypto_keypair_free(res->res_client.pki_keypair);
269       }
270
271       if (res->res_client.pki_signing_key_files) {
272          delete res->res_client.pki_signing_key_files;
273       }
274       if (res->res_client.pki_signers) {
275          X509_KEYPAIR *keypair;
276          foreach_alist(keypair, res->res_client.pki_signers) {
277             crypto_keypair_free(keypair);
278          }
279          delete res->res_client.pki_signers;
280       }
281
282       if (res->res_client.pki_master_key_files) {
283          delete res->res_client.pki_master_key_files;
284       }
285
286       if (res->res_client.pki_recipients) {
287          X509_KEYPAIR *keypair;
288          foreach_alist(keypair, res->res_client.pki_recipients) {
289             crypto_keypair_free(keypair);
290          }
291          delete res->res_client.pki_recipients;
292       }
293
294       if (res->res_client.tls_ctx) { 
295          free_tls_context(res->res_client.tls_ctx);
296       }
297       if (res->res_client.tls_ca_certfile) {
298          free(res->res_client.tls_ca_certfile);
299       }
300       if (res->res_client.tls_ca_certdir) {
301          free(res->res_client.tls_ca_certdir);
302       }
303       if (res->res_client.tls_certfile) {
304          free(res->res_client.tls_certfile);
305       }
306       if (res->res_client.tls_keyfile) {
307          free(res->res_client.tls_keyfile);
308       }
309       break;
310    case R_MSGS:
311       if (res->res_msgs.mail_cmd)
312          free(res->res_msgs.mail_cmd);
313       if (res->res_msgs.operator_cmd)
314          free(res->res_msgs.operator_cmd);
315       free_msgs_res((MSGS *)res);  /* free message resource */
316       res = NULL;
317       break;
318    default:
319       printf(_("Unknown resource type %d\n"), type);
320    }
321    /* Common stuff again -- free the resource, recurse to next one */
322    if (res) {
323       free(res);
324    }
325    if (nres) {
326       free_resource(nres, type);
327    }
328 }
329
330 /* Save the new resource by chaining it into the head list for
331  * the resource. If this is pass 2, we update any resource
332  * pointers (currently only in the Job resource).
333  */
334 void save_resource(int type, RES_ITEM *items, int pass)
335 {
336    URES *res;
337    int rindex = type - r_first;
338    int i, size;
339    int error = 0;
340
341    /*
342     * Ensure that all required items are present
343     */
344    for (i=0; items[i].name; i++) {
345       if (items[i].flags & ITEM_REQUIRED) {
346             if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
347                Emsg2(M_ABORT, 0, _("%s item is required in %s resource, but not found.\n"),
348                  items[i].name, resources[rindex]);
349              }
350       }
351    }
352
353    /* During pass 2, we looked up pointers to all the resources
354     * referrenced in the current resource, , now we
355     * must copy their address from the static record to the allocated
356     * record.
357     */
358    if (pass == 2) {
359       switch (type) {
360          /* Resources not containing a resource */
361          case R_MSGS:
362             break;
363
364          /* Resources containing another resource */
365          case R_DIRECTOR:
366             if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
367                Emsg1(M_ABORT, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
368             }
369             res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
370             break;
371          case R_CLIENT:
372             if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_dir.hdr.name)) == NULL) {
373                Emsg1(M_ABORT, 0, _("Cannot find Client resource %s\n"), res_all.res_dir.hdr.name);
374             }
375             res->res_client.pki_signing_key_files = res_all.res_client.pki_signing_key_files;
376             res->res_client.pki_master_key_files = res_all.res_client.pki_master_key_files;
377
378             res->res_client.pki_signers = res_all.res_client.pki_signers;
379             res->res_client.pki_recipients = res_all.res_client.pki_recipients;
380
381             res->res_client.messages = res_all.res_client.messages;
382             break;
383          default:
384             Emsg1(M_ERROR, 0, _("Unknown resource type %d\n"), type);
385             error = 1;
386             break;
387       }
388       /* Note, the resoure name was already saved during pass 1,
389        * so here, we can just release it.
390        */
391       if (res_all.res_dir.hdr.name) {
392          free(res_all.res_dir.hdr.name);
393          res_all.res_dir.hdr.name = NULL;
394       }
395       if (res_all.res_dir.hdr.desc) {
396          free(res_all.res_dir.hdr.desc);
397          res_all.res_dir.hdr.desc = NULL;
398       }
399       return;
400    }
401
402    /* The following code is only executed on pass 1 */
403    switch (type) {
404       case R_DIRECTOR:
405          size = sizeof(DIRRES);
406          break;
407       case R_CLIENT:
408          size = sizeof(CLIENT);
409          break;
410       case R_MSGS:
411          size = sizeof(MSGS);
412          break;
413       default:
414          printf(_("Unknown resource type %d\n"), type);
415          error = 1;
416          size = 1;
417          break;
418    }
419    /* Common */
420    if (!error) {
421       res = (URES *)malloc(size);
422       memcpy(res, &res_all, size);
423       if (!res_head[rindex]) {
424          res_head[rindex] = (RES *)res; /* store first entry */
425       } else {
426          RES *next, *last;
427          /* Add new res to end of chain */
428          for (last=next=res_head[rindex]; next; next=next->next) {
429             last = next;
430             if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
431                Emsg2(M_ERROR_TERM, 0,
432                   _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
433                   resources[rindex].name, res->res_dir.hdr.name);
434             }
435          }
436          last->next = (RES *)res;
437          Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type),
438                res->res_dir.hdr.name);
439       }
440    }
441 }