diff --git a/src/dird/ua_cmds.c b/src/dird/ua_cmds.c index bb5d18983fd..dea092fcfb6 100644 --- a/src/dird/ua_cmds.c +++ b/src/dird/ua_cmds.c @@ -320,11 +320,15 @@ static struct ua_cmdstruct commands[] = { { NT_("move"), move_cmd, _("Move slots in an autochanger"), NT_("storage= srcslots= dstslots="), true, true }, { NT_("prune"), prune_cmd, _("Prune records from catalog"), - NT_("files | jobs | jobtype= | pool= | client= | volume= | directory= | recursive"), true, true }, + NT_("files [client=] [pool=] [yes] |\n" + "jobs [client=] [pool=] [jobtype=] [yes] |\n" + "volume [=volume] [pool=] [yes] |\n" + "stats [yes] |\n" + "directory [=directory] [client=] [recursive] [yes]"), true, true }, { NT_("purge"), purge_cmd, _("Purge records from catalog"), NT_("[files [job= | jobid= | client= | volume=]] |\n" "[jobs [client= | volume=]] |\n" - "[volume [=] [storage=] [pool= | allpools] [devicetype=] [drive=] [action=]] |\n" + "[volume[=] [storage=] [pool= | allpools] [devicetype=] [drive=] [action=]] |\n" "[quota [client=]]"), true, true }, { NT_("quit"), quit_cmd, _("Terminate Bconsole session"), NT_(""), false, false }, diff --git a/src/dird/ua_prune.c b/src/dird/ua_prune.c index d7521bb327a..b2c0dbdbb38 100644 --- a/src/dird/ua_prune.c +++ b/src/dird/ua_prune.c @@ -3,7 +3,7 @@ Copyright (C) 2002-2009 Free Software Foundation Europe e.V. Copyright (C) 2011-2012 Planets Communications B.V. - Copyright (C) 2013-2013 Bareos GmbH & Co. KG + Copyright (C) 2013-2016 Bareos GmbH & Co. KG This program is Free Software; you can redistribute it and/or modify it under the terms of version three of the GNU Affero General Public @@ -90,12 +90,6 @@ int file_delete_handler(void *ctx, int num_fields, char **row) /* * Prune records from database - * - * prune files client=xxx [pool=yyy] - * prune jobs client=xxx [pool=yyy] - * prune volume=xxx - * prune stats - * prune directory=xxx [client=xxx] [recursive] */ bool prune_cmd(UAContext *ua, const char *cmd) { @@ -105,6 +99,7 @@ bool prune_cmd(UAContext *ua, const char *cmd) MEDIA_DBR mr; utime_t retention; int kw; + const char *permission_denied_message = _("Permission denied: need full %s permission.\n"); static const char *keywords[] = { NT_("Files"), NT_("Jobs"), @@ -114,6 +109,21 @@ bool prune_cmd(UAContext *ua, const char *cmd) NULL }; + /* + * All prune commands might target jobs that reside on different storages. + * Instead of checking all of them, + * we require full permission on jobs and storages. + * Client and Pool permissions are checked at the individual subcommands. + */ + if (ua->acl_has_restrictions(Job_ACL)) { + ua->error_msg(permission_denied_message, "job"); + return false; + } + if (ua->acl_has_restrictions(Storage_ACL)) { + ua->error_msg(permission_denied_message, "storage"); + return false; + } + if (!open_client_db(ua, true)) { return false; } @@ -134,11 +144,12 @@ bool prune_cmd(UAContext *ua, const char *cmd) switch (kw) { case 0: /* prune files */ + if (!(client = get_client_resource(ua))) { return false; } - if (find_arg_with_value(ua, NT_("pool")) >= 0) { + if ((find_arg_with_value(ua, NT_("pool")) >= 0) || ua->acl_has_restrictions(Pool_ACL)) { pool = get_pool_resource(ua); } else { pool = NULL; @@ -165,7 +176,7 @@ bool prune_cmd(UAContext *ua, const char *cmd) return false; } - if (find_arg_with_value(ua, NT_("pool")) >= 0) { + if ((find_arg_with_value(ua, NT_("pool")) >= 0) || ua->acl_has_restrictions(Pool_ACL)) { pool = get_pool_resource(ua); } else { pool = NULL; @@ -174,8 +185,15 @@ bool prune_cmd(UAContext *ua, const char *cmd) /* * Ask what jobtype to prune. */ - if (!get_user_job_type_selection(ua, &jobtype) || jobtype == -1) { - return (jobtype == -1) ? true : false; + if (!get_user_job_type_selection(ua, &jobtype)) { + return false; + } + + /* + * Verify that result jobtype is valid (this should always be the case). + */ + if (jobtype < 0) { + return false; } /* @@ -192,6 +210,12 @@ bool prune_cmd(UAContext *ua, const char *cmd) return prune_jobs(ua, client, pool, jobtype); } case 2: /* prune volume */ + + if (ua->acl_has_restrictions(Client_ACL)) { + ua->error_msg(permission_denied_message, "client"); + return false; + } + if (!select_pool_and_media_dbr(ua, &pr, &mr)) { return false; } @@ -213,13 +237,28 @@ bool prune_cmd(UAContext *ua, const char *cmd) retention = me->stats_retention; + if (ua->acl_has_restrictions(Client_ACL)) { + ua->error_msg(permission_denied_message, "client"); + return false; + } + if (ua->acl_has_restrictions(Pool_ACL)) { + ua->error_msg(permission_denied_message, "pool"); + return false; + } + if (!confirm_retention(ua, &retention, "Statistics")) { return false; } return prune_stats(ua, retention); case 4: /* prune directory */ - if (find_arg_with_value(ua, NT_("client")) >= 0) { + + if (ua->acl_has_restrictions(Pool_ACL)) { + ua->error_msg(permission_denied_message, "pool"); + return false; + } + + if ((find_arg_with_value(ua, NT_("client")) >= 0) || ua->acl_has_restrictions(Client_ACL)) { if (!(client = get_client_resource(ua))) { return false; } diff --git a/src/dird/ua_select.c b/src/dird/ua_select.c index 1185c0627ab..fe8b43233a9 100644 --- a/src/dird/ua_select.c +++ b/src/dird/ua_select.c @@ -1827,6 +1827,9 @@ bool get_user_job_type_selection(UAContext *ua, int *jobtype) int i; char job_type[MAX_NAME_LENGTH]; + /* set returning jobtype to invalid */ + *jobtype = -1; + if ((i = find_arg_with_value(ua, NT_("jobtype"))) >= 0) { bstrncpy(job_type, ua->argv[i], sizeof(job_type)); } else { @@ -1836,8 +1839,7 @@ bool get_user_job_type_selection(UAContext *ua, int *jobtype) } if (do_prompt(ua, _("JobType"), _("Select Job Type"), job_type, sizeof(job_type)) < 0) { - *jobtype = -1; - return true; + return false; } }