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/ipa/ipa_hbac_rules.h"
26 : #include "providers/ldap/sdap_async.h"
27 :
28 : struct ipa_hbac_rule_state {
29 : struct tevent_context *ev;
30 : struct sdap_handle *sh;
31 : struct sdap_options *opts;
32 :
33 : int search_base_iter;
34 : struct sdap_search_base **search_bases;
35 :
36 : const char **attrs;
37 : char *rules_filter;
38 : char *cur_filter;
39 :
40 : size_t rule_count;
41 : struct sysdb_attrs **rules;
42 : };
43 :
44 : static errno_t
45 : ipa_hbac_rule_info_next(struct tevent_req *req,
46 : struct ipa_hbac_rule_state *state);
47 : static void
48 : ipa_hbac_rule_info_done(struct tevent_req *subreq);
49 :
50 : struct tevent_req *
51 0 : ipa_hbac_rule_info_send(TALLOC_CTX *mem_ctx,
52 : struct tevent_context *ev,
53 : struct sdap_handle *sh,
54 : struct sdap_options *opts,
55 : struct sdap_search_base **search_bases,
56 : struct sysdb_attrs *ipa_host)
57 : {
58 : errno_t ret;
59 : size_t i;
60 0 : struct tevent_req *req = NULL;
61 : struct ipa_hbac_rule_state *state;
62 : TALLOC_CTX *tmp_ctx;
63 : const char *host_dn;
64 : char *host_dn_clean;
65 : char *host_group_clean;
66 : char *rule_filter;
67 : const char **memberof_list;
68 :
69 0 : if (ipa_host == NULL) {
70 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Missing host\n");
71 0 : return NULL;
72 : }
73 :
74 0 : tmp_ctx = talloc_new(mem_ctx);
75 0 : if (tmp_ctx == NULL) return NULL;
76 :
77 0 : ret = sysdb_attrs_get_string(ipa_host, SYSDB_ORIG_DN, &host_dn);
78 0 : if (ret != EOK) {
79 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not identify IPA hostname\n");
80 0 : goto error;
81 : }
82 :
83 0 : ret = sss_filter_sanitize(tmp_ctx, host_dn, &host_dn_clean);
84 0 : if (ret != EOK) goto error;
85 :
86 0 : req = tevent_req_create(mem_ctx, &state, struct ipa_hbac_rule_state);
87 0 : if (req == NULL) {
88 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create failed.\n");
89 0 : goto error;
90 : }
91 :
92 0 : state->ev = ev;
93 0 : state->sh = sh;
94 0 : state->opts = opts;
95 0 : state->search_bases = search_bases;
96 0 : state->search_base_iter = 0;
97 0 : state->attrs = talloc_zero_array(state, const char *, 15);
98 0 : if (state->attrs == NULL) {
99 0 : ret = ENOMEM;
100 0 : goto immediate;
101 : }
102 0 : state->attrs[0] = OBJECTCLASS;
103 0 : state->attrs[1] = IPA_CN;
104 0 : state->attrs[2] = IPA_UNIQUE_ID;
105 0 : state->attrs[3] = IPA_ENABLED_FLAG;
106 0 : state->attrs[4] = IPA_ACCESS_RULE_TYPE;
107 0 : state->attrs[5] = IPA_MEMBER_USER;
108 0 : state->attrs[6] = IPA_USER_CATEGORY;
109 0 : state->attrs[7] = IPA_MEMBER_SERVICE;
110 0 : state->attrs[8] = IPA_SERVICE_CATEGORY;
111 0 : state->attrs[9] = IPA_SOURCE_HOST;
112 0 : state->attrs[10] = IPA_SOURCE_HOST_CATEGORY;
113 0 : state->attrs[11] = IPA_EXTERNAL_HOST;
114 0 : state->attrs[12] = IPA_MEMBER_HOST;
115 0 : state->attrs[13] = IPA_HOST_CATEGORY;
116 0 : state->attrs[14] = NULL;
117 :
118 0 : rule_filter = talloc_asprintf(tmp_ctx,
119 : "(&(objectclass=%s)"
120 : "(%s=%s)(%s=%s)"
121 : "(|(%s=%s)(%s=%s)",
122 : IPA_HBAC_RULE,
123 : IPA_ENABLED_FLAG, IPA_TRUE_VALUE,
124 : IPA_ACCESS_RULE_TYPE, IPA_HBAC_ALLOW,
125 : IPA_HOST_CATEGORY, "all",
126 : IPA_MEMBER_HOST, host_dn_clean);
127 0 : if (rule_filter == NULL) {
128 0 : ret = ENOMEM;
129 0 : goto immediate;
130 : }
131 :
132 : /* Add all parent groups of ipa_hostname to the filter */
133 0 : ret = sysdb_attrs_get_string_array(ipa_host, SYSDB_ORIG_MEMBEROF,
134 : tmp_ctx, &memberof_list);
135 0 : if (ret != EOK && ret != ENOENT) {
136 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not identify.\n");
137 0 : } if (ret == ENOENT) {
138 : /* This host is not a member of any hostgroups */
139 0 : memberof_list = talloc_array(tmp_ctx, const char *, 1);
140 0 : if (memberof_list == NULL) {
141 0 : ret = ENOMEM;
142 0 : goto immediate;
143 : }
144 0 : memberof_list[0] = NULL;
145 : }
146 :
147 0 : for (i = 0; memberof_list[i]; i++) {
148 0 : ret = sss_filter_sanitize(tmp_ctx,
149 0 : memberof_list[i],
150 : &host_group_clean);
151 0 : if (ret != EOK) goto immediate;
152 :
153 0 : rule_filter = talloc_asprintf_append(rule_filter, "(%s=%s)",
154 : IPA_MEMBER_HOST,
155 : host_group_clean);
156 0 : if (rule_filter == NULL) {
157 0 : ret = ENOMEM;
158 0 : goto immediate;
159 : }
160 : }
161 :
162 0 : rule_filter = talloc_asprintf_append(rule_filter, "))");
163 0 : if (rule_filter == NULL) {
164 0 : ret = ENOMEM;
165 0 : goto immediate;
166 : }
167 0 : state->rules_filter = talloc_steal(state, rule_filter);
168 :
169 0 : ret = ipa_hbac_rule_info_next(req, state);
170 0 : if (ret == EOK) {
171 0 : ret = EINVAL;
172 : }
173 :
174 0 : if (ret != EAGAIN) {
175 0 : goto immediate;
176 : }
177 :
178 0 : talloc_free(tmp_ctx);
179 0 : return req;
180 :
181 : immediate:
182 0 : if (ret == EOK) {
183 0 : tevent_req_done(req);
184 : } else {
185 0 : tevent_req_error(req, ret);
186 : }
187 0 : tevent_req_post(req, ev);
188 0 : talloc_free(tmp_ctx);
189 0 : return req;
190 :
191 : error:
192 0 : talloc_free(tmp_ctx);
193 0 : return NULL;
194 : }
195 :
196 : static errno_t
197 0 : ipa_hbac_rule_info_next(struct tevent_req *req,
198 : struct ipa_hbac_rule_state *state)
199 : {
200 : struct tevent_req *subreq;
201 : struct sdap_search_base *base;
202 :
203 0 : base = state->search_bases[state->search_base_iter];
204 0 : if (base == NULL) {
205 0 : return EOK;
206 : }
207 :
208 0 : talloc_zfree(state->cur_filter);
209 0 : state->cur_filter = sdap_combine_filters(state, state->rules_filter,
210 : base->filter);
211 0 : if (state->cur_filter == NULL) {
212 0 : return ENOMEM;
213 : }
214 :
215 0 : DEBUG(SSSDBG_TRACE_FUNC, "Sending request for next search base: "
216 : "[%s][%d][%s]\n", base->basedn, base->scope,
217 : state->cur_filter);
218 :
219 0 : subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,
220 : base->basedn, base->scope,
221 0 : state->cur_filter, state->attrs,
222 : NULL, 0,
223 0 : dp_opt_get_int(state->opts->basic,
224 : SDAP_ENUM_SEARCH_TIMEOUT),
225 : true);
226 0 : if (subreq == NULL) {
227 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sdap_get_generic_send failed.\n");
228 0 : return ENOMEM;
229 : }
230 0 : tevent_req_set_callback(subreq, ipa_hbac_rule_info_done, req);
231 :
232 0 : return EAGAIN;
233 : }
234 :
235 : static void
236 0 : ipa_hbac_rule_info_done(struct tevent_req *subreq)
237 : {
238 : errno_t ret;
239 0 : struct tevent_req *req =
240 0 : tevent_req_callback_data(subreq, struct tevent_req);
241 0 : struct ipa_hbac_rule_state *state =
242 0 : tevent_req_data(req, struct ipa_hbac_rule_state);
243 : int i;
244 : size_t rule_count;
245 : size_t total_count;
246 : struct sysdb_attrs **rules;
247 : struct sysdb_attrs **target;
248 :
249 0 : ret = sdap_get_generic_recv(subreq, state,
250 : &rule_count,
251 : &rules);
252 0 : if (ret != EOK) {
253 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Could not retrieve HBAC rules\n");
254 0 : goto fail;
255 : }
256 :
257 0 : if (rule_count > 0) {
258 0 : total_count = rule_count + state->rule_count;
259 0 : state->rules = talloc_realloc(state, state->rules,
260 : struct sysdb_attrs *,
261 : total_count);
262 0 : if (state->rules == NULL) {
263 0 : ret = ENOMEM;
264 0 : goto fail;
265 : }
266 :
267 0 : i = 0;
268 0 : while (state->rule_count < total_count) {
269 0 : target = &state->rules[state->rule_count];
270 0 : *target = talloc_steal(state->rules, rules[i]);
271 :
272 0 : state->rule_count++;
273 0 : i++;
274 : }
275 : }
276 :
277 0 : state->search_base_iter++;
278 0 : ret = ipa_hbac_rule_info_next(req, state);
279 0 : if (ret == EAGAIN) {
280 0 : return;
281 0 : } else if (ret != EOK) {
282 0 : goto fail;
283 0 : } else if (ret == EOK && state->rule_count == 0) {
284 0 : DEBUG(SSSDBG_MINOR_FAILURE, "No rules apply to this host\n");
285 0 : tevent_req_error(req, ENOENT);
286 0 : return;
287 : }
288 :
289 : /* We went through all search bases and we have some results */
290 0 : tevent_req_done(req);
291 :
292 0 : return;
293 :
294 : fail:
295 0 : tevent_req_error(req, ret);
296 : }
297 :
298 : errno_t
299 0 : ipa_hbac_rule_info_recv(struct tevent_req *req,
300 : TALLOC_CTX *mem_ctx,
301 : size_t *rule_count,
302 : struct sysdb_attrs ***rules)
303 : {
304 0 : struct ipa_hbac_rule_state *state =
305 0 : tevent_req_data(req, struct ipa_hbac_rule_state);
306 :
307 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
308 :
309 0 : *rule_count = state->rule_count;
310 0 : *rules = talloc_steal(mem_ctx, state->rules);
311 :
312 0 : return EOK;
313 : }
|