diff --git a/core/src/dird/authenticate_console.cc b/core/src/dird/authenticate_console.cc index 44e092813b2..eca22ba6211 100644 --- a/core/src/dird/authenticate_console.cc +++ b/core/src/dird/authenticate_console.cc @@ -83,7 +83,7 @@ OptionResult ConsoleAuthenticator::DoDefaultAuthentication() auth_success_ = ua_->UA_sock->AuthenticateInboundConnection( NULL, my_config, default_console_name.c_str(), me->password_, me); - ua_->cons = nullptr; + ua_->user_acl = nullptr; return OptionResult::Completed; } @@ -100,9 +100,9 @@ void ConsoleAuthenticator::DoNamedAuthentication() NULL, my_config, console_name_.c_str(), optional_console_resource_->password_, optional_console_resource_); if (auth_success_) { - ua_->cons = optional_console_resource_; + ua_->user_acl = &optional_console_resource_->user_acl; } else { - ua_->cons = nullptr; + ua_->user_acl = nullptr; Dmsg1(200, "Could not authenticate console %s\n", console_name_.c_str()); } } @@ -220,9 +220,9 @@ bool ConsoleAuthenticatorFrom_18_2::SendInfoMessage() message += BAREOS_SERVICES_MESSAGE; message += "\n"; message += "You are "; - if (ua_->cons) { + if (ua_->user_acl) { message += "logged in as: "; - message += ua_->cons->resource_name_; + message += ua_->user_acl->corresponding_resource->resource_name_; } else { message += "connected using the default console"; } @@ -325,18 +325,18 @@ OptionResult ConsoleAuthenticatorFrom_18_2::AuthenticatePamUser() std::string authenticated_username; if (!PamAuthenticateUser(ua_->UA_sock, pam_username, pam_password, authenticated_username)) { - ua_->cons = nullptr; + ua_->user_acl = nullptr; auth_success_ = false; } else { - ConsoleResource* user = (ConsoleResource*)my_config->GetResWithName( - R_CONSOLE, authenticated_username.c_str()); + UserResource* user = (UserResource*)my_config->GetResWithName( + R_USER, authenticated_username.c_str()); if (!user) { Dmsg1(200, "No user config found for user %s\n", authenticated_username.c_str()); - ua_->cons = nullptr; + ua_->user_acl = nullptr; auth_success_ = false; } else { - ua_->cons = user; + ua_->user_acl = &user->user_acl; auth_success_ = true; } } diff --git a/core/src/dird/dird_conf.cc b/core/src/dird/dird_conf.cc index e1a7d764883..7ed2443aa01 100644 --- a/core/src/dird/dird_conf.cc +++ b/core/src/dird/dird_conf.cc @@ -105,6 +105,7 @@ static PoolResource* res_pool; static MessagesResource* res_msgs; static CounterResource* res_counter; static DeviceResource* res_dev; +static UserResource* res_user; /* clang-format off */ @@ -186,24 +187,28 @@ static ResourceItem profile_items[] = { {nullptr, 0, 0, nullptr, 0, 0, nullptr, nullptr, nullptr} }; +#define USER_ACL(resource) \ + { "JobACL", CFG_TYPE_ACL, ITEM(resource, user_acl.ACL_lists), Job_ACL, 0, NULL, NULL, NULL },\ + { "ClientACL", CFG_TYPE_ACL, ITEM(resource, user_acl.ACL_lists), Client_ACL, 0, NULL, NULL, NULL },\ + { "StorageACL", CFG_TYPE_ACL, ITEM(resource, user_acl.ACL_lists), Storage_ACL, 0, NULL, NULL, NULL },\ + { "ScheduleACL", CFG_TYPE_ACL, ITEM(resource, user_acl.ACL_lists), Schedule_ACL, 0, NULL, NULL, NULL },\ + { "RunACL", CFG_TYPE_ACL, ITEM(resource, user_acl.ACL_lists), Run_ACL, 0, NULL, NULL, NULL },\ + { "PoolACL", CFG_TYPE_ACL, ITEM(resource, user_acl.ACL_lists), Pool_ACL, 0, NULL, NULL, NULL },\ + { "CommandACL", CFG_TYPE_ACL, ITEM(resource, user_acl.ACL_lists), Command_ACL, 0, NULL, NULL, NULL },\ + { "FileSetACL", CFG_TYPE_ACL, ITEM(resource, user_acl.ACL_lists), FileSet_ACL, 0, NULL, NULL, NULL },\ + { "CatalogACL", CFG_TYPE_ACL, ITEM(resource, user_acl.ACL_lists), Catalog_ACL, 0, NULL, NULL, NULL },\ + { "WhereACL", CFG_TYPE_ACL, ITEM(resource, user_acl.ACL_lists), Where_ACL, 0, NULL, NULL, NULL },\ + { "PluginOptionsACL", CFG_TYPE_ACL, ITEM(resource, user_acl.ACL_lists), PluginOptions_ACL, 0, NULL, NULL, NULL },\ + { "Profile", CFG_TYPE_ALIST_RES, ITEM(resource, user_acl.profiles), R_PROFILE, 0, NULL, "14.2.3-",\ + "Profiles can be assigned to a Console. ACL are checked until either a deny ACL is found or an allow ACL. "\ + "First the console ACL is checked then any profile the console is linked to." } + + static ResourceItem con_items[] = { { "Name", CFG_TYPE_NAME, ITEM(res_con, resource_name_), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL }, { "Description", CFG_TYPE_STR, ITEM(res_con, description_), 0, 0, NULL, NULL, NULL }, { "Password", CFG_TYPE_AUTOPASSWORD, ITEM(res_con, password_), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL }, - { "JobACL", CFG_TYPE_ACL, ITEM(res_con, ACL_lists), Job_ACL, 0, NULL, NULL, NULL }, - { "ClientACL", CFG_TYPE_ACL, ITEM(res_con, ACL_lists), Client_ACL, 0, NULL, NULL, NULL }, - { "StorageACL", CFG_TYPE_ACL, ITEM(res_con, ACL_lists), Storage_ACL, 0, NULL, NULL, NULL }, - { "ScheduleACL", CFG_TYPE_ACL, ITEM(res_con, ACL_lists), Schedule_ACL, 0, NULL, NULL, NULL }, - { "RunACL", CFG_TYPE_ACL, ITEM(res_con, ACL_lists), Run_ACL, 0, NULL, NULL, NULL }, - { "PoolACL", CFG_TYPE_ACL, ITEM(res_con, ACL_lists), Pool_ACL, 0, NULL, NULL, NULL }, - { "CommandACL", CFG_TYPE_ACL, ITEM(res_con, ACL_lists), Command_ACL, 0, NULL, NULL, NULL }, - { "FileSetACL", CFG_TYPE_ACL, ITEM(res_con, ACL_lists), FileSet_ACL, 0, NULL, NULL, NULL }, - { "CatalogACL", CFG_TYPE_ACL, ITEM(res_con, ACL_lists), Catalog_ACL, 0, NULL, NULL, NULL }, - { "WhereACL", CFG_TYPE_ACL, ITEM(res_con, ACL_lists), Where_ACL, 0, NULL, NULL, NULL }, - { "PluginOptionsACL", CFG_TYPE_ACL, ITEM(res_con, ACL_lists), PluginOptions_ACL, 0, NULL, NULL, NULL }, - { "Profile", CFG_TYPE_ALIST_RES, ITEM(res_con, profiles), R_PROFILE, 0, NULL, "14.2.3-", - "Profiles can be assigned to a Console. ACL are checked until either a deny ACL is found or an allow ACL. " - "First the console ACL is checked then any profile the console is linked to." }, + USER_ACL(res_con), { "UsePamAuthentication", CFG_TYPE_BOOL, ITEM(res_con, use_pam_authentication_), 0, CFG_ITEM_DEFAULT, "false", "18.2.4-", NULL }, TLS_COMMON_CONFIG(res_con), @@ -211,6 +216,13 @@ static ResourceItem con_items[] = { {nullptr, 0, 0, nullptr, 0, 0, nullptr, nullptr, nullptr} }; +static ResourceItem user_items[] = { + { "Name", CFG_TYPE_NAME, ITEM(res_user, resource_name_), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL }, + { "Description", CFG_TYPE_STR, ITEM(res_user, description_), 0, 0, NULL, NULL, NULL }, + USER_ACL(res_user), + {nullptr, 0, 0, nullptr, 0, 0, nullptr, nullptr, nullptr} +}; + static ResourceItem cli_items[] = { { "Name", CFG_TYPE_NAME, ITEM(res_client, resource_name_), 0, CFG_ITEM_REQUIRED, NULL, NULL, "The name of the resource." }, @@ -548,10 +560,10 @@ static ResourceTable resources[] = { [] (){ res_profile = new ProfileResource(); }, reinterpret_cast(&res_profile) }, { "Console", con_items, R_CONSOLE, sizeof(ConsoleResource), [] (){ res_con = new ConsoleResource(); }, reinterpret_cast(&res_con) }, - { "User", con_items, R_CONSOLE, sizeof(ConsoleResource), - [] (){ res_con = new ConsoleResource(); }, reinterpret_cast(&res_con) }, { "Device", NULL, R_DEVICE, sizeof(DeviceResource), [] (){ res_dev = new DeviceResource(); }, reinterpret_cast(&res_dev) },/* info obtained from SD */ + { "User", user_items, R_USER, sizeof(UserResource), + [] (){ res_user = new UserResource(); }, reinterpret_cast(&res_user) }, {nullptr, nullptr, 0, 0, nullptr, nullptr} }; @@ -2380,7 +2392,21 @@ static bool UpdateResourcePointer(int type, ResourceItem* items) } else { p->tls_cert_.allowed_certificate_common_names_ = std::move(res_con->tls_cert_.allowed_certificate_common_names_); - p->profiles = res_con->profiles; + p->user_acl.profiles = res_con->user_acl.profiles; + p->user_acl.corresponding_resource = p; + } + break; + } + case R_USER: { + UserResource* p = dynamic_cast( + my_config->GetResWithName(R_USER, res_user->resource_name_)); + if (!p) { + Emsg1(M_ERROR, 0, _("Cannot find User resource %s\n"), + res_user->resource_name_); + return false; + } else { + p->user_acl.profiles = res_user->user_acl.profiles; + p->user_acl.corresponding_resource = p; } break; } @@ -3703,7 +3729,8 @@ static void ConfigBeforeCallback(ConfigurationParser& my_config) {R_SCHEDULE, "R_SCHEDULE"}, {R_FILESET, "R_FILESET"}, {R_POOL, "R_POOL"}, {R_MSGS, "R_MSGS"}, {R_COUNTER, "R_COUNTER"}, {R_PROFILE, "R_PROFILE"}, - {R_CONSOLE, "R_CONSOLE"}, {R_DEVICE, "R_DEVICE"}}; + {R_CONSOLE, "R_CONSOLE"}, {R_DEVICE, "R_DEVICE"}, + {R_USER, "R_USER"}}; my_config.InitializeQualifiedResourceNameTypeConverter(map); } @@ -3768,6 +3795,10 @@ static bool AddResourceCopyToEndOfChain(int type, new_resource = res_con; res_con = nullptr; break; + case R_USER: + new_resource = res_user; + res_user = nullptr; + break; case R_DEVICE: new_resource = res_dev; res_dev = nullptr; @@ -3847,6 +3878,7 @@ static void DumpResource(int type, case R_DIRECTOR: case R_PROFILE: case R_CONSOLE: + case R_USER: case R_COUNTER: case R_CLIENT: case R_DEVICE: @@ -3950,11 +3982,26 @@ static void FreeResource(BareosResource* res, int type) ConsoleResource* p = dynamic_cast(res); assert(p); if (p->password_.value) { free(p->password_.value); } - if (p->profiles) { delete p->profiles; } + if (p->user_acl.profiles) { delete p->user_acl.profiles; } for (int i = 0; i < Num_ACL; i++) { - if (p->ACL_lists[i]) { - delete p->ACL_lists[i]; - p->ACL_lists[i] = NULL; + if (p->user_acl.ACL_lists[i]) { + delete p->user_acl.ACL_lists[i]; + p->user_acl.corresponding_resource = nullptr; + p->user_acl.ACL_lists[i] = NULL; + } + } + delete p; + break; + } + case R_USER: { + UserResource* p = dynamic_cast(res); + assert(p); + if (p->user_acl.profiles) { delete p->user_acl.profiles; } + for (int i = 0; i < Num_ACL; i++) { + if (p->user_acl.ACL_lists[i]) { + delete p->user_acl.ACL_lists[i]; + p->user_acl.corresponding_resource = nullptr; + p->user_acl.ACL_lists[i] = NULL; } } delete p; diff --git a/core/src/dird/dird_conf.h b/core/src/dird/dird_conf.h index be21d5fa582..c0805ab2665 100644 --- a/core/src/dird/dird_conf.h +++ b/core/src/dird/dird_conf.h @@ -62,8 +62,9 @@ enum R_PROFILE, R_CONSOLE, R_DEVICE, + R_USER, R_FIRST = R_DIRECTOR, - R_LAST = R_DEVICE /* keep this updated */ + R_LAST = R_USER /* keep this updated */ }; /** @@ -225,6 +226,12 @@ class ProfileResource : public BareosResource { alist* ACL_lists[Num_ACL] = {0}; /**< Pointers to ACLs */ }; +struct UserAcl { + BareosResource* corresponding_resource = nullptr; + alist* ACL_lists[Num_ACL] = {0}; /**< Pointers to ACLs */ + alist* profiles = nullptr; /**< Pointers to profile resources */ +}; + /** * Console Resource */ @@ -234,12 +241,17 @@ class ConsoleResource public: ConsoleResource() = default; virtual ~ConsoleResource() = default; - - alist* ACL_lists[Num_ACL] = {0}; /**< Pointers to ACLs */ - alist* profiles = nullptr; /**< Pointers to profile resources */ + UserAcl user_acl; bool use_pam_authentication_ = false; /**< PAM Console */ }; +class UserResource : public BareosResource { + public: + UserResource() = default; + virtual ~UserResource() = default; + UserAcl user_acl; +}; + /** * Catalog Resource */ diff --git a/core/src/dird/ua.cc b/core/src/dird/ua.cc index af6ed0df4ae..d9818f8af06 100644 --- a/core/src/dird/ua.cc +++ b/core/src/dird/ua.cc @@ -35,7 +35,7 @@ UaContext::UaContext() , shared_db(nullptr) , private_db(nullptr) , catalog(nullptr) - , cons(nullptr) + , user_acl(nullptr) , cmd(nullptr) , args(nullptr) , errmsg(nullptr) diff --git a/core/src/dird/ua.h b/core/src/dird/ua.h index a7641687e5a..ae48e288cac 100644 --- a/core/src/dird/ua.h +++ b/core/src/dird/ua.h @@ -53,6 +53,7 @@ class ScheduleResource; struct RestoreBootstrapRecord; struct ua_cmdstruct; class UnifiedStorageResource; +struct UserAcl; class UaContext { public: @@ -63,7 +64,7 @@ class UaContext { BareosDb* shared_db; /**< Shared database connection used by multiple ua's */ BareosDb* private_db; /**< Private database connection only used by this ua */ CatalogResource* catalog; - ConsoleResource* cons; /**< Console resource */ + UserAcl* user_acl; /**< acl from console or user resource */ POOLMEM* cmd; /**< Return command/name buffer */ POOLMEM* args; /**< Command line arguments */ POOLMEM* errmsg; /**< Store error message */ diff --git a/core/src/dird/ua_acl.cc b/core/src/dird/ua_acl.cc index f08c75392f0..40881ee10d4 100644 --- a/core/src/dird/ua_acl.cc +++ b/core/src/dird/ua_acl.cc @@ -248,22 +248,22 @@ bool UaContext::AclAccessOk(int acl, /* * If no console resource => default console and all is permitted */ - if (!cons) { - Dmsg0(1400, "Root cons access OK.\n"); + if (!user_acl) { + Dmsg0(1400, "Root user access OK.\n"); retval = true; goto bail_out; } - retval = FindInAclList(cons->ACL_lists[acl], acl, item, len); + retval = FindInAclList(user_acl->ACL_lists[acl], acl, item, len); /* * If we didn't find a matching ACL try to use the profiles this console is * connected to. */ - if (!retval && cons->profiles && cons->profiles->size()) { + if (!retval && user_acl->profiles && user_acl->profiles->size()) { ProfileResource* profile = nullptr; - foreach_alist (profile, cons->profiles) { + foreach_alist (profile, user_acl->profiles) { retval = FindInAclList(profile->ACL_lists[acl], acl, item, len); /* @@ -291,11 +291,11 @@ bool UaContext::AclNoRestrictions(int acl) /* * If no console resource => default console and all is permitted */ - if (!cons) { return true; } + if (!user_acl) { return true; } - if (cons->ACL_lists[acl]) { - for (int i = 0; i < cons->ACL_lists[acl]->size(); i++) { - list_value = (char*)cons->ACL_lists[acl]->get(i); + if (user_acl->ACL_lists[acl]) { + for (int i = 0; i < user_acl->ACL_lists[acl]->size(); i++) { + list_value = (char*)user_acl->ACL_lists[acl]->get(i); if (*list_value == '!') { return false; } @@ -303,7 +303,7 @@ bool UaContext::AclNoRestrictions(int acl) } } - foreach_alist (profile, cons->profiles) { + foreach_alist (profile, user_acl->profiles) { if (profile) { if (profile->ACL_lists[acl]) { for (int i = 0; i < profile->ACL_lists[acl]->size(); i++) { diff --git a/core/src/dird/ua_audit.cc b/core/src/dird/ua_audit.cc index 1f98af69087..b236ab40975 100644 --- a/core/src/dird/ua_audit.cc +++ b/core/src/dird/ua_audit.cc @@ -61,11 +61,13 @@ static inline void LogAuditEventAclMsg(UaContext* ua, int acl, const char* item) { - const char* console_name; + const char* user_name; const char* host; const char* acl_type_name; - console_name = (ua->cons) ? ua->cons->resource_name_ : "default"; + user_name = (ua->user_acl) + ? ua->user_acl->corresponding_resource->resource_name_ + : "default"; host = (ua->UA_sock) ? ua->UA_sock->host() : "unknown"; switch (acl) { @@ -107,7 +109,7 @@ static inline void LogAuditEventAclMsg(UaContext* ua, break; } - Emsg4(M_AUDIT, 0, audit_msg, console_name, host, acl_type_name, item); + Emsg4(M_AUDIT, 0, audit_msg, user_name, host, acl_type_name, item); } void UaContext::LogAuditEventAclFailure(int acl, const char* item) @@ -131,15 +133,16 @@ void UaContext::LogAuditEventAclSuccess(int acl, const char* item) */ void UaContext::LogAuditEventCmdline() { - const char* console_name; + const char* user_name; const char* host; if (!me->auditing) { return; } - console_name = cons ? cons->resource_name_ : "default"; + user_name = + user_acl ? user_acl->corresponding_resource->resource_name_ : "default"; host = UA_sock ? UA_sock->host() : "unknown"; - Emsg3(M_AUDIT, 0, _("Console [%s] from [%s] cmdline %s\n"), console_name, - host, cmd); + Emsg3(M_AUDIT, 0, _("Console [%s] from [%s] cmdline %s\n"), user_name, host, + cmd); } } /* namespace directordaemon */ diff --git a/core/src/dird/ua_cmds.cc b/core/src/dird/ua_cmds.cc index b4ad5d1fc69..4b1c7a1de91 100644 --- a/core/src/dird/ua_cmds.cc +++ b/core/src/dird/ua_cmds.cc @@ -1054,9 +1054,11 @@ static bool SetipCmd(UaContext* ua, const char* cmd) ClientResource* client; char buf[1024]; - client = ua->GetClientResWithName(ua->cons->resource_name_); + client = ua->GetClientResWithName( + ua->user_acl->corresponding_resource->resource_name_); if (!client) { - ua->ErrorMsg(_("Client \"%s\" not found.\n"), ua->cons->resource_name_); + ua->ErrorMsg(_("Client \"%s\" not found.\n"), + ua->user_acl->corresponding_resource->resource_name_); return false; } @@ -2698,7 +2700,8 @@ static bool wait_cmd(UaContext* ua, const char* cmd) static bool WhoAmICmd(UaContext* ua, const char* cmd) { std::string message; - message = ua->cons ? ua->cons->resource_name_ : "root"; + message = ua->user_acl ? ua->user_acl->corresponding_resource->resource_name_ + : "root"; message += '\n'; return ua->UA_sock->fsend(message.c_str()); } diff --git a/docs/manuals/source/TasksAndConcepts/PAM.rst b/docs/manuals/source/TasksAndConcepts/PAM.rst index b3fa43db2df..ce2808bb500 100644 --- a/docs/manuals/source/TasksAndConcepts/PAM.rst +++ b/docs/manuals/source/TasksAndConcepts/PAM.rst @@ -111,7 +111,6 @@ Users have limited access to commands and jobs. Therefore the appropriate rights User { Name = "a-pam-user" - Password = "" # unsed because authenticated by PAM CommandACL = status, .status JobACL = *all* } diff --git a/systemtests/tests/bconsole-pam/etc/bareos/bareos-dir.d/user/user1.conf b/systemtests/tests/bconsole-pam/etc/bareos/bareos-dir.d/user/user1.conf index 63a221e4512..62dd564d5bd 100644 --- a/systemtests/tests/bconsole-pam/etc/bareos/bareos-dir.d/user/user1.conf +++ b/systemtests/tests/bconsole-pam/etc/bareos/bareos-dir.d/user/user1.conf @@ -1,6 +1,5 @@ User { Name = "user1" - Password = "" # unsed because authenticated by PAM Profile = operator }