]> granicus.if.org Git - icinga2/blob - lib/icinga/usergroup.cpp
Fix "assign where" for nested groups
[icinga2] / lib / icinga / usergroup.cpp
1 /******************************************************************************
2  * Icinga 2                                                                   *
3  * Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org)    *
4  *                                                                            *
5  * This program is free software; you can redistribute it and/or              *
6  * modify it under the terms of the GNU General Public License                *
7  * as published by the Free Software Foundation; either version 2             *
8  * of the License, or (at your option) any later version.                     *
9  *                                                                            *
10  * This program is distributed in the hope that it will be useful,            *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
13  * GNU General Public License for more details.                               *
14  *                                                                            *
15  * You should have received a copy of the GNU General Public License          *
16  * along with this program; if not, write to the Free Software Foundation     *
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.             *
18  ******************************************************************************/
19
20 #include "icinga/usergroup.hpp"
21 #include "config/objectrule.hpp"
22 #include "base/dynamictype.hpp"
23 #include "base/objectlock.hpp"
24 #include "base/logger.hpp"
25 #include "base/context.hpp"
26 #include "base/workqueue.hpp"
27 #include <boost/foreach.hpp>
28
29 using namespace icinga;
30
31 REGISTER_TYPE(UserGroup);
32
33 INITIALIZE_ONCE(&UserGroup::RegisterObjectRuleHandler);
34
35 void UserGroup::RegisterObjectRuleHandler(void)
36 {
37         ObjectRule::RegisterType("UserGroup", &UserGroup::EvaluateObjectRules);
38 }
39
40 bool UserGroup::EvaluateObjectRuleOne(const User::Ptr& user, const ObjectRule& rule)
41 {
42         DebugInfo di = rule.GetDebugInfo();
43
44         std::ostringstream msgbuf;
45         msgbuf << "Evaluating 'object' rule (" << di << ")";
46         CONTEXT(msgbuf.str());
47
48         Dictionary::Ptr locals = make_shared<Dictionary>();
49         locals->Set("user", user);
50
51         if (!rule.EvaluateFilter(locals))
52                 return false;
53
54         Log(LogDebug, "UserGroup")
55             << "Assigning membership for group '" << rule.GetName() << "' to user '" << user->GetName() << "' for rule " << di;
56
57         String group_name = rule.GetName();
58         UserGroup::Ptr group = UserGroup::GetByName(group_name);
59
60         if (!group) {
61                 Log(LogCritical, "UserGroup")
62                     << "Invalid membership assignment. Group '" << group_name << "' does not exist.";
63                 return false;
64         }
65
66         /* assign user group membership */
67         group->ResolveGroupMembership(user, true);
68
69         return true;
70 }
71
72 void UserGroup::EvaluateObjectRule(const ObjectRule& rule)
73 {
74         BOOST_FOREACH(const User::Ptr& user, DynamicType::GetObjectsByType<User>()) {
75                 CONTEXT("Evaluating group membership in '" + rule.GetName() + "' for user '" + user->GetName() + "'");
76
77                 EvaluateObjectRuleOne(user, rule);
78         }
79 }
80
81 void UserGroup::EvaluateObjectRules(const std::vector<ObjectRule>& rules)
82 {
83         ParallelWorkQueue upq;
84
85         BOOST_FOREACH(const ObjectRule& rule, rules) {
86                 upq.Enqueue(boost::bind(UserGroup::EvaluateObjectRule, boost::cref(rule)));
87         }
88
89         upq.Join();
90 }
91
92 std::set<User::Ptr> UserGroup::GetMembers(void) const
93 {
94         boost::mutex::scoped_lock lock(m_UserGroupMutex);
95         return m_Members;
96 }
97
98 void UserGroup::AddMember(const User::Ptr& user)
99 {
100         user->AddGroup(GetName());
101
102         boost::mutex::scoped_lock lock(m_UserGroupMutex);
103         m_Members.insert(user);
104 }
105
106 void UserGroup::RemoveMember(const User::Ptr& user)
107 {
108         boost::mutex::scoped_lock lock(m_UserGroupMutex);
109         m_Members.erase(user);
110 }
111
112 bool UserGroup::ResolveGroupMembership(const User::Ptr& user, bool add, int rstack) {
113
114         if (add && rstack > 20) {
115                 Log(LogWarning, "UserGroup")
116                     << "Too many nested groups for group '" << GetName() << "': User '"
117                     << user->GetName() << "' membership assignment failed.";
118
119                 return false;
120         }
121
122         Array::Ptr groups = GetGroups();
123
124         if (groups && groups->GetLength() > 0) {
125                 ObjectLock olock(groups);
126
127                 BOOST_FOREACH(const String& name, groups) {
128                         UserGroup::Ptr group = UserGroup::GetByName(name);
129
130                         if (group && !group->ResolveGroupMembership(user, add, rstack + 1))
131                                 return false;
132                 }
133         }
134
135         if (add)
136                 AddMember(user);
137         else
138                 RemoveMember(user);
139
140         return true;
141 }
142