From 96acf5ecbae240ead8b712852f3609e82dd1bd36 Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Sun, 22 Aug 2004 17:37:46 +0000 Subject: [PATCH] - Add default Console resource in src/dird/bacula-dir.conf.in with access restricted to commands used by tray-monitor: status and .status. - Add default Director ressource in src/filed/bacula-fd.conf.in and src/stored/bacula-sd.conf.in with Monitor directive enabled. - Add .status dir [current|last] command to dird. - Add Monitor directive in fd/sd configuration file (restrict access to status and .status commands). @meno: I made some changes in src/filed/authenticate.c and src/stored/authenticate.c, which must be adapted to your new authentication code. Please contact me if you have any questions. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@1549 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/src/dird/bacula-dir.conf.in | 11 +++ bacula/src/dird/ua_dotcmds.c | 2 + bacula/src/dird/ua_status.c | 47 ++++++++++++ bacula/src/filed/authenticate.c | 5 +- bacula/src/filed/bacula-fd.conf.in | 10 +++ bacula/src/filed/filed.h | 2 +- bacula/src/filed/filed_conf.c | 1 + bacula/src/filed/filed_conf.h | 1 + bacula/src/filed/job.c | 79 +++++++++++--------- bacula/src/jcr.h | 4 +- bacula/src/stored/authenticate.c | 5 +- bacula/src/stored/bacula-sd.conf.in | 10 +++ bacula/src/stored/dircmd.c | 59 ++++++++------- bacula/src/stored/stored_conf.c | 1 + bacula/src/stored/stored_conf.h | 7 +- bacula/src/tray-monitor/tray-monitor.c | 3 +- bacula/src/tray-monitor/tray-monitor.conf.in | 14 +++- 17 files changed, 186 insertions(+), 75 deletions(-) diff --git a/bacula/src/dird/bacula-dir.conf.in b/bacula/src/dird/bacula-dir.conf.in index fe51c4b156..ed9b17082b 100644 --- a/bacula/src/dird/bacula-dir.conf.in +++ b/bacula/src/dird/bacula-dir.conf.in @@ -219,3 +219,14 @@ Pool { Volume Retention = 365 days # one year Accept Any Volume = yes # write on any volume in the pool } + +# +# Restricted console used by tray-monitor to get the status of the director +# +Console { + Name = Monitor + Password = "@mon_dir_password@" + CommandACL = status, .status + ClientACL = + StorageACL = +} \ No newline at end of file diff --git a/bacula/src/dird/ua_dotcmds.c b/bacula/src/dird/ua_dotcmds.c index d22fe6af9a..98c9c53de0 100644 --- a/bacula/src/dird/ua_dotcmds.c +++ b/bacula/src/dird/ua_dotcmds.c @@ -45,6 +45,7 @@ extern const char *client_backups; extern int qmessagescmd(UAContext *ua, const char *cmd); extern int quit_cmd(UAContext *ua, const char *cmd); extern int qhelp_cmd(UAContext *ua, const char *cmd); +extern int qstatus_cmd(UAContext *ua, const char *cmd); /* Forward referenced functions */ static int diecmd(UAContext *ua, const char *cmd); @@ -70,6 +71,7 @@ static struct cmdstruct commands[] = { { N_(".types"), typescmd, NULL}, { N_(".backups"), backupscmd, NULL}, { N_(".levels"), levelscmd, NULL}, + { N_(".status"), qstatus_cmd, NULL}, { N_(".storage"), storagecmd, NULL}, { N_(".defaults"), defaultscmd, NULL}, { N_(".messages"), qmessagescmd, NULL}, diff --git a/bacula/src/dird/ua_status.c b/bacula/src/dird/ua_status.c index 9acb7fd0e5..0383a8c3fd 100644 --- a/bacula/src/dird/ua_status.c +++ b/bacula/src/dird/ua_status.c @@ -42,6 +42,53 @@ static void do_client_status(UAContext *ua, CLIENT *client); static void do_director_status(UAContext *ua); static void do_all_status(UAContext *ua); +static char OKqstatus[] = "2000 OK .status\n"; +static char DotStatusJob[] = "JobId=%d JobStatus=%c JobErrors=%d\n"; + +/* + * .status command + */ +int qstatus_cmd(UAContext *ua, const char *cmd) +{ + JCR* njcr; + s_last_job* job; + + if (!open_db(ua)) { + return 1; + } + Dmsg1(20, "status:%s:\n", cmd); + + if ((ua->argc != 3) || (strcasecmp(ua->argk[1], "dir"))) { + bsendmsg(ua, "2900 Bad .status command, missing arguments.\n"); + return 1; + } + + if (strcasecmp(ua->argk[2], "current") == 0) { + bsendmsg(ua, OKqstatus, ua->argk[2]); + lock_jcr_chain(); + foreach_jcr(njcr) { + if (njcr->JobId != 0) { + bsendmsg(ua, DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors); + } + free_locked_jcr(njcr); + } + unlock_jcr_chain(); + } + else if (strcasecmp(ua->argk[2], "last") == 0) { + bsendmsg(ua, OKqstatus, ua->argk[2]); + if ((last_jobs) && (last_jobs->size() > 0)) { + job = (s_last_job*)last_jobs->last(); + bsendmsg(ua, DotStatusJob, job->JobId, job->JobStatus, job->Errors); + } + } + else { + bsendmsg(ua, "2900 Bad .status command, wrong argument.\n"); + return 1; + } + + return 1; +} + /* * status command */ diff --git a/bacula/src/filed/authenticate.c b/bacula/src/filed/authenticate.c index ec3acb05e8..5e63ba0288 100644 --- a/bacula/src/filed/authenticate.c +++ b/bacula/src/filed/authenticate.c @@ -36,7 +36,7 @@ static char Dir_sorry[] = "2999 No go\n"; /********************************************************************* * */ -static int authenticate(int rcode, BSOCK *bs) +static int authenticate(int rcode, BSOCK *bs, JCR* jcr) { POOLMEM *dirname; DIRRES *director; @@ -85,6 +85,7 @@ static int authenticate(int rcode, BSOCK *bs) } stop_bsock_timer(tid); free_pool_memory(dirname); + jcr->director = director; return (director != NULL); } @@ -100,7 +101,7 @@ int authenticate_director(JCR *jcr) { BSOCK *dir = jcr->dir_bsock; - if (!authenticate(R_DIRECTOR, dir)) { + if (!authenticate(R_DIRECTOR, dir, jcr)) { bnet_fsend(dir, "%s", Dir_sorry); Emsg0(M_FATAL, 0, _("Unable to authenticate Director\n")); bmicrosleep(5, 0); diff --git a/bacula/src/filed/bacula-fd.conf.in b/bacula/src/filed/bacula-fd.conf.in index e83250e8c9..cb23806638 100644 --- a/bacula/src/filed/bacula-fd.conf.in +++ b/bacula/src/filed/bacula-fd.conf.in @@ -15,6 +15,16 @@ Director { Password = "@fd_password@" } +# +# Restricted Director, used by tray-monitor to get the +# status of the file daemon +# +Director { + Name = @hostname@-mon + Password = "@mon_fd_password@" + Monitor = yes +} + # # "Global" File daemon configuration specifications # diff --git a/bacula/src/filed/filed.h b/bacula/src/filed/filed.h index 99c3045e7c..451d601bcd 100644 --- a/bacula/src/filed/filed.h +++ b/bacula/src/filed/filed.h @@ -26,10 +26,10 @@ */ #define FILE_DAEMON 1 +#include "filed_conf.h" #include "findlib/find.h" #include "jcr.h" #include "protos.h" /* file daemon prototypes */ -#include "filed_conf.h" #ifdef HAVE_LIBZ #include /* compression headers */ #else diff --git a/bacula/src/filed/filed_conf.c b/bacula/src/filed/filed_conf.c index 319eef943f..aaa3b33707 100644 --- a/bacula/src/filed/filed_conf.c +++ b/bacula/src/filed/filed_conf.c @@ -105,6 +105,7 @@ static RES_ITEM dir_items[] = { {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0}, {"address", store_str, ITEM(res_dir.address), 0, 0, 0}, {"enablessl", store_yesno, ITEM(res_dir.enable_ssl),1, ITEM_DEFAULT, 0}, + {"monitor", store_yesno, ITEM(res_dir.monitor), 1, ITEM_DEFAULT, 0}, {NULL, NULL, NULL, 0, 0, 0} }; diff --git a/bacula/src/filed/filed_conf.h b/bacula/src/filed/filed_conf.h index ce1f4a8c84..f1d9fa5210 100644 --- a/bacula/src/filed/filed_conf.h +++ b/bacula/src/filed/filed_conf.h @@ -51,6 +51,7 @@ struct DIRRES { char *password; /* Director password */ char *address; /* Director address or zero */ int enable_ssl; /* Use SSL for this Director */ + int monitor; /* Have only access to status and .status functions */ }; struct CLIENT { diff --git a/bacula/src/filed/job.c b/bacula/src/filed/job.c index 86bdfab4bc..d9a43a7659 100644 --- a/bacula/src/filed/job.c +++ b/bacula/src/filed/job.c @@ -67,31 +67,32 @@ static void set_options(findFOPTS *fo, const char *opts); struct s_cmds { const char *cmd; int (*func)(JCR *); + int monitoraccess; /* specify if monitors have access to this function */ }; /* * The following are the recognized commands from the Director. */ static struct s_cmds cmds[] = { - {"backup", backup_cmd}, - {"cancel", cancel_cmd}, - {"setdebug=", setdebug_cmd}, - {"estimate", estimate_cmd}, - {"exclude", exclude_cmd}, - {"Hello", hello_cmd}, - {"include", include_cmd}, - {"fileset", fileset_cmd}, - {"JobId=", job_cmd}, - {"level = ", level_cmd}, - {"restore", restore_cmd}, - {"session", session_cmd}, - {"status", status_cmd}, - {".status", qstatus_cmd}, - {"storage ", storage_cmd}, - {"verify", verify_cmd}, - {"bootstrap", bootstrap_cmd}, - {"RunBeforeJob", runbefore_cmd}, - {"RunAfterJob", runafter_cmd}, + {"backup", backup_cmd, 0}, + {"cancel", cancel_cmd, 0}, + {"setdebug=", setdebug_cmd, 0}, + {"estimate", estimate_cmd, 0}, + {"exclude", exclude_cmd, 0}, + {"Hello", hello_cmd, 1}, + {"include", include_cmd, 0}, + {"fileset", fileset_cmd, 0}, + {"JobId=", job_cmd, 0}, + {"level = ", level_cmd, 0}, + {"restore", restore_cmd, 0}, + {"session", session_cmd, 0}, + {"status", status_cmd, 1}, + {".status", qstatus_cmd, 1}, + {"storage ", storage_cmd, 0}, + {"verify", verify_cmd, 0}, + {"bootstrap", bootstrap_cmd, 0}, + {"RunBeforeJob", runbefore_cmd, 0}, + {"RunAfterJob", runafter_cmd, 0}, {NULL, NULL} /* list terminator */ }; @@ -109,6 +110,7 @@ static char runafter[] = "RunAfterJob %s\n"; /* Responses sent to Director */ static char errmsg[] = "2999 Invalid command\n"; static char no_auth[] = "2998 No Authorization\n"; +static char illegal_cmd[] = "2997 Illegal command for a Director with Monitor directive enabled\n"; static char OKinc[] = "2000 OK include\n"; static char OKest[] = "2000 OK estimate files=%u bytes=%s\n"; static char OKexc[] = "2000 OK exclude\n"; @@ -185,30 +187,37 @@ void *handle_client_request(void *dirp) /* Read command */ if (bnet_recv(dir) < 0) { - break; /* connection terminated */ + break; /* connection terminated */ } dir->msg[dir->msglen] = 0; Dmsg1(100, "msg); found = false; for (i=0; cmds[i].cmd; i++) { - if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) { - if (!jcr->authenticated && cmds[i].func != hello_cmd) { - bnet_fsend(dir, no_auth); - break; - } - found = true; /* indicate command found */ + if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) { + found = true; /* indicate command found */ + if (!jcr->authenticated && cmds[i].func != hello_cmd) { + bnet_fsend(dir, no_auth); + bnet_sig(dir, BNET_EOD); + break; + } + if ((jcr->authenticated) && (!cmds[i].monitoraccess) && (jcr->director->monitor)) { + Dmsg1(100, "Command %s illegal.\n", cmds[i].cmd); + bnet_fsend(dir, illegal_cmd); + bnet_sig(dir, BNET_EOD); + break; + } Dmsg1(100, "Executing %s command.\n", cmds[i].cmd); - if (!cmds[i].func(jcr)) { /* do command */ - quit = true; /* error or fully terminated, get out */ + if (!cmds[i].func(jcr)) { /* do command */ + quit = true; /* error or fully terminated, get out */ Dmsg0(20, "Quit command loop due to command error or Job done.\n"); - } - break; - } + } + break; + } } - if (!found) { /* command not found */ - bnet_fsend(dir, errmsg); - quit = true; - break; + if (!found) { /* command not found */ + bnet_fsend(dir, errmsg); + quit = true; + break; } } diff --git a/bacula/src/jcr.h b/bacula/src/jcr.h index 9b267a4235..7c142ddd86 100644 --- a/bacula/src/jcr.h +++ b/bacula/src/jcr.h @@ -206,6 +206,7 @@ struct JCR { pthread_t heartbeat_id; /* id of heartbeat thread */ volatile BSOCK *hb_bsock; /* duped SD socket */ POOLMEM *RunAfterJob; /* Command to run after job */ + DIRRES* director; /* Director resource */ #endif /* FILE_DAEMON */ @@ -237,7 +238,8 @@ struct JCR { bool no_attributes; /* set if no attributes wanted */ bool spool_data; /* set to spool data */ int CurVol; /* Current Volume count */ - + DIRRES* director; /* Director resource */ + uint32_t FileId; /* Last file id inserted */ /* Parmaters for Open Read Session */ diff --git a/bacula/src/stored/authenticate.c b/bacula/src/stored/authenticate.c index 2cd2110c5b..bf8f0f4516 100644 --- a/bacula/src/stored/authenticate.c +++ b/bacula/src/stored/authenticate.c @@ -37,7 +37,7 @@ static char OK_hello[] = "3000 OK Hello\n"; * * */ -static int authenticate(int rcode, BSOCK *bs) +static int authenticate(int rcode, BSOCK *bs, JCR* jcr) { POOLMEM *dirname; DIRRES *director = NULL; @@ -89,6 +89,7 @@ static int authenticate(int rcode, BSOCK *bs) } stop_bsock_timer(tid); free_pool_memory(dirname); + jcr->director = director; return 1; } @@ -108,7 +109,7 @@ int authenticate_director(JCR *jcr) { BSOCK *dir = jcr->dir_bsock; - if (!authenticate(R_DIRECTOR, dir)) { + if (!authenticate(R_DIRECTOR, dir, jcr)) { bnet_fsend(dir, "%s", Dir_sorry); Emsg1(M_ERROR, 0, _("Unable to authenticate Director at %s.\n"), dir->who); bmicrosleep(5, 0); diff --git a/bacula/src/stored/bacula-sd.conf.in b/bacula/src/stored/bacula-sd.conf.in index 1b58851c65..43482b447e 100644 --- a/bacula/src/stored/bacula-sd.conf.in +++ b/bacula/src/stored/bacula-sd.conf.in @@ -26,6 +26,16 @@ Director { Password = "@sd_password@" } +# +# Restricted Director, used by tray-monitor to get the +# status of the storage daemon +# +Director { + Name = @hostname@-mon + Password = "@mon_sd_password@" + Monitor = yes +} + # # Devices supported by this Storage daemon # To connect, the Director's bacula-dir.conf must have the diff --git a/bacula/src/stored/dircmd.c b/bacula/src/stored/dircmd.c index 40c43f1648..500c8485cd 100644 --- a/bacula/src/stored/dircmd.c +++ b/bacula/src/stored/dircmd.c @@ -54,7 +54,7 @@ extern struct s_last_job last_job; /* Static variables */ static char derrmsg[] = "3900 Invalid command\n"; static char OKsetdebug[] = "3000 OK setdebug=%d\n"; - +static char illegal_cmd[] = "3997 Illegal command for a Director with Monitor directive enabled\n"; /* Imported functions */ extern void terminate_child(); @@ -82,25 +82,26 @@ static void label_volume_if_ok(JCR *jcr, DEVICE *dev, char *oldname, struct s_cmds { const char *cmd; int (*func)(JCR *jcr); + int monitoraccess; /* specify if monitors have access to this function */ }; /* * The following are the recognized commands from the Director. */ static struct s_cmds cmds[] = { - {"JobId=", job_cmd}, /* start Job */ - {"setdebug=", setdebug_cmd}, /* set debug level */ - {"cancel", cancel_cmd}, - {"label", label_cmd}, /* label a tape */ - {"relabel", relabel_cmd}, /* relabel a tape */ - {"mount", mount_cmd}, - {"unmount", unmount_cmd}, - {"status", status_cmd}, - {".status", qstatus_cmd}, - {"autochanger", autochanger_cmd}, - {"release", release_cmd}, - {"readlabel", readlabel_cmd}, - {NULL, NULL} /* list terminator */ + {"JobId=", job_cmd, 0}, /* start Job */ + {"setdebug=", setdebug_cmd, 0}, /* set debug level */ + {"cancel", cancel_cmd, 0}, + {"label", label_cmd, 0}, /* label a tape */ + {"relabel", relabel_cmd, 0}, /* relabel a tape */ + {"mount", mount_cmd, 0}, + {"unmount", unmount_cmd, 0}, + {"status", status_cmd, 1}, + {".status", qstatus_cmd, 1}, + {"autochanger", autochanger_cmd, 0}, + {"release", release_cmd, 0}, + {"readlabel", readlabel_cmd, 0}, + {NULL, NULL} /* list terminator */ }; @@ -180,24 +181,30 @@ void *handle_connection_request(void *arg) for (quit=0; !quit;) { /* Read command */ if ((bnet_stat = bnet_recv(bs)) <= 0) { - break; /* connection terminated */ + break; /* connection terminated */ } Dmsg1(9, "msg); found = false; for (i=0; cmds[i].cmd; i++) { - if (strncmp(cmds[i].cmd, bs->msg, strlen(cmds[i].cmd)) == 0) { - if (!cmds[i].func(jcr)) { /* do command */ - quit = true; /* error, get out */ - Dmsg1(90, "Command %s requsts quit\n", cmds[i].cmd); - } - found = true; /* indicate command found */ - break; - } + if (strncmp(cmds[i].cmd, bs->msg, strlen(cmds[i].cmd)) == 0) { + if ((!cmds[i].monitoraccess) && (jcr->director->monitor)) { + Dmsg1(100, "Command %s illegal.\n", cmds[i].cmd); + bnet_fsend(bs, illegal_cmd); + bnet_sig(bs, BNET_EOD); + break; + } + if (!cmds[i].func(jcr)) { /* do command */ + quit = true; /* error, get out */ + Dmsg1(90, "Command %s requsts quit\n", cmds[i].cmd); + } + found = true; /* indicate command found */ + break; + } } if (!found) { /* command not found */ - bnet_fsend(bs, derrmsg); - quit = true; - break; + bnet_fsend(bs, derrmsg); + quit = true; + break; } } bnet_sig(bs, BNET_TERMINATE); diff --git a/bacula/src/stored/stored_conf.c b/bacula/src/stored/stored_conf.c index 2e51bb2003..25edf24b74 100644 --- a/bacula/src/stored/stored_conf.c +++ b/bacula/src/stored/stored_conf.c @@ -76,6 +76,7 @@ static RES_ITEM dir_items[] = { {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0}, {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0}, {"enablessl", store_yesno, ITEM(res_dir.enable_ssl), 1, ITEM_DEFAULT, 0}, + {"monitor", store_yesno, ITEM(res_dir.monitor), 1, ITEM_DEFAULT, 0}, {NULL, NULL, 0, 0, 0, 0} }; diff --git a/bacula/src/stored/stored_conf.h b/bacula/src/stored/stored_conf.h index d2bef94658..457dce7335 100644 --- a/bacula/src/stored/stored_conf.h +++ b/bacula/src/stored/stored_conf.h @@ -45,9 +45,10 @@ enum { struct DIRRES { RES hdr; - char *password; /* Director password */ - char *address; /* Director IP address or zero */ - int enable_ssl; /* Use SSL with this Director */ + char *password; /* Director password */ + char *address; /* Director IP address or zero */ + int enable_ssl; /* Use SSL with this Director */ + int monitor; /* Have only access to status and .status functions */ }; diff --git a/bacula/src/tray-monitor/tray-monitor.c b/bacula/src/tray-monitor/tray-monitor.c index a89c10d906..6241ebe760 100644 --- a/bacula/src/tray-monitor/tray-monitor.c +++ b/bacula/src/tray-monitor/tray-monitor.c @@ -71,7 +71,6 @@ void changeStatus(monitoritem* item, stateenum status); void changeStatusMessage(monitoritem* item, const char *fmt,...); /* Callbacks */ -static void TrayIconDaemonChanged(GtkWidget *widget, monitoritem* data); static void TrayIconActivate(GtkWidget *widget, gpointer data); static void TrayIconExit(unsigned int activateTime, unsigned int button); static void TrayIconPopupMenu(unsigned int button, unsigned int activateTime); @@ -592,9 +591,9 @@ int docmd(monitoritem* item, const char* command, GSList** list) { str = g_string_sized_new(64); g_string_printf(str, "ERR=%s\n", item->D_sock->msg); g_slist_append(*list, str); - item->D_sock = NULL; changeStatus(NULL, error); changeStatusMessage(item, "Authentication error : %s", item->D_sock->msg); + item->D_sock = NULL; return 0; } diff --git a/bacula/src/tray-monitor/tray-monitor.conf.in b/bacula/src/tray-monitor/tray-monitor.conf.in index bbeccaf3c3..3c451666f2 100644 --- a/bacula/src/tray-monitor/tray-monitor.conf.in +++ b/bacula/src/tray-monitor/tray-monitor.conf.in @@ -3,19 +3,27 @@ # Monitor { - Name = @hostname@-dir + Name = @hostname@-mon } Client { Name = @hostname@-fd Address = @hostname@ FDPort = @fd_port@ - Password = "@fd_password@" # password for FileDaemon + Password = "@mon_fd_password@" # password for FileDaemon } Storage { Name = @hostname@-sd Address = @hostname@ SDPort = @sd_port@ - Password = "@sd_password@" # password for StorageDaemon + Password = "@mon_sd_password@" # password for StorageDaemon +} + +Director { + ConsoleName = Monitor + Name = @hostname@-dir + DIRport = @dir_port@ + address = @hostname@ + Password = "@mon_dir_password@" # password for Director } \ No newline at end of file -- 2.39.5