From d08d3642c66b931918accc895e1440389408fe95 Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Sat, 26 Aug 2006 11:28:39 +0000 Subject: [PATCH] kes Add host:port to connect failure messages to FD and SD from Dir. kes Add WhereACL to console ACL list. If nothing is specified, only the default is permitted for restore. Otherwise, *all* allows any path, or you can specify permitted paths. This should allow control over where users can restore files. This is untested. kes Modified message to add a ? (as in loaded?) when querying the autochanger for what Slot is loaded. kes Fixed the use of Slot, so that is more correctly maintained, thus eliminating unneeded duplicate calls to determine what Slot is loaded. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@3374 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/kernstodo | 8 +++---- bacula/projects | 25 ++++++++++++++++++++ bacula/src/dird/authenticate.c | 41 ++++++++++++++++++++------------- bacula/src/dird/dird_conf.c | 3 ++- bacula/src/dird/dird_conf.h | 1 + bacula/src/dird/ua_acl.c | 28 +++++++++++----------- bacula/src/dird/ua_restore.c | 8 +++++++ bacula/src/dird/ua_run.c | 4 ++++ bacula/src/stored/autochanger.c | 24 ++++++++++++------- bacula/src/stored/dev.c | 11 ++++----- bacula/src/stored/dev.h | 2 +- bacula/src/stored/dvd.c | 6 +++-- bacula/src/version.h | 4 ++-- bacula/technotes-1.39 | 11 +++++++++ 14 files changed, 121 insertions(+), 55 deletions(-) diff --git a/bacula/kernstodo b/bacula/kernstodo index 4f214467cb..5a30162551 100644 --- a/bacula/kernstodo +++ b/bacula/kernstodo @@ -46,16 +46,12 @@ For 1.39: - Look at why SIGPIPE during connection can cause seg fault in writing the daemon message, when Dir dropped to bacula:bacula - Look at zlib 32 => 64 problems. -- Ensure that connection to daemon failure always indicates what - daemon it was trying to connect to. - Try turning on disk seek code. - Possibly turn on St. Bernard code. - Fix bextract to restore ACLs, or better yet, use common routines. - Do we migrate appendable Volumes? - Remove queue.c code. -- Add bconsole option to use stdin/out instead of conio. -- Fix ClientRunBefore/AfterJob compatibility. - Fix re-read of last block to check if job has actually written a block, and check if block was written by a different job (i.e. multiple simultaneous jobs writing). @@ -1654,4 +1650,8 @@ Block Position: 0 - Fix wx-console scanning problem with commas in names. - Add manpages to the list of directories for make install. Notify Scott +- Add bconsole option to use stdin/out instead of conio. +- Fix ClientRunBefore/AfterJob compatibility. +- Ensure that connection to daemon failure always indicates what + daemon it was trying to connect to. diff --git a/bacula/projects b/bacula/projects index 4af15b1ce7..69b1a556d8 100644 --- a/bacula/projects +++ b/bacula/projects @@ -997,3 +997,28 @@ Status: could override the Storage parameter for full and/or differential backups, then the Full job would use the proper Storage device, which has more capacity (i.e. a 8TB tape library. + + +Item: Implement multiple numeric backup levels as supported by dump +Date: 3 April 2006 +Origin: Daniel Rich +Status: +What: Dump allows specification of backup levels numerically instead of just + "full", "incr", and "diff". In this system, at any given level, all + files are backed up that were were modified since the last backup of a + higher level (with 0 being the highest and 9 being the lowest). A + level 0 is therefore equivalent to a full, level 9 an incremental, and + the levels 1 through 8 are varying levels of differentials. For + bacula's sake, these could be represented as "full", "incr", and + "diff1", "diff2", etc. + +Why: Support of multiple backup levels would provide for more advanced backup + rotation schemes such as "Towers of Hanoi". This would allow better + flexibility in performing backups, and can lead to shorter recover + times. + +Notes: Legato Networker supports a similar system with full, incr, and 1-9 as + levels. + +Kern notes: I think this would add very little functionality, but a *lot* of + additional overhead to Bacula. diff --git a/bacula/src/dird/authenticate.c b/bacula/src/dird/authenticate.c index 383e78ae57..d0abcff46f 100644 --- a/bacula/src/dird/authenticate.c +++ b/bacula/src/dird/authenticate.c @@ -91,12 +91,13 @@ bool authenticate_storage_daemon(JCR *jcr, STORE *store) if (!auth_success) { stop_bsock_timer(tid); Dmsg0(50, _("Director and Storage daemon passwords or names not the same.\n")); - Jmsg0(jcr, M_FATAL, 0, - _("Director unable to authenticate with Storage daemon. Possible causes:\n" + Jmsg2(jcr, M_FATAL, 0, + _("Director unable to authenticate with Storage daemon on \"%s:%d\". Possible causes:\n" "Passwords or names not the same or\n" "Maximum Concurrent Jobs exceeded on the SD or\n" "SD networking messed up (restart daemon).\n" - "Please see http://www.bacula.org/rel-manual/faq.html#AuthorizationErrors for help.\n")); + "Please see http://www.bacula.org/rel-manual/faq.html#AuthorizationErrors for help.\n"), + sd->host, sd->port); return 0; } @@ -119,7 +120,8 @@ bool authenticate_storage_daemon(JCR *jcr, STORE *store) /* Engage TLS! Full Speed Ahead! */ if (!bnet_tls_client(store->tls_ctx, sd)) { stop_bsock_timer(tid); - Jmsg(jcr, M_FATAL, 0, _("TLS negotiation failed.\n")); + Jmsg(jcr, M_FATAL, 0, _("TLS negotiation failed with SD on \"%s:%d\"\n"), + sd->host, sd->port); return 0; } } @@ -127,15 +129,16 @@ bool authenticate_storage_daemon(JCR *jcr, STORE *store) Dmsg1(116, ">stored: %s", sd->msg); if (bnet_recv(sd) <= 0) { stop_bsock_timer(tid); - Jmsg1(jcr, M_FATAL, 0, _("bdirdwho, sd->host, bnet_strerror(sd)); return 0; } Dmsg1(110, "msg); stop_bsock_timer(tid); if (strncmp(sd->msg, OKhello, sizeof(OKhello)) != 0) { Dmsg0(50, _("Storage daemon rejected Hello command\n")); - Jmsg0(jcr, M_FATAL, 0, _("Storage daemon rejected Hello command\n")); + Jmsg2(jcr, M_FATAL, 0, _("Storage daemon on \"%s:%d\" rejected Hello command\n"), + sd->host, sd->port); return 0; } return 1; @@ -163,7 +166,8 @@ int authenticate_file_daemon(JCR *jcr) btimer_t *tid = start_bsock_timer(fd, AUTH_TIMEOUT); if (!bnet_fsend(fd, hello, dirname)) { stop_bsock_timer(tid); - Jmsg(jcr, M_FATAL, 0, _("Error sending Hello to File daemon. ERR=%s\n"), bnet_strerror(fd)); + Jmsg(jcr, M_FATAL, 0, _("Error sending Hello to File daemon on \"%s:%d\". ERR=%s\n"), + fd->host, fd->port, bnet_strerror(fd)); return 0; } Dmsg1(50, "Sent: %s", fd->msg); @@ -190,25 +194,28 @@ int authenticate_file_daemon(JCR *jcr) stop_bsock_timer(tid); Dmsg0(50, _("Director and File daemon passwords or names not the same.\n")); Jmsg(jcr, M_FATAL, 0, - _("Unable to authenticate with File daemon. Possible causes:\n" + _("Unable to authenticate with File daemon on \"%s:%d\". Possible causes:\n" "Passwords or names not the same or\n" "Maximum Concurrent Jobs exceeded on the FD or\n" "FD networking messed up (restart daemon).\n" - "Please see http://www.bacula.org/rel-manual/faq.html#AuthorizationErrors for help.\n")); + "Please see http://www.bacula.org/rel-manual/faq.html#AuthorizationErrors for help.\n"), + fd->host, fd->port); return 0; } /* Verify that the remote host is willing to meet our TLS requirements */ if (tls_remote_need < tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) { stop_bsock_timer(tid); - Jmsg(jcr, M_FATAL, 0, _("Authorization problem: Remote server did not advertise required TLS support.\n")); + Jmsg(jcr, M_FATAL, 0, _("Authorization problem: FD \"%s:%s\" did not advertise required TLS support.\n"), + fd->who, fd->host); return 0; } /* Verify that we are willing to meet the remote host's requirements */ if (tls_remote_need > tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) { stop_bsock_timer(tid); - Jmsg(jcr, M_FATAL, 0, _("Authorization problem: Remote server requires TLS.\n")); + Jmsg(jcr, M_FATAL, 0, _("Authorization problem: FD on \"%s:%d\" requires TLS.\n"), + fd->host, fd->port); return 0; } @@ -217,7 +224,8 @@ int authenticate_file_daemon(JCR *jcr) /* Engage TLS! Full Speed Ahead! */ if (!bnet_tls_client(client->tls_ctx, fd)) { stop_bsock_timer(tid); - Jmsg(jcr, M_FATAL, 0, _("TLS negotiation failed.\n")); + Jmsg(jcr, M_FATAL, 0, _("TLS negotiation failed with FD on \"%s:%d\".\n"), + fd->host, fd->port); return 0; } } @@ -227,15 +235,16 @@ int authenticate_file_daemon(JCR *jcr) stop_bsock_timer(tid); Dmsg1(50, _("Bad response from File daemon to Hello command: ERR=%s\n"), bnet_strerror(fd)); - Jmsg(jcr, M_FATAL, 0, _("Bad response from File daemon to Hello command: ERR=%s\n"), - bnet_strerror(fd)); + Jmsg(jcr, M_FATAL, 0, _("Bad response from File daemon on \"%s:%d\" to Hello command: ERR=%s\n"), + fd->host, fd->port, bnet_strerror(fd)); return 0; } Dmsg1(110, "msg); stop_bsock_timer(tid); if (strncmp(fd->msg, FDOKhello, sizeof(FDOKhello)) != 0) { Dmsg0(50, _("File daemon rejected Hello command\n")); - Jmsg(jcr, M_FATAL, 0, _("File daemon rejected Hello command\n")); + Jmsg(jcr, M_FATAL, 0, _("File daemon on \"%s:%d\" rejected Hello command\n"), + fd->host, fd->port); return 0; } return 1; diff --git a/bacula/src/dird/dird_conf.c b/bacula/src/dird/dird_conf.c index 8cbf3e3feb..520d133cc9 100644 --- a/bacula/src/dird/dird_conf.c +++ b/bacula/src/dird/dird_conf.c @@ -137,6 +137,7 @@ static RES_ITEM con_items[] = { {"commandacl", store_acl, ITEM(res_con.ACL_lists), Command_ACL, 0, 0}, {"filesetacl", store_acl, ITEM(res_con.ACL_lists), FileSet_ACL, 0, 0}, {"catalogacl", store_acl, ITEM(res_con.ACL_lists), Catalog_ACL, 0, 0}, + {"whereacl", store_acl, ITEM(res_con.ACL_lists), Where_ACL, 0, 0}, {"tlsenable", store_bool, ITEM(res_con.tls_enable), 0, 0, 0}, {"tlsrequire", store_bool, ITEM(res_con.tls_require), 0, 0, 0}, {"tlsverifypeer", store_bool, ITEM(res_con.tls_verify_peer), 0, ITEM_DEFAULT, true}, @@ -1546,7 +1547,7 @@ void store_acl(LEX *lc, RES_ITEM *item, int index, int pass) int token; for (;;) { - token = lex_get_token(lc, T_NAME); + token = lex_get_token(lc, T_STRING); if (pass == 1) { if (((alist **)item->value)[item->code] == NULL) { ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist)); diff --git a/bacula/src/dird/dird_conf.h b/bacula/src/dird/dird_conf.h index e77ccdeaae..67ec18d747 100644 --- a/bacula/src/dird/dird_conf.h +++ b/bacula/src/dird/dird_conf.h @@ -168,6 +168,7 @@ enum { Command_ACL, FileSet_ACL, Catalog_ACL, + Where_ACL, Num_ACL /* keep last */ }; diff --git a/bacula/src/dird/ua_acl.c b/bacula/src/dird/ua_acl.c index dcfc0e468a..6a801c686d 100644 --- a/bacula/src/dird/ua_acl.c +++ b/bacula/src/dird/ua_acl.c @@ -8,22 +8,17 @@ */ /* - Copyright (C) 2004-2005 Kern Sibbald + Copyright (C) 2004-2006 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 - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. + modify it under the terms of the GNU General Public License + version 2 as amended with additional clauses defined in the + file LICENSE in the main source directory. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, - MA 02111-1307, USA. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + the file LICENSE for additional details. */ @@ -46,12 +41,15 @@ bool acl_access_ok(UAContext *ua, int acl, char *item, int len) /* If no console resource => default console and all is permitted */ if (!ua->cons) { Dmsg0(1400, "Root cons access OK.\n"); - return true; /* No cons resource -> root console OK for everything */ + return true; /* No cons resource -> root console OK for everything */ } alist *list = ua->cons->ACL_lists[acl]; - if (!list) { - return false; /* List empty, reject everything */ + if (!list) { /* empty list */ + if (len == 0 && acl == Where_ACL) { + return true; /* Empty list for Where => empty where */ + } + return false; /* List empty, reject everything */ } /* Special case *all* gives full access */ @@ -63,7 +61,7 @@ bool acl_access_ok(UAContext *ua, int acl, char *item, int len) for (int i=0; isize(); i++) { if (strcasecmp(item, (char *)list->get(i)) == 0) { Dmsg3(1400, "ACL found %s in %d %s\n", item, acl, (char *)list->get(i)); - return true; + return true; } } return false; diff --git a/bacula/src/dird/ua_restore.c b/bacula/src/dird/ua_restore.c index 07f00a0c3d..c8765f5117 100644 --- a/bacula/src/dird/ua_restore.c +++ b/bacula/src/dird/ua_restore.c @@ -79,6 +79,10 @@ int restore_cmd(UAContext *ua, const char *cmd) i = find_arg_with_value(ua, "where"); if (i >= 0) { rx.where = ua->argv[i]; + if (!acl_access_ok(ua, Where_ACL, rx.where)) { + bsendmsg(ua, _("Forbidden \"where\" specified.\n")); + goto bail_out; + } } if (!open_db(ua)) { @@ -164,6 +168,10 @@ int restore_cmd(UAContext *ua, const char *cmd) /* Build run command */ if (rx.where) { + if (!acl_access_ok(ua, Where_ACL, rx.where)) { + bsendmsg(ua, _("Forbidden \"where\" specified.\n")); + goto bail_out; + } Mmsg(ua->cmd, "run job=\"%s\" client=\"%s\" storage=\"%s\" bootstrap=\"%s\"" " where=\"%s\" files=%d catalog=\"%s\"", diff --git a/bacula/src/dird/ua_run.c b/bacula/src/dird/ua_run.c index b55bc1590a..c18fce45ed 100644 --- a/bacula/src/dird/ua_run.c +++ b/bacula/src/dird/ua_run.c @@ -185,6 +185,10 @@ int run_cmd(UAContext *ua, const char *cmd) return 0; } where = ua->argv[i]; + if (!acl_access_ok(ua, Where_ACL, where)) { + bsendmsg(ua, _("Forbidden \"where\" specified.\n")); + return 0; + } kw_ok = true; break; case 10: /* bootstrap */ diff --git a/bacula/src/stored/autochanger.c b/bacula/src/stored/autochanger.c index 2db94094e4..f2bd9fd1fc 100644 --- a/bacula/src/stored/autochanger.c +++ b/bacula/src/stored/autochanger.c @@ -182,6 +182,7 @@ int autoload_device(DCR *dcr, int writing, BSOCK *dir) Jmsg(jcr, M_FATAL, 0, _("3992 Bad autochanger \"load slot %d, drive %d\": ERR=%s.\n"), slot, drive, be.strerror()); rtn_stat = -1; /* hard error */ + dev->Slot = -1; /* mark unknown */ } Dmsg2(100, "load slot %d status=%d\n", slot, status); unlock_changer(dcr); @@ -212,15 +213,22 @@ bail_out: int get_autochanger_loaded_slot(DCR *dcr) { JCR *jcr = dcr->jcr; + DEVICE *dev = dcr->dev; POOLMEM *changer, *results; int status, loaded; uint32_t timeout = dcr->device->max_changer_wait; int drive = dcr->dev->drive_index; + if (!dev->is_autochanger()) { + return -1; + } if (!dcr->device->changer_command) { Jmsg(jcr, M_FATAL, 0, _("3992 Missing Changer command.\n")); return -1; } + if (dev->Slot >0) { + return dev->Slot; + } results = get_pool_memory(PM_MESSAGE); changer = get_pool_memory(PM_FNAME); @@ -228,7 +236,7 @@ int get_autochanger_loaded_slot(DCR *dcr) /* Find out what is loaded, zero means device is unloaded */ lock_changer(dcr); - Jmsg(jcr, M_INFO, 0, _("3301 Issuing autochanger \"loaded drive %d\" command.\n"), + Jmsg(jcr, M_INFO, 0, _("3301 Issuing autochanger \"loaded? drive %d\" command.\n"), drive); changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "loaded"); *results = 0; @@ -238,18 +246,18 @@ int get_autochanger_loaded_slot(DCR *dcr) if (status == 0) { loaded = str_to_int32(results); if (loaded > 0) { - Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded drive %d\", result is Slot %d.\n"), + Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded? drive %d\", result is Slot %d.\n"), drive, loaded); - dcr->dev->Slot = loaded; + dev->Slot = loaded; } else { - Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded drive %d\", result: nothing loaded.\n"), + Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded? drive %d\", result: nothing loaded.\n"), drive); - dcr->dev->Slot = 0; + dev->Slot = -1; /* unknown */ } } else { berrno be; be.set_errno(status); - Jmsg(jcr, M_INFO, 0, _("3991 Bad autochanger \"loaded drive %d\" command: ERR=%s.\n"), + Jmsg(jcr, M_INFO, 0, _("3991 Bad autochanger \"loaded? drive %d\" command: ERR=%s.\n"), drive, be.strerror()); loaded = -1; /* force unload */ } @@ -325,7 +333,7 @@ bool unload_autochanger(DCR *dcr, int loaded) slot, dev->drive_index, be.strerror()); ok = false; } else { - dev->Slot = 0; /* nothing loaded */ + dev->Slot = -1; /* unknown */ } free_pool_memory(changer); unlock_changer(dcr); @@ -424,7 +432,7 @@ static bool unload_other_drive(DCR *dcr, int slot) slot, dev->drive_index, be.strerror()); ok = false; } else { - dev->Slot = 0; /* nothing loaded */ + dev->Slot = -1; /* nothing loaded */ Dmsg0(100, "Slot unloaded\n"); } unlock_changer(dcr); diff --git a/bacula/src/stored/dev.c b/bacula/src/stored/dev.c index 9dfaa307d0..43eec74d98 100644 --- a/bacula/src/stored/dev.c +++ b/bacula/src/stored/dev.c @@ -131,6 +131,7 @@ init_dev(JCR *jcr, DEVRES *device) dev = (DEVICE *)malloc(sizeof(DEVICE)); memset(dev, 0, sizeof(DEVICE)); + dev->Slot = -1; /* unknown */ /* Copy user supplied device parameters from Resource */ dev->dev_name = get_memory(strlen(device->device_name)+1); @@ -281,6 +282,7 @@ DEVICE::open(DCR *dcr, int omode) Dmsg4(29, "open dev: type=%d dev_name=%s vol=%s mode=%s\n", dev_type, print_name(), VolCatInfo.VolCatName, mode_to_str(omode)); state &= ~(ST_LABEL|ST_APPEND|ST_READ|ST_EOT|ST_WEOT|ST_EOF); + Slot = -1; /* unknown slot */ label_type = B_BACULA_LABEL; if (is_tape() || is_fifo()) { open_tape_device(dcr, omode); @@ -325,9 +327,7 @@ void DEVICE::open_tape_device(DCR *dcr, int omode) int nonblocking = O_NONBLOCK; Dmsg0(29, "open dev: device is tape\n"); - if (is_autochanger()) { - get_autochanger_loaded_slot(dcr); - } + get_autochanger_loaded_slot(dcr); set_mode(omode); timeout = max_open_wait; @@ -423,9 +423,7 @@ void DEVICE::open_file_device(DCR *dcr, int omode) { POOL_MEM archive_name(PM_FNAME); - if (is_autochanger()) { - get_autochanger_loaded_slot(dcr); - } + get_autochanger_loaded_slot(dcr); /* * Handle opening of File Archive (not a tape) @@ -1799,6 +1797,7 @@ void DEVICE::close() part_size = 0; part_start = 0; EndFile = EndBlock = 0; + Slot = -1; /* unknown slot */ free_volume(this); memset(&VolCatInfo, 0, sizeof(VolCatInfo)); memset(&VolHdr, 0, sizeof(VolHdr)); diff --git a/bacula/src/stored/dev.h b/bacula/src/stored/dev.h index 4f2068ee15..3f4d13e223 100644 --- a/bacula/src/stored/dev.h +++ b/bacula/src/stored/dev.h @@ -162,7 +162,7 @@ struct VOLUME_CAT_INFO { uint32_t EndFile; /* Last file number */ uint32_t EndBlock; /* Last block number */ int32_t LabelType; /* Bacula/ANSI/IBM */ - int32_t Slot; /* Slot in changer */ + int32_t Slot; /* >0=Slot loaded, 0=nothing, -1=unknown */ bool InChanger; /* Set if vol in current magazine */ uint32_t VolCatMaxJobs; /* Maximum Jobs to write to volume */ uint32_t VolCatMaxFiles; /* Maximum files to write to volume */ diff --git a/bacula/src/stored/dvd.c b/bacula/src/stored/dvd.c index bc50a59a24..3bb1d6733a 100644 --- a/bacula/src/stored/dvd.c +++ b/bacula/src/stored/dvd.c @@ -727,7 +727,8 @@ bool dvd_close_job(DCR *dcr) return ok; } -bool truncate_dvd(DCR *dcr) { +bool truncate_dvd(DCR *dcr) +{ DEVICE* dev = dcr->dev; if (dev->fd >= 0) { @@ -795,7 +796,8 @@ bool truncate_dvd(DCR *dcr) { /* Checks if we can write on a non-blank DVD: meaning that it just have been * truncated (there is only one zero-sized file on the DVD, with the right * volume name). */ -bool check_can_write_on_non_blank_dvd(DCR *dcr) { +bool check_can_write_on_non_blank_dvd(DCR *dcr) +{ DEVICE* dev = dcr->dev; DIR* dp; struct dirent *entry, *result; diff --git a/bacula/src/version.h b/bacula/src/version.h index 99683cf5a6..2903b73427 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -4,8 +4,8 @@ #undef VERSION #define VERSION "1.39.21" -#define BDATE "23 August 2006" -#define LSMDATE "23Aug06" +#define BDATE "26 August 2006" +#define LSMDATE "26Aug06" #define BYEAR "2006" /* year for copyright messages in progs */ /* Debug flags */ diff --git a/bacula/technotes-1.39 b/bacula/technotes-1.39 index d83b2bf41a..aad540623a 100644 --- a/bacula/technotes-1.39 +++ b/bacula/technotes-1.39 @@ -1,6 +1,17 @@ Technical notes on version 1.39 General: +26Aug06 +kes Add host:port to connect failure messages to FD and SD from Dir. +kes Add WhereACL to console ACL list. If nothing is specified, only + the default is permitted for restore. Otherwise, *all* allows any + path, or you can specify permitted paths. This should allow control + over where users can restore files. This is untested. +kes Modified message to add a ? (as in loaded?) when querying the autochanger + for what Slot is loaded. +kes Fixed the use of Slot, so that is more correctly maintained, thus + eliminating unneeded duplicate calls to determine what Slot is loaded. + 25Aug06 kes Install man pages with 'make install' kes wx-console crashes because of differences between Bacula and wxWidgets -- 2.39.5