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