Line data Source code
1 : /*
2 : SSSD
3 :
4 : Authors:
5 : Stephen Gallagher <sgallagh@redhat.com>
6 :
7 : Copyright (C) 2011 Red Hat
8 :
9 : This program is free software; you can redistribute it and/or modify
10 : it under the terms of the GNU General Public License as published by
11 : the Free Software Foundation; either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program. If not, see <http://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "util/util.h"
24 : #include "providers/ipa/ipa_hbac_private.h"
25 : #include "providers/ldap/sdap_async.h"
26 :
27 : /* Returns EOK and populates groupname if
28 : * the group_dn is actually a group.
29 : * Returns ENOENT if group_dn does not point
30 : * at a a group.
31 : * Returns EINVAL if there is a parsing error.
32 : * Returns ENOMEM as appropriate
33 : */
34 : errno_t
35 0 : get_ipa_groupname(TALLOC_CTX *mem_ctx,
36 : struct sysdb_ctx *sysdb,
37 : const char *group_dn,
38 : const char **groupname)
39 : {
40 : errno_t ret;
41 : struct ldb_dn *dn;
42 : const char *rdn_name;
43 : const char *group_comp_name;
44 : const char *account_comp_name;
45 : const struct ldb_val *rdn_val;
46 : const struct ldb_val *group_comp_val;
47 : const struct ldb_val *account_comp_val;
48 :
49 : /* This is an IPA-specific hack. It may not
50 : * work for non-IPA servers and will need to
51 : * be changed if SSSD ever supports HBAC on
52 : * a non-IPA server.
53 : */
54 0 : *groupname = NULL;
55 :
56 0 : dn = ldb_dn_new(mem_ctx, sysdb_ctx_get_ldb(sysdb), group_dn);
57 0 : if (dn == NULL) {
58 0 : ret = ENOMEM;
59 0 : goto done;
60 : }
61 :
62 0 : if (!ldb_dn_validate(dn)) {
63 0 : ret = ERR_MALFORMED_ENTRY;
64 0 : goto done;
65 : }
66 :
67 0 : if (ldb_dn_get_comp_num(dn) < 4) {
68 : /* RDN, groups, accounts, and at least one DC= */
69 : /* If it's fewer, it's not a group DN */
70 0 : ret = ERR_UNEXPECTED_ENTRY_TYPE;
71 0 : goto done;
72 : }
73 :
74 : /* If the RDN name is 'cn' */
75 0 : rdn_name = ldb_dn_get_rdn_name(dn);
76 0 : if (rdn_name == NULL) {
77 : /* Shouldn't happen if ldb_dn_validate()
78 : * passed, but we'll be careful.
79 : */
80 0 : ret = ERR_MALFORMED_ENTRY;
81 0 : goto done;
82 : }
83 :
84 0 : if (strcasecmp("cn", rdn_name) != 0) {
85 : /* RDN has the wrong attribute name.
86 : * It's not a group.
87 : */
88 0 : ret = ERR_UNEXPECTED_ENTRY_TYPE;
89 0 : goto done;
90 : }
91 :
92 : /* and the second component is "cn=groups" */
93 0 : group_comp_name = ldb_dn_get_component_name(dn, 1);
94 0 : if (strcasecmp("cn", group_comp_name) != 0) {
95 : /* The second component name is not "cn" */
96 0 : ret = ERR_UNEXPECTED_ENTRY_TYPE;
97 0 : goto done;
98 : }
99 :
100 0 : group_comp_val = ldb_dn_get_component_val(dn, 1);
101 0 : if (strncasecmp("groups",
102 0 : (const char *) group_comp_val->data,
103 : group_comp_val->length) != 0) {
104 : /* The second component value is not "groups" */
105 0 : ret = ERR_UNEXPECTED_ENTRY_TYPE;
106 0 : goto done;
107 : }
108 :
109 : /* and the third component is "accounts" */
110 0 : account_comp_name = ldb_dn_get_component_name(dn, 2);
111 0 : if (strcasecmp("cn", account_comp_name) != 0) {
112 : /* The third component name is not "cn" */
113 0 : ret = ERR_UNEXPECTED_ENTRY_TYPE;
114 0 : goto done;
115 : }
116 :
117 0 : account_comp_val = ldb_dn_get_component_val(dn, 2);
118 0 : if (strncasecmp("accounts",
119 0 : (const char *) account_comp_val->data,
120 : account_comp_val->length) != 0) {
121 : /* The third component value is not "accounts" */
122 0 : ret = ERR_UNEXPECTED_ENTRY_TYPE;
123 0 : goto done;
124 : }
125 :
126 : /* Then the value of the RDN is the group name */
127 0 : rdn_val = ldb_dn_get_rdn_val(dn);
128 0 : *groupname = talloc_strndup(mem_ctx,
129 0 : (const char *)rdn_val->data,
130 : rdn_val->length);
131 0 : if (*groupname == NULL) {
132 0 : ret = ENOMEM;
133 0 : goto done;
134 : }
135 :
136 0 : ret = EOK;
137 :
138 : done:
139 0 : talloc_free(dn);
140 0 : return ret;
141 : }
142 :
143 : errno_t
144 0 : hbac_user_attrs_to_rule(TALLOC_CTX *mem_ctx,
145 : struct sss_domain_info *domain,
146 : const char *rule_name,
147 : struct sysdb_attrs *rule_attrs,
148 : struct hbac_rule_element **users)
149 : {
150 : errno_t ret;
151 0 : TALLOC_CTX *tmp_ctx = NULL;
152 0 : struct hbac_rule_element *new_users = NULL;
153 0 : struct ldb_message_element *el = NULL;
154 0 : struct ldb_message **msgs = NULL;
155 : char *filter;
156 : char *member_dn;
157 : const char *member_user;
158 0 : const char *attrs[] = { SYSDB_NAME, NULL };
159 0 : size_t num_users = 0;
160 0 : size_t num_groups = 0;
161 : const char *name;
162 :
163 : size_t count;
164 : size_t i;
165 :
166 0 : tmp_ctx = talloc_new(mem_ctx);
167 0 : if (tmp_ctx == NULL) return ENOMEM;
168 :
169 0 : new_users = talloc_zero(tmp_ctx, struct hbac_rule_element);
170 0 : if (new_users == NULL) {
171 0 : ret = ENOMEM;
172 0 : goto done;
173 : }
174 :
175 0 : DEBUG(SSSDBG_TRACE_LIBS, "Processing users for rule [%s]\n", rule_name);
176 :
177 0 : ret = hbac_get_category(rule_attrs, IPA_USER_CATEGORY,
178 : &new_users->category);
179 0 : if (ret != EOK) {
180 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not identify user categories\n");
181 0 : goto done;
182 : }
183 0 : if (new_users->category & HBAC_CATEGORY_ALL) {
184 : /* Short-cut to the exit */
185 0 : ret = EOK;
186 0 : goto done;
187 : }
188 :
189 0 : ret = sysdb_attrs_get_el(rule_attrs, IPA_MEMBER_USER, &el);
190 0 : if (ret != EOK && ret != ENOENT) {
191 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_attrs_get_el failed.\n");
192 0 : goto done;
193 : }
194 0 : if (ret == ENOENT || el->num_values == 0) {
195 0 : el->num_values = 0;
196 0 : DEBUG(SSSDBG_CONF_SETTINGS,
197 : "No user specified, rule will never apply.\n");
198 : }
199 :
200 0 : new_users->names = talloc_array(new_users,
201 : const char *,
202 : el->num_values + 1);
203 0 : if (new_users->names == NULL) {
204 0 : ret = ENOMEM;
205 0 : goto done;
206 : }
207 :
208 0 : new_users->groups = talloc_array(new_users,
209 : const char *,
210 : el->num_values + 1);
211 0 : if (new_users->groups == NULL) {
212 0 : ret = ENOMEM;
213 0 : goto done;
214 : }
215 :
216 0 : for (i = 0; i < el->num_values; i++) {
217 0 : member_user = (const char *)el->values[i].data;
218 0 : ret = sss_filter_sanitize(tmp_ctx, member_user, &member_dn);
219 0 : if (ret != EOK) goto done;
220 :
221 0 : filter = talloc_asprintf(member_dn, "(%s=%s)",
222 : SYSDB_ORIG_DN, member_dn);
223 0 : if (filter == NULL) {
224 0 : ret = ENOMEM;
225 0 : goto done;
226 : }
227 :
228 : /* First check if this is a user */
229 0 : ret = sysdb_search_users(tmp_ctx, domain,
230 : filter, attrs, &count, &msgs);
231 0 : if (ret != EOK && ret != ENOENT) goto done;
232 0 : if (ret == EOK && count == 0) {
233 0 : ret = ENOENT;
234 : }
235 :
236 0 : if (ret == EOK) {
237 0 : if (count > 1) {
238 0 : DEBUG(SSSDBG_CRIT_FAILURE,
239 : "Original DN matched multiple users. Skipping \n");
240 0 : talloc_zfree(member_dn);
241 0 : continue;
242 : }
243 :
244 : /* Original DN matched a single user. Get the username */
245 0 : name = ldb_msg_find_attr_as_string(msgs[0], SYSDB_NAME, NULL);
246 0 : if (name == NULL) {
247 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Attribute is missing!\n");
248 0 : ret = EFAULT;
249 0 : goto done;
250 : }
251 :
252 0 : new_users->names[num_users] = talloc_strdup(new_users->names,
253 : name);
254 0 : if (new_users->names[num_users] == NULL) {
255 0 : ret = ENOMEM;
256 0 : goto done;
257 : }
258 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Added user [%s] to rule [%s]\n",
259 : name, rule_name);
260 0 : num_users++;
261 : } else {
262 : /* Check if it is a group instead */
263 0 : ret = sysdb_search_groups(tmp_ctx, domain, filter, attrs,
264 : &count, &msgs);
265 0 : if (ret != EOK && ret != ENOENT) goto done;
266 0 : if (ret == EOK && count == 0) {
267 0 : ret = ENOENT;
268 : }
269 :
270 0 : if (ret == EOK) {
271 0 : if (count > 1) {
272 0 : DEBUG(SSSDBG_CRIT_FAILURE,
273 : "Original DN matched multiple groups. "
274 : "Skipping\n");
275 0 : talloc_zfree(member_dn);
276 0 : continue;
277 : }
278 :
279 : /* Original DN matched a single group. Get the groupname */
280 0 : name = ldb_msg_find_attr_as_string(msgs[0], SYSDB_NAME, NULL);
281 0 : if (name == NULL) {
282 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Attribute is missing!\n");
283 0 : ret = EFAULT;
284 0 : goto done;
285 : }
286 :
287 0 : new_users->groups[num_groups] =
288 0 : talloc_strdup(new_users->groups, name);
289 0 : if (new_users->groups[num_groups] == NULL) {
290 0 : ret = ENOMEM;
291 0 : goto done;
292 : }
293 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
294 : "Added POSIX group [%s] to rule [%s]\n",
295 : name, rule_name);
296 0 : num_groups++;
297 : } else {
298 : /* If the group still matches the group pattern,
299 : * we can assume it is a non-POSIX group.
300 : */
301 0 : ret = get_ipa_groupname(new_users->groups, domain->sysdb,
302 : member_user,
303 0 : &new_users->groups[num_groups]);
304 0 : if (ret == EOK) {
305 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
306 : "Added non-POSIX group [%s] to rule [%s]\n",
307 : new_users->groups[num_groups], rule_name);
308 0 : num_groups++;
309 : } else {
310 : /* Not a group, so we don't care about it */
311 0 : DEBUG(SSSDBG_CRIT_FAILURE,
312 : "[%s] does not map to either a user or group. "
313 : "Skipping\n", member_dn);
314 : }
315 : }
316 : }
317 0 : talloc_zfree(member_dn);
318 : }
319 0 : new_users->names[num_users] = NULL;
320 0 : new_users->groups[num_groups] = NULL;
321 :
322 : /* Shrink the arrays down to their real sizes */
323 0 : new_users->names = talloc_realloc(new_users, new_users->names,
324 : const char *, num_users + 1);
325 0 : if (new_users->names == NULL) {
326 0 : ret = ENOMEM;
327 0 : goto done;
328 : }
329 :
330 0 : new_users->groups = talloc_realloc(new_users, new_users->groups,
331 : const char *, num_groups + 1);
332 0 : if (new_users->groups == NULL) {
333 0 : ret = ENOMEM;
334 0 : goto done;
335 : }
336 :
337 0 : ret = EOK;
338 : done:
339 0 : if (ret == EOK) {
340 0 : *users = talloc_steal(mem_ctx, new_users);
341 : }
342 0 : talloc_free(tmp_ctx);
343 :
344 0 : return ret;
345 : }
|