From 13b70b45ab81f042379739d6390f8150f0fea470 Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Thu, 6 Jan 2005 16:37:20 +0000 Subject: [PATCH] - Apply all of Preben's patches, but revert to old backup.c and old restore.c in filed. Also turn off code in new acl.c because of errors. The new code, when fully implemented moves platform specific code into acl.c. One of the patches also implements WildFile and WildDir -- thanks. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@1787 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/LICENSE | 2 +- bacula/src/c | 2 +- bacula/src/dird/dird_conf.c | 16 ++ bacula/src/dird/dird_conf.h | 4 + bacula/src/dird/fd_cmds.c | 12 + bacula/src/dird/inc_conf.c | 48 +++- bacula/src/filed/Makefile.in | 4 +- bacula/src/filed/acl.c | 427 +++++++++++++++++++++++++++++++++++ bacula/src/filed/acl.h | 70 ++++++ bacula/src/filed/filed.c | 10 +- bacula/src/filed/filed.h | 1 + bacula/src/filed/job.c | 92 +++++++- bacula/src/filed/protos.h | 4 + bacula/src/findlib/find.c | 46 ++++ bacula/src/findlib/find.h | 4 + bacula/src/findlib/fstype.c | 18 +- bacula/src/version.h | 4 +- 17 files changed, 728 insertions(+), 36 deletions(-) create mode 100644 bacula/src/filed/acl.c create mode 100644 bacula/src/filed/acl.h diff --git a/bacula/LICENSE b/bacula/LICENSE index 18162b1900..14fedbc9e8 100644 --- a/bacula/LICENSE +++ b/bacula/LICENSE @@ -49,7 +49,7 @@ the copyright license set forth in this Agreement. Code falling under the above conditions will be marked as follows: - Copyright (C) 2000-2004 Kern Sibbald and John Walker + Copyright (C) 2000-2005 Kern Sibbald This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/bacula/src/c b/bacula/src/c index c910dbd8ec..5c8d1e7c4b 100644 --- a/bacula/src/c +++ b/bacula/src/c @@ -1,5 +1,5 @@ /* - Copyright (C) 2000-2004 Kern Sibbald and John Walker + Copyright (C) 2000-2005 Kern Sibbald and John Walker This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/bacula/src/dird/dird_conf.c b/bacula/src/dird/dird_conf.c index 255ba70cd5..336f413d74 100644 --- a/bacula/src/dird/dird_conf.c +++ b/bacula/src/dird/dird_conf.c @@ -581,9 +581,21 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fm for (k=0; kregex.size(); k++) { sendit(sock, " R %s\n", fo->regex.get(k)); } + for (k=0; kregexdir.size(); k++) { + sendit(sock, " RD %s\n", fo->regexdir.get(k)); + } + for (k=0; kregexfile.size(); k++) { + sendit(sock, " RF %s\n", fo->regexfile.get(k)); + } for (k=0; kwild.size(); k++) { sendit(sock, " W %s\n", fo->wild.get(k)); } + for (k=0; kwilddir.size(); k++) { + sendit(sock, " WD %s\n", fo->wilddir.get(k)); + } + for (k=0; kwildfile.size(); k++) { + sendit(sock, " WF %s\n", fo->wildfile.get(k)); + } for (k=0; kbase.size(); k++) { sendit(sock, " B %s\n", fo->base.get(k)); } @@ -749,7 +761,11 @@ static void free_incexe(INCEXE *incexe) for (int i=0; inum_opts; i++) { FOPTS *fopt = incexe->opts_list[i]; fopt->regex.destroy(); + fopt->regexdir.destroy(); + fopt->regexfile.destroy(); fopt->wild.destroy(); + fopt->wilddir.destroy(); + fopt->wildfile.destroy(); fopt->base.destroy(); fopt->fstype.destroy(); if (fopt->reader) { diff --git a/bacula/src/dird/dird_conf.h b/bacula/src/dird/dird_conf.h index 30c10732ff..779fe50335 100644 --- a/bacula/src/dird/dird_conf.h +++ b/bacula/src/dird/dird_conf.h @@ -250,7 +250,11 @@ struct JOB { struct FOPTS { char opts[MAX_FOPTS]; /* options string */ alist regex; /* regex string(s) */ + alist regexdir; /* regex string(s) for directories */ + alist regexfile; /* regex string(s) for files */ alist wild; /* wild card strings */ + alist wilddir; /* wild card strings for directories */ + alist wildfile; /* wild card strings for files */ alist base; /* list of base names */ alist fstype; /* file system type limitation */ char *reader; /* reader program */ diff --git a/bacula/src/dird/fd_cmds.c b/bacula/src/dird/fd_cmds.c index 20678f4f10..1c9e389502 100644 --- a/bacula/src/dird/fd_cmds.c +++ b/bacula/src/dird/fd_cmds.c @@ -400,9 +400,21 @@ static int send_fileset(JCR *jcr) for (k=0; kregex.size(); k++) { bnet_fsend(fd, "R %s\n", fo->regex.get(k)); } + for (k=0; kregexdir.size(); k++) { + bnet_fsend(fd, "RD %s\n", fo->regexdir.get(k)); + } + for (k=0; kregexfile.size(); k++) { + bnet_fsend(fd, "RF %s\n", fo->regexfile.get(k)); + } for (k=0; kwild.size(); k++) { bnet_fsend(fd, "W %s\n", fo->wild.get(k)); } + for (k=0; kwilddir.size(); k++) { + bnet_fsend(fd, "WD %s\n", fo->wilddir.get(k)); + } + for (k=0; kwildfile.size(); k++) { + bnet_fsend(fd, "WF %s\n", fo->wildfile.get(k)); + } for (k=0; kbase.size(); k++) { bnet_fsend(fd, "B %s\n", fo->base.get(k)); } diff --git a/bacula/src/dird/inc_conf.c b/bacula/src/dird/inc_conf.c index e723ce4c7e..d1ec4bb8ca 100644 --- a/bacula/src/dird/inc_conf.c +++ b/bacula/src/dird/inc_conf.c @@ -87,8 +87,12 @@ static RES_ITEM options_items[] = { {"mtimeonly", store_opts, NULL, 0, 0, 0}, {"keepatime", store_opts, NULL, 0, 0, 0}, {"regex", store_regex, NULL, 0, 0, 0}, + {"regexdir", store_regex, NULL, 1, 0, 0}, + {"regexfile", store_regex, NULL, 2, 0, 0}, {"base", store_base, NULL, 0, 0, 0}, {"wild", store_wild, NULL, 0, 0, 0}, + {"wilddir", store_wild, NULL, 1, 0, 0}, + {"wildfile", store_wild, NULL, 2, 0, 0}, {"exclude", store_opts, NULL, 0, 0, 0}, {"aclsupport", store_opts, NULL, 0, 0, 0}, {"reader", store_reader, NULL, 0, 0, 0}, @@ -473,6 +477,8 @@ static void store_regex(LEX *lc, RES_ITEM *item, int index, int pass) int token, rc; regex_t preg; char prbuf[500]; + char *type; + int newsize; token = lex_get_token(lc, T_SKIP_EOL); if (pass == 1) { @@ -490,9 +496,21 @@ static void store_regex(LEX *lc, RES_ITEM *item, int index, int pass) break; } regfree(&preg); - res_incexe.current_opts->regex.append(bstrdup(lc->str)); - Dmsg3(900, "set regex %p size=%d %s\n", - res_incexe.current_opts, res_incexe.current_opts->regex.size(),lc->str); + if (item->code == 1) { + type = "regexdir"; + res_incexe.current_opts->regexdir.append(bstrdup(lc->str)); + newsize = res_incexe.current_opts->regexdir.size(); + } else if (item->code == 2) { + type = "regexfile"; + res_incexe.current_opts->regexfile.append(bstrdup(lc->str)); + newsize = res_incexe.current_opts->regexfile.size(); + } else { + type = "regex"; + res_incexe.current_opts->regex.append(bstrdup(lc->str)); + newsize = res_incexe.current_opts->regex.size(); + } + Dmsg4(900, "set %s %p size=%d %s\n", + type, res_incexe.current_opts, newsize, lc->str); break; default: scan_err1(lc, _("Expected a regex string, got: %s\n"), lc->str); @@ -552,6 +570,8 @@ static void store_writer(LEX *lc, RES_ITEM *item, int index, int pass) static void store_wild(LEX *lc, RES_ITEM *item, int index, int pass) { int token; + char *type; + int newsize; token = lex_get_token(lc, T_SKIP_EOL); if (pass == 1) { @@ -562,9 +582,21 @@ static void store_wild(LEX *lc, RES_ITEM *item, int index, int pass) case T_IDENTIFIER: case T_UNQUOTED_STRING: case T_QUOTED_STRING: - res_incexe.current_opts->wild.append(bstrdup(lc->str)); - Dmsg3(900, "set wild %p size=%d %s\n", - res_incexe.current_opts, res_incexe.current_opts->wild.size(),lc->str); + if (item->code == 1) { + type = "wilddir"; + res_incexe.current_opts->wilddir.append(bstrdup(lc->str)); + newsize = res_incexe.current_opts->wilddir.size(); + } else if (item->code == 2) { + type = "wildfile"; + res_incexe.current_opts->wildfile.append(bstrdup(lc->str)); + newsize = res_incexe.current_opts->wildfile.size(); + } else { + type = "wild"; + res_incexe.current_opts->wild.append(bstrdup(lc->str)); + newsize = res_incexe.current_opts->wild.size(); + } + Dmsg4(9, "set %s %p size=%d %s\n", + type, res_incexe.current_opts, newsize, lc->str); break; default: scan_err1(lc, _("Expected a wild-card string, got: %s\n"), lc->str); @@ -715,7 +747,11 @@ static void setup_current_opts(void) FOPTS *fo = (FOPTS *)malloc(sizeof(FOPTS)); memset(fo, 0, sizeof(FOPTS)); fo->regex.init(1, true); + fo->regexdir.init(1, true); + fo->regexfile.init(1, true); fo->wild.init(1, true); + fo->wilddir.init(1, true); + fo->wildfile.init(1, true); fo->base.init(1, true); fo->fstype.init(1, true); res_incexe.current_opts = fo; diff --git a/bacula/src/filed/Makefile.in b/bacula/src/filed/Makefile.in index 551541b3da..e5c05e2e3e 100755 --- a/bacula/src/filed/Makefile.in +++ b/bacula/src/filed/Makefile.in @@ -23,10 +23,10 @@ first_rule: all dummy: # -SVRSRCS = filed.c authenticate.c backup.c chksum.c estimate.c \ +SVRSRCS = filed.c authenticate.c acl.c backup.c chksum.c estimate.c \ filed_conf.c heartbeat.c job.c \ restore.c status.c verify.c verify_vol.c -SVROBJS = filed.o authenticate.o backup.o chksum.o estimate.o \ +SVROBJS = filed.o authenticate.o acl.o backup.o chksum.o estimate.o \ filed_conf.o heartbeat.o job.o \ restore.o status.o verify.o verify_vol.o diff --git a/bacula/src/filed/acl.c b/bacula/src/filed/acl.c new file mode 100644 index 0000000000..d749c31f0f --- /dev/null +++ b/bacula/src/filed/acl.c @@ -0,0 +1,427 @@ +/* + * Functions to handle ACL for bacula. + * + * We handle two different typers of ACLs: access and default ACLS. + * Default ACLs only apply to directories. + * + * On some systems (eg. linux and FreeBSD) we must obtain the two ACLs + * independently, while others (eg. Solaris) provide both in one call. + * + * As for the streams to use, we have two choices: + * + * 1. Build a generic framework. + * With two different types of ACLs, supported differently, we + * probably end up encoding and decoding everything ourselves. + * + * 2. Take the easy way out. + * Just handle each platform individually, assuming that backups + * and restores are done on the same (kind of) client. + * + * Currently we take the easy way out. We use two kinds of streams, one + * for access ACLs and one for default ACLs. If an OS mixes the two, we + * send the mix in the access ACL stream. + * + * Looking at more man pages, supporting a framework seems really hard + * if we want to support HP-UX. Deity knows what AIX is up to. + * + * Written by Preben 'Peppe' Guldberg, December MMIV + * + * Version $Id$ + */ + +#ifdef xxxxxxx + +Remove fprintf's and actuallyfree and fix POOLMEM coding + +Pass errmsg buffer and a length or a POOLMEM buffer +into subroutine rather than malloc in +subroutine and free() in higher level routine, which causes +memory leaks if you forget to free. + +#ifndef TEST_PROGRAM +#include "bacula.h" +#include "filed.h" +#else +/* + * Compile and set up with eg. with eg. + * + * $ cc -DTEST_PROGRAM -DHAVE_SUN_OS -lsec -o acl acl.c + * $ ln -s acl aclcp + * + * You can then list ACLs with acl and copy them with aclcp. + * + * For a list of compiler flags, see the list preceding the big #if below. + */ +#include +#include +#include +#include +#include "acl.h" +#define POOLMEM char +#define bstrdup strdup +#define actuallyfree(x) free(x) +int aclls(char *fname); +int aclcp(char *src, char *dst); +#endif + +/* + * List of supported OSs. + * Not sure if all the HAVE_XYZ_OS are correct for autoconf. + * The ones that says man page, are coded according to man pages only. + */ +#if !defined(HAVE_ACL) /* ACL support is required, of course */ \ + || !( defined(HAVE_AIX_OS) /* man page -- may need flags */ \ + || defined(HAVE_FREEBSD_OS) /* tested -- compile wihtout flags */ \ + || defined(HAVE_IRIX_OS) /* man page -- compile without flags */ \ + || defined(HAVE_OSF1_OS) /* man page -- may need -lpacl */ \ + || defined(HAVE_LINUX_OS) /* tested -- compile with -lacl */ \ + || defined(HAVE_HPUX_OS) /* man page -- may need flags */ \ + || defined(HAVE_SUN_OS) /* tested -- compile with -lsec */ \ + ) +POOLMEM *bacl_get(char *fname, int acltype) +{ + return NULL; +} + +int bacl_set(char *fname, int acltype, char *acltext) +{ + return -1; +} +#elif defined(HAVE_AIX_OS) +#include + +POOLMEM *bacl_get(char *fname, int acltype) +{ + char *tmp; + POOLMEM *acltext = NULL; + + if ((tmp = acl_get(fname)) != NULL) { + acltext = bstrdup(tmp); + actuallyfree(tmp); + } + return acltext; +} + +int bacl_set(char *fname, int acltype, char *acltext) +{ + if (acl_put(fname, acltext, 0) != 0) { + return -1; + } + return 0; +} + +#elif defined(HAVE_FREEBSD_OS) \ + || defined(HAVE_IRIX_OS) \ + || defined(HAVE_OSF1_OS) \ + || defined(HAVE_LINUX_OS) +#include +#include + +/* On IRIX we can get shortened ACLs */ +#if defined(HAVE_IRIX_OS) && defined(BACL_WANT_SHORT_ACLS) +#define acl_to_text(acl,len) acl_to_short_text((acl), (len)) +#endif + +/* In Linux we can get numeric and/or shorted ACLs */ +#if defined(HAVE_LINUX_OS) +#if defined(BACL_WANT_SHORT_ACLS) && defined(BACL_WANT_NUMERIC_IDS) +#define BACL_ALTERNATE_TEXT (TEXT_ABBREVIATE|TEXT_NUMERIC_IDS) +#elif defined(BACL_WANT_SHORT_ACLS) +#define BACL_ALTERNATE_TEXT TEXT_ABBREVIATE +#elif defined(BACL_WANT_NUMERIC_IDS) +#define BACL_ALTERNATE_TEXT TEXT_NUMERIC_IDS +#endif +#ifdef BACL_ALTERNATE_TEXT +#include +#define acl_to_text(acl,len) ((len), acl_to_any_text((acl), NULL, ',', BACL_ALTERNATE_TEXT)) +#endif +#endif + +POOLMEM *bacl_get(char *fname, int acltype) +{ + acl_t acl; + int ostype; + char *tmp; + POOLMEM *acltext = NULL; + + ostype = (acltype & BACL_TYPE_DEFAULT) ? ACL_TYPE_DEFAULT : ACL_TYPE_ACCESS; + + acl = acl_get_file(fname, ostype); + if (acl) { + if ((tmp = acl_to_text(acl, NULL)) != NULL) { + acltext = bstrdup(tmp); + acl_free(tmp); + } + acl_free(acl); + } + return acltext; +} + +int bacl_set(char *fname, int acltype, char *acltext) +{ + acl_t acl; + int ostype, stat; + + ostype = (acltype & BACL_TYPE_DEFAULT) ? ACL_TYPE_DEFAULT : ACL_TYPE_ACCESS; + + acl = acl_from_text(acltext); + if (acl == NULL) { + return -1; + } + + /* + * FreeBSD always fails acl_valid() - at least on valid input... + * As it does the right thing, given valid input, just ignore acl_valid(). + */ +#ifndef HAVE_FREEBSD_OS + if (acl_valid(acl) != 0) { + acl_free(acl); + return -1; + } +#endif + + stat = acl_set_file(fname, ostype, acl); + acl_free(acl); + return stat; +} + +#elif defined(HAVE_HPUX_OS) +#include +#include + +POOLMEM *bacl_get(char *fname, int acltype) +{ + int n; + struct acl_entry acls[NACLENTRIES]; + char *tmp; + POOLMEM *acltext = NULL; + + if ((n = getacl(fname, 0, acls)) <= 0) { + return NULL; + } + if ((n = getacl(fname, n, acls)) > 0) { + if ((tmp = acltostr(n, acls, FORM_SHORT)) != NULL) { + acltext = bstrdup(tmp); + actuallyfree(tmp); + } + } + return acltext; +} + +int bacl_set(char *fname, int acltype, char *acltext) +{ + int n, stat; + struct acl_entry acls[NACLENTRIES]; + + n = strtoacl(acltext, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP); + if (n <= 0) { + return -1; + } + if (strtoacl(acltext, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) { + return -1; + } + if (setacl(fname, n, acls) != 0) { + return -1; + } + return 0; +} + +#elif defined(HAVE_SUN_OS) +#include + +POOLMEM *bacl_get(char *fname, int acltype) +{ + int n; + aclent_t *acls; + char *tmp; + POOLMEM *acltext = NULL; + + n = acl(fname, GETACLCNT, 0, NULL); + if (n <= 0) { + return NULL; + } + if ((acls = (aclent_t *)malloc(n * sizeof(aclent_t))) == NULL) { + return NULL; + } + if (acl(fname, GETACL, n, acls) == n) { + if ((tmp = acltotext(acls, n)) != NULL) { + acltext = bstrdup(tmp); + actuallyfree(tmp); + } + } + actuallyfree(acls); + return acltext; +} + +int bacl_set(char *fname, int acltype, char *acltext) +{ + int n, stat; + aclent_t *acls; + + acls = aclfromtext(acltext, &n); + if (!acls) { + return -1; + } + stat = acl(fname, SETACL, n, acls); + actuallyfree(acls); + return stat; +} + +#endif + + +#ifdef TEST_PROGRAM +int main(int argc, char **argv) +{ + char *prgname; + int status = 0; + + if (argc < 1) { + fprintf(stderr, "Cannot determine my own name\n"); + return EXIT_FAILURE; + } + + prgname = strrchr(argv[0], '/'); + if (prgname == NULL || *++prgname == '\0') { + prgname = argv[0]; + } + --argc; + ++argv; + + /* aclcp "copies" ACLs - set ACLs on destination equal to ACLs on source */ + if (strcmp(prgname, "aclcp") == 0) { + int verbose = 0; + if (strcmp(*argv, "-v") == 0) { + ++verbose; + --argc; + ++argv; + } + if (argc != 2) { + fprintf(stderr, "%s: wrong number of arguments\n" + "usage:\t%s [-v] source destination\n" + "\tCopies ACLs from source to destination.\n" + "\tSpecify -v to show ACLs after copy for verification.\n", + prgname, prgname); + return EXIT_FAILURE; + } + if (strcmp(argv[0], argv[1]) == 0) { + fprintf(stderr, "%s: identical source and destination.\n" + "usage:\t%s [-v] source destination\n" + "\tCopies ACLs from source to destination.\n" + "\tSpecify -v to show ACLs after copy for verification.\n", + prgname, prgname); + return EXIT_FAILURE; + } + if (verbose) { + aclls(argv[0]); + } + status = aclcp(argv[0], argv[1]); + if (verbose && status == 0) { + aclls(argv[1]); + } + return status; + } + + /* Default: just list ACLs */ + if (argc < 1) { + fprintf(stderr, "%s: missing arguments\n" + "usage:\t%s file ...\n" + "\tLists ACLs of specified files or directories.\n", + prgname, prgname); + return EXIT_FAILURE; + } + while (argc--) { + if (!aclls(*argv++)) { + status = EXIT_FAILURE; + } + } + + return status; +} + +int aclcp(char *src, char *dst) +{ + struct stat st; + POOLMEM *acltext; + + if (lstat(dst, &st) != 0) { + fprintf(stderr, "aclcp: destination does not exist\n"); + return EXIT_FAILURE; + } + if (S_ISLNK(st.st_mode)) { + fprintf(stderr, "aclcp: cannot set ACL on symlinks\n"); + return EXIT_FAILURE; + } + if (lstat(src, &st) != 0) { + fprintf(stderr, "aclcp: source does not exist\n"); + return EXIT_FAILURE; + } + if (S_ISLNK(st.st_mode)) { + fprintf(stderr, "aclcp: will not read ACL from symlinks\n"); + return EXIT_FAILURE; + } + + acltext = bacl_get(src, BACL_TYPE_ACCESS); + if (!acltext) { + fprintf(stderr, "aclcp: could not read ACLs for %s\n", src); + return EXIT_FAILURE; + } else { + if (bacl_set(dst, BACL_TYPE_ACCESS, acltext) != 0) { + fprintf(stderr, "aclcp: could not set ACLs on %s\n", dst); + actuallyfree(acltext); + return EXIT_FAILURE; + } + actuallyfree(acltext); + } + + if (S_ISDIR(st.st_mode) && (BACL_CAP & BACL_CAP_DEFAULTS_DIR)) { + acltext = bacl_get(src, BACL_TYPE_DEFAULT); + if (acltext) { + if (bacl_set(dst, BACL_TYPE_DEFAULT, acltext) != 0) { + fprintf(stderr, "aclcp: could not set default ACLs on %s\n", dst); + actuallyfree(acltext); + return EXIT_FAILURE; + } + actuallyfree(acltext); + } + } + + return 0; +} + +int aclls(char *fname) +{ + struct stat st; + POOLMEM *acltext; + + if (lstat(fname, &st) != 0) { + fprintf(stderr, "acl: source does not exist\n"); + return EXIT_FAILURE; + } + if (S_ISLNK(st.st_mode)) { + fprintf(stderr, "acl: will not read ACL from symlinks\n"); + return EXIT_FAILURE; + } + + acltext = bacl_get(fname, BACL_TYPE_ACCESS); + if (!acltext) { + fprintf(stderr, "acl: could not read ACLs for %s\n", fname); + return EXIT_FAILURE; + } + printf("#file: %s\n%s\n", fname, acltext); + actuallyfree(acltext); + + if (S_ISDIR(st.st_mode) && (BACL_CAP & BACL_CAP_DEFAULTS_DIR)) { + acltext = bacl_get(fname, BACL_TYPE_DEFAULT); + if (!acltext) { + fprintf(stderr, "acl: could not read default ACLs for %s\n", fname); + return EXIT_FAILURE; + } + printf("#file: %s [default]\n%s\n", fname, acltext); + actuallyfree(acltext); + } + + return 0; +} +#endif +#endif diff --git a/bacula/src/filed/acl.h b/bacula/src/filed/acl.h new file mode 100644 index 0000000000..c9fadcb790 --- /dev/null +++ b/bacula/src/filed/acl.h @@ -0,0 +1,70 @@ +/* + * Properties we use for getting and setting ACLs. + */ + +#ifndef _BACULA_ACL_ +#define _BACULA_ACL_ + +/* If you want shorter ACL strings when possible, uncomment this */ +#define BACL_WANT_SHORT_ACLS + +/* If you want numeric user/group ids when possible, uncomment this */ +/* #define BACL_WANT_NUMERIC_IDS */ + +/* We support the following types of ACLs */ +#define BACL_TYPE_NONE 0x000 +#define BACL_TYPE_ACCESS 0x001 +#define BACL_TYPE_DEFAULT 0x002 + +#define BACL_CAP_NONE 0x000 /* No special capabilities */ +#define BACL_CAP_DEFAULTS 0x001 /* Has default ACLs for directories */ +#define BACL_CAP_DEFAULTS_DIR 0x002 /* Default ACLs must be read separately */ + +/* Set capabilities for various OS */ +#if defined(HAVE_SUN_OS) +#define BACL_CAP BACL_CAP_DEFAULTS +#elif defined(HAVE_FREEBSD_OS) \ + || defined(HAVE_IRIX_OS) \ + || defined(HAVE_OSF1_OS) \ + || defined(HAVE_LINUX_OS) +#define BACL_CAP (BACL_CAP_DEFAULTS|BACL_CAP_DEFAULTS_DIR) +#else +#define BACL_CAP BACL_CAP_NONE +#endif + +#endif +/* + * Properties we use for getting and setting ACLs. + */ + +#ifndef _BACULA_ACL_ +#define _BACULA_ACL_ + +/* If you want shorter ACL strings when possible, uncomment this */ +#define BACL_WANT_SHORT_ACLS + +/* If you want numeric user/group ids when possible, uncomment this */ +/* #define BACL_WANT_NUMERIC_IDS */ + +/* We support the following types of ACLs */ +#define BACL_TYPE_NONE 0x000 +#define BACL_TYPE_ACCESS 0x001 +#define BACL_TYPE_DEFAULT 0x002 + +#define BACL_CAP_NONE 0x000 /* No special capabilities */ +#define BACL_CAP_DEFAULTS 0x001 /* Has default ACLs for directories */ +#define BACL_CAP_DEFAULTS_DIR 0x002 /* Default ACLs must be read separately */ + +/* Set capabilities for various OS */ +#if defined(HAVE_SUN_OS) +#define BACL_CAP BACL_CAP_DEFAULTS +#elif defined(HAVE_FREEBSD_OS) \ + || defined(HAVE_IRIX_OS) \ + || defined(HAVE_OSF1_OS) \ + || defined(HAVE_LINUX_OS) +#define BACL_CAP (BACL_CAP_DEFAULTS|BACL_CAP_DEFAULTS_DIR) +#else +#define BACL_CAP BACL_CAP_NONE +#endif + +#endif diff --git a/bacula/src/filed/filed.c b/bacula/src/filed/filed.c index 71c2b14bbd..37a1d3547c 100644 --- a/bacula/src/filed/filed.c +++ b/bacula/src/filed/filed.c @@ -7,7 +7,7 @@ * */ /* - Copyright (C) 2000-2004 Kern Sibbald and John Walker + Copyright (C) 2000-2005 Kern Sibbald This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -62,8 +62,8 @@ static pthread_t server_tid; static void usage() { - fprintf(stderr, _( -"Copyright (C) 2000-2004 Kern Sibbald and John Walker\n" + Pmsg0(-1, _( +"Copyright (C) 2000-2005 Kern Sibbald\n" "\nVersion: " VERSION " (" BDATE ")\n\n" "Usage: bacula-fd [-f -s] [-c config_file] [-d debug_level]\n" " -c use as configuration file\n" @@ -202,7 +202,7 @@ int main (int argc, char *argv[]) me->messages = (MSGS *)GetNextRes(R_MSGS, NULL); UnlockRes(); if (!me->messages) { - Emsg1(M_ABORT, 0, _("No Messages resource defined in %s\n"), configfile); + Emsg1(M_ABORT, 0, _("No Messages resource defined in %s\n"), configfile); } } close_msg(NULL); /* close temp message handler */ @@ -253,7 +253,7 @@ int main (int argc, char *argv[]) /* Become server, and handle requests */ IPADDR *p; foreach_dlist(p, me->FDaddrs) { - Dmsg1(10, "filed: listening on port %d\n", p->get_port_host_order()); + Dmsg1(10, "filed: listening on port %d\n", p->get_port_host_order()); } bnet_thread_server(me->FDaddrs, me->MaxConcurrentJobs, &dir_workq, handle_client_request); } diff --git a/bacula/src/filed/filed.h b/bacula/src/filed/filed.h index a49139a996..7902f45df9 100644 --- a/bacula/src/filed/filed.h +++ b/bacula/src/filed/filed.h @@ -30,6 +30,7 @@ #include "chksum.h" #include "findlib/find.h" #include "jcr.h" +#include "acl.h" #include "protos.h" /* file daemon prototypes */ #ifdef HAVE_LIBZ #include /* compression headers */ diff --git a/bacula/src/filed/job.c b/bacula/src/filed/job.c index 3b516bef6b..e7fb78c341 100644 --- a/bacula/src/filed/job.c +++ b/bacula/src/filed/job.c @@ -248,7 +248,11 @@ void *handle_client_request(void *dirp) regfree((regex_t *)fo->regex.get(k)); } fo->regex.destroy(); + fo->regexdir.destroy(); + fo->regexfile.destroy(); fo->wild.destroy(); + fo->wilddir.destroy(); + fo->wildfile.destroy(); fo->base.destroy(); fo->fstype.destroy(); if (fo->reader) { @@ -269,7 +273,11 @@ void *handle_client_request(void *dirp) for (j=0; jopts_list.size(); j++) { findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j); fo->regex.destroy(); + fo->regexdir.destroy(); + fo->regexfile.destroy(); fo->wild.destroy(); + fo->wilddir.destroy(); + fo->wildfile.destroy(); fo->base.destroy(); fo->fstype.destroy(); } @@ -632,7 +640,11 @@ static findFOPTS *start_options(FF_PKT *ff) findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS)); memset(fo, 0, sizeof(findFOPTS)); fo->regex.init(1, true); + fo->regexdir.init(1, true); + fo->regexfile.init(1, true); fo->wild.init(1, true); + fo->wilddir.init(1, true); + fo->wildfile.init(1, true); fo->base.init(1, true); fo->fstype.init(1, true); incexe->current_opts = fo; @@ -706,15 +718,35 @@ static void add_fileset(JCR *jcr, const char *item) int state = fileset->state; findFOPTS *current_opts; + /* Get code, optional subcode, and position item past the dividing space */ Dmsg1(100, "%s\n", item); int code = item[0]; - if (item[1] == ' ') { /* If string follows */ - item += 2; /* point to string */ + if (code != '\0') { + ++item; + } + int subcode = ' '; /* A space is always a valid subcode */ + if (item[0] != '\0' && item[0] != ' ') { + subcode = item[0]; + ++item; + } + if (*item == ' ') { + ++item; } + /* Skip all lines we receive after an error */ if (state == state_error) { return; } + + /* + * The switch tests the code for validity. + * The subcode is always good if it is a space, otherwise we must confirm. + * We set state to state_error first assuming the subcode is invalid, + * requiring state to be set in cases below that handle subcodes. + */ + if (subcode != ' ') { + state = state_error; + } switch (code) { case 'I': /* New include */ @@ -759,8 +791,16 @@ static void add_fileset(JCR *jcr, const char *item) state = state_error; break; } - current_opts->regex.append(preg); state = state_options; + if (subcode == ' ') { + current_opts->regex.append(preg); + } else if (subcode == 'D') { + current_opts->regexdir.append(preg); + } else if (subcode == 'F') { + current_opts->regexfile.append(preg); + } else { + state = state_error; + } break; case 'B': current_opts = start_options(ff); @@ -774,8 +814,16 @@ static void add_fileset(JCR *jcr, const char *item) break; case 'W': current_opts = start_options(ff); - current_opts->wild.append(bstrdup(item)); state = state_options; + if (subcode == ' ') { + current_opts->wild.append(bstrdup(item)); + } else if (subcode == 'D') { + current_opts->wilddir.append(bstrdup(item)); + } else if (subcode == 'F') { + current_opts->wildfile.append(bstrdup(item)); + } else { + state = state_error; + } break; case 'O': current_opts = start_options(ff); @@ -814,9 +862,21 @@ static bool term_fileset(JCR *jcr) for (k=0; kregex.size(); k++) { Dmsg1(400, "R %s\n", (char *)fo->regex.get(k)); } - for (k=0; kwild.size(); k++) { - Dmsg1(400, "W %s\n", (char *)fo->wild.get(k)); - } + for (k=0; kregexdir.size(); k++) { + Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k)); + } + for (k=0; kregexfile.size(); k++) { + Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k)); + } + for (k=0; kwild.size(); k++) { + Dmsg1(400, "W %s\n", (char *)fo->wild.get(k)); + } + for (k=0; kwilddir.size(); k++) { + Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k)); + } + for (k=0; kwildfile.size(); k++) { + Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k)); + } for (k=0; kbase.size(); k++) { Dmsg1(400, "B %s\n", (char *)fo->base.get(k)); } @@ -842,9 +902,21 @@ static bool term_fileset(JCR *jcr) for (k=0; kregex.size(); k++) { Dmsg1(400, "R %s\n", (char *)fo->regex.get(k)); } - for (k=0; kwild.size(); k++) { - Dmsg1(400, "W %s\n", (char *)fo->wild.get(k)); - } + for (k=0; kregexdir.size(); k++) { + Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k)); + } + for (k=0; kregexfile.size(); k++) { + Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k)); + } + for (k=0; kwild.size(); k++) { + Dmsg1(400, "W %s\n", (char *)fo->wild.get(k)); + } + for (k=0; kwilddir.size(); k++) { + Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k)); + } + for (k=0; kwildfile.size(); k++) { + Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k)); + } for (k=0; kbase.size(); k++) { Dmsg1(400, "B %s\n", (char *)fo->base.get(k)); } diff --git a/bacula/src/filed/protos.h b/bacula/src/filed/protos.h index 901912b972..6d30c93dfc 100644 --- a/bacula/src/filed/protos.h +++ b/bacula/src/filed/protos.h @@ -35,3 +35,7 @@ void start_heartbeat_monitor(JCR *jcr); void stop_heartbeat_monitor(JCR *jcr); void start_dir_heartbeat(JCR *jcr); void stop_dir_heartbeat(JCR *jcr); + +/* From acl.c */ +POOLMEM *bacl_get(char *fname, int acltype); +int bacl_set(char *fname, int acltype, char *acltext); diff --git a/bacula/src/findlib/find.c b/bacula/src/findlib/find.c index 826251a8f1..1d5f1009fc 100644 --- a/bacula/src/findlib/find.c +++ b/bacula/src/findlib/find.c @@ -180,6 +180,29 @@ static bool accept_file(FF_PKT *ff) ff->writer = fo->writer; ff->fstypes = fo->fstype; ic = (ff->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0; + if (S_ISDIR(ff->statp.st_mode)) { + for (k=0; kwilddir.size(); k++) { + if (fnmatch((char *)fo->wilddir.get(k), ff->fname, fnmode|ic) == 0) { + if (ff->flags & FO_EXCLUDE) { + Dmsg2(100, "Exclude wilddir: %s file=%s\n", (char *)fo->wilddir.get(k), + ff->fname); + return false; /* reject file */ + } + return true; /* accept file */ + } + } + } else { + for (k=0; kwildfile.size(); k++) { + if (fnmatch((char *)fo->wildfile.get(k), ff->fname, fnmode|ic) == 0) { + if (ff->flags & FO_EXCLUDE) { + Dmsg2(100, "Exclude wildfile: %s file=%s\n", (char *)fo->wildfile.get(k), + ff->fname); + return false; /* reject file */ + } + return true; /* accept file */ + } + } + } for (k=0; kwild.size(); k++) { if (fnmatch((char *)fo->wild.get(k), ff->fname, fnmode|ic) == 0) { if (ff->flags & FO_EXCLUDE) { @@ -191,6 +214,29 @@ static bool accept_file(FF_PKT *ff) } } #ifndef WIN32 + if (S_ISDIR(ff->statp.st_mode)) { + for (k=0; kregexdir.size(); k++) { + const int nmatch = 30; + regmatch_t pmatch[nmatch]; + if (regexec((regex_t *)fo->regexdir.get(k), ff->fname, nmatch, pmatch, 0) == 0) { + if (ff->flags & FO_EXCLUDE) { + return false; /* reject file */ + } + return true; /* accept file */ + } + } + } else { + for (k=0; kregexfile.size(); k++) { + const int nmatch = 30; + regmatch_t pmatch[nmatch]; + if (regexec((regex_t *)fo->regexfile.get(k), ff->fname, nmatch, pmatch, 0) == 0) { + if (ff->flags & FO_EXCLUDE) { + return false; /* reject file */ + } + return true; /* accept file */ + } + } + } for (k=0; kregex.size(); k++) { const int nmatch = 30; regmatch_t pmatch[nmatch]; diff --git a/bacula/src/findlib/find.h b/bacula/src/findlib/find.h index 5caed56e27..16d1a393a9 100755 --- a/bacula/src/findlib/find.h +++ b/bacula/src/findlib/find.h @@ -128,7 +128,11 @@ struct findFOPTS { int GZIP_level; /* GZIP level */ char VerifyOpts[MAX_FOPTS]; /* verify options */ alist regex; /* regex string(s) */ + alist regexdir; /* regex string(s) for directories */ + alist regexfile; /* regex string(s) for files */ alist wild; /* wild card strings */ + alist wilddir; /* wild card strings for directories */ + alist wildfile; /* wild card strings for files */ alist base; /* list of base names */ alist fstype; /* file system type limitation */ char *reader; /* reader program */ diff --git a/bacula/src/findlib/fstype.c b/bacula/src/findlib/fstype.c index c6e4620a87..873532069c 100644 --- a/bacula/src/findlib/fstype.c +++ b/bacula/src/findlib/fstype.c @@ -43,9 +43,9 @@ "HAVE_SUN_OS\n" #define POOLMEM char #define bstrdup strdup -#define Dmsg0(n,s) fprintf(stderr, s "\n"); -#define Dmsg1(n,s,a1) fprintf(stderr, s "\n", a1); -#define Dmsg2(n,s,a1,a2) fprintf(stderr, s "\n", a1, a2); +#define Dmsg0(n,s) fprintf(stderr, s); +#define Dmsg1(n,s,a1) fprintf(stderr, s, a1); +#define Dmsg2(n,s,a1,a2) fprintf(stderr, s, a1, a2); #endif /* @@ -65,7 +65,7 @@ POOLMEM *fstype(const char *fname) if (statfs(fname, &st) == 0) { return bstrdup(st.f_fstypename); } - Dmsg1(50, "statfs() failed for \"%s\"", fname); + Dmsg1(50, "statfs() failed for \"%s\"\n", fname); return NULL; } @@ -79,7 +79,7 @@ POOLMEM *fstype(const char *fname) if (statvfs(fname, &st) == 0) { return bstrdup(st.f_basetype); } - Dmsg1(50, "statfs() failed for \"%s\"", fname); + Dmsg1(50, "statfs() failed for \"%s\"\n", fname); return NULL; } @@ -172,12 +172,12 @@ POOLMEM *fstype(const char *fname) #endif default: - Dmsg2(10, "Unknown file system type \"0x%x\" for \"%s\".", st.f_type, + Dmsg2(10, "Unknown file system type \"0x%x\" for \"%s\".\n", st.f_type, fname); return NULL; } } - Dmsg1(50, "statfs() failed for \"%s\"", fname); + Dmsg1(50, "statfs() failed for \"%s\"\n", fname); return NULL; } @@ -190,14 +190,14 @@ POOLMEM *fstype(const char *fname) if (lstat(fname, &st) == 0) { return bstrdup(st.st_fstype); } - Dmsg1(50, "lstat() failed for \"%s\"", fname); + Dmsg1(50, "lstat() failed for \"%s\"\n", fname); return NULL; } #else /* No recognised OS */ POOLMEM *fstype(const char *fname) { - Dmsg0(10, "!!! fstype() not implemented for this OS. !!!"); + Dmsg0(10, "!!! fstype() not implemented for this OS. !!!\n"); #ifdef TEST_PROGRAM Dmsg1(10, "Please define one of the following when compiling:\n\n%s\n", SUPPORTEDOSES); diff --git a/bacula/src/version.h b/bacula/src/version.h index 28bed4bc23..2f0c65f4ac 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -1,8 +1,8 @@ /* */ #undef VERSION #define VERSION "1.37.1" -#define BDATE "01 January 2005" -#define LSMDATE "01Jan05" +#define BDATE "06 January 2005" +#define LSMDATE "06Jan05" /* Debug flags */ #undef DEBUG -- 2.39.5