Line data Source code
1 : /*
2 : Authors:
3 : Pavel Březina <pbrezina@redhat.com>
4 :
5 : Copyright (C) 2012 Red Hat
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with this program. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include <talloc.h>
22 : #include <tevent.h>
23 : #include <string.h>
24 : #include <ldb.h>
25 :
26 : #include "util/util.h"
27 : #include "providers/ldap/ldap_common.h"
28 : #include "providers/ldap/sdap_async_enum.h"
29 : #include "db/sysdb.h"
30 : #include "db/sysdb_services.h"
31 :
32 : struct sdap_reinit_cleanup_state {
33 : struct sss_domain_info *domain;
34 : struct sysdb_ctx *sysdb;
35 : };
36 :
37 : static errno_t sdap_reinit_clear_usn(struct sysdb_ctx *sysdb,
38 : struct sss_domain_info *domain);
39 : static void sdap_reinit_cleanup_done(struct tevent_req *subreq);
40 : static errno_t sdap_reinit_delete_records(struct sss_domain_info *domain);
41 :
42 0 : struct tevent_req* sdap_reinit_cleanup_send(TALLOC_CTX *mem_ctx,
43 : struct be_ctx *be_ctx,
44 : struct sdap_id_ctx *id_ctx)
45 : {
46 0 : struct tevent_req *req = NULL;
47 0 : struct tevent_req *subreq = NULL;
48 : struct sdap_reinit_cleanup_state *state;
49 : int ret;
50 :
51 : /*
52 : * 1. remove entryUSN attribute from all entries
53 : * 2. run enumeration
54 : * 3. remove records that doesn't have entryUSN attribute updated
55 : *
56 : * We don't need to do this for sudo rules, they will be refreshed
57 : * automatically during next smart/full refresh, or when an expired rule
58 : * is deleted.
59 : */
60 :
61 0 : req = tevent_req_create(mem_ctx, &state, struct sdap_reinit_cleanup_state);
62 0 : if (req == NULL) {
63 0 : return NULL;
64 : }
65 :
66 0 : state->sysdb = be_ctx->domain->sysdb;
67 0 : state->domain = be_ctx->domain;
68 :
69 0 : if (!be_ctx->domain->enumerate) {
70 : /* enumeration is disabled, this whole process is meaningless */
71 0 : ret = EOK;
72 0 : goto immediately;
73 : }
74 :
75 0 : ret = sdap_reinit_clear_usn(state->sysdb, state->domain);
76 0 : if (ret != EOK) {
77 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to clear USN attributes [%d]: %s\n",
78 : ret, strerror(ret));
79 0 : goto immediately;
80 : }
81 :
82 0 : subreq = sdap_dom_enum_send(id_ctx, be_ctx->ev, id_ctx,
83 0 : id_ctx->opts->sdom, id_ctx->conn);
84 0 : if (subreq == NULL) {
85 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to issue enumeration request\n");
86 0 : ret = ENOMEM;
87 0 : goto immediately;
88 : }
89 :
90 0 : tevent_req_set_callback(subreq, sdap_reinit_cleanup_done, req);
91 :
92 0 : return req;
93 :
94 : immediately:
95 0 : if (ret != EOK) {
96 0 : tevent_req_error(req, ret);
97 : } else {
98 0 : tevent_req_done(req);
99 : }
100 0 : tevent_req_post(req, be_ctx->ev);
101 :
102 0 : return req;
103 : }
104 :
105 0 : static void sdap_delete_msgs_usn(struct sysdb_ctx *sysdb,
106 : struct ldb_message **msgs,
107 : size_t msgs_num)
108 : {
109 0 : struct ldb_message_element el = { 0, SYSDB_USN, 0, NULL };
110 0 : struct sysdb_attrs usn_el = { 1, &el };
111 : errno_t ret;
112 : int i;
113 :
114 0 : for (i = 0; i < msgs_num; i++) {
115 0 : ret = sysdb_set_entry_attr(sysdb, msgs[i]->dn, &usn_el, SYSDB_MOD_DEL);
116 0 : if (ret) {
117 0 : DEBUG(SSSDBG_TRACE_FUNC, "Failed to clean USN on entry: [%s]\n",
118 : ldb_dn_get_linearized(msgs[i]->dn));
119 : }
120 : }
121 0 : }
122 :
123 0 : static errno_t sdap_reinit_clear_usn(struct sysdb_ctx *sysdb,
124 : struct sss_domain_info *domain)
125 : {
126 0 : TALLOC_CTX *tmp_ctx = NULL;
127 0 : bool in_transaction = false;
128 0 : struct ldb_message **msgs = NULL;
129 0 : size_t msgs_num = 0;
130 0 : const char *attrs[] = { "dn", NULL };
131 : int sret;
132 : errno_t ret;
133 :
134 0 : tmp_ctx = talloc_new(NULL);
135 0 : if (tmp_ctx == NULL) {
136 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
137 0 : return ENOMEM;
138 : }
139 :
140 0 : ret = sysdb_transaction_start(sysdb);
141 0 : if (ret != EOK) {
142 0 : goto done;
143 : }
144 0 : in_transaction = true;
145 :
146 : /* reset users' usn */
147 0 : ret = sysdb_search_users(tmp_ctx, domain,
148 : "", attrs, &msgs_num, &msgs);
149 0 : if (ret != EOK) {
150 0 : goto done;
151 : }
152 0 : sdap_delete_msgs_usn(sysdb, msgs, msgs_num);
153 0 : talloc_zfree(msgs);
154 0 : msgs_num = 0;
155 :
156 : /* reset groups' usn */
157 0 : ret = sysdb_search_groups(tmp_ctx, domain, "", attrs, &msgs_num, &msgs);
158 0 : if (ret != EOK) {
159 0 : goto done;
160 : }
161 0 : sdap_delete_msgs_usn(sysdb, msgs, msgs_num);
162 0 : talloc_zfree(msgs);
163 0 : msgs_num = 0;
164 :
165 : /* reset services' usn */
166 0 : ret = sysdb_search_services(tmp_ctx, domain, "", attrs, &msgs_num, &msgs);
167 0 : if (ret != EOK) {
168 0 : DEBUG(SSSDBG_OP_FAILURE,
169 : "Cannot search services [%d]: %s\n", ret, strerror(ret));
170 0 : goto done;
171 : }
172 :
173 0 : sdap_delete_msgs_usn(sysdb, msgs, msgs_num);
174 0 : talloc_zfree(msgs);
175 0 : msgs_num = 0;
176 :
177 0 : ret = sysdb_transaction_commit(sysdb);
178 0 : if (ret == EOK) {
179 0 : in_transaction = false;
180 : } else {
181 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Could not commit transaction\n");
182 : }
183 :
184 : done:
185 0 : if (in_transaction) {
186 0 : sret = sysdb_transaction_cancel(sysdb);
187 0 : if (sret != EOK) {
188 0 : DEBUG(SSSDBG_OP_FAILURE, "Could not cancel transaction\n");
189 : }
190 : }
191 :
192 0 : talloc_free(tmp_ctx);
193 :
194 0 : return ret;
195 : }
196 :
197 0 : static void sdap_reinit_cleanup_done(struct tevent_req *subreq)
198 : {
199 0 : struct tevent_req *req = NULL;
200 0 : struct sdap_reinit_cleanup_state *state = NULL;
201 : errno_t ret;
202 :
203 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
204 0 : state = tevent_req_data(req, struct sdap_reinit_cleanup_state);
205 :
206 0 : ret = sdap_dom_enum_recv(subreq);
207 0 : talloc_zfree(subreq);
208 0 : if (ret != EOK) {
209 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Domain enumeration failed [%d]: %s\n",
210 : ret, strerror(ret));
211 0 : goto fail;
212 : }
213 :
214 : /* Ok, we've completed an enumeration. Save this to the
215 : * sysdb so we can postpone starting up the enumeration
216 : * process on the next SSSD service restart (to avoid
217 : * slowing down system boot-up
218 : */
219 0 : ret = sysdb_set_enumerated(state->domain, true);
220 0 : if (ret != EOK) {
221 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Could not mark domain as having "
222 : "enumerated.\n");
223 : /* This error is non-fatal, so continue */
224 : }
225 :
226 0 : ret = sdap_reinit_delete_records(state->domain);
227 0 : if (ret != EOK) {
228 0 : goto fail;
229 : }
230 :
231 0 : tevent_req_done(req);
232 0 : return;
233 :
234 : fail:
235 0 : tevent_req_error(req, ret);
236 : }
237 :
238 0 : static void sdap_delete_msgs_dn(struct sysdb_ctx *sysdb,
239 : struct ldb_message **msgs,
240 : size_t msgs_num)
241 : {
242 : errno_t ret;
243 : int i;
244 :
245 0 : for (i = 0; i < msgs_num; i++) {
246 0 : ret = sysdb_delete_entry(sysdb, msgs[i]->dn, true);
247 0 : if (ret) {
248 0 : DEBUG(SSSDBG_TRACE_FUNC, "Failed to delete entry: [%s]\n",
249 : ldb_dn_get_linearized(msgs[i]->dn));
250 : }
251 : }
252 0 : }
253 :
254 0 : static errno_t sdap_reinit_delete_records(struct sss_domain_info *domain)
255 : {
256 0 : TALLOC_CTX *tmp_ctx = NULL;
257 0 : bool in_transaction = false;
258 0 : struct ldb_message **msgs = NULL;
259 0 : size_t msgs_num = 0;
260 0 : const char *attrs[] = { "dn", NULL };
261 : int sret;
262 : errno_t ret;
263 0 : struct sysdb_ctx *sysdb = domain->sysdb;
264 :
265 0 : tmp_ctx = talloc_new(NULL);
266 0 : if (tmp_ctx == NULL) {
267 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
268 0 : return ENOMEM;
269 : }
270 :
271 0 : ret = sysdb_transaction_start(sysdb);
272 0 : if (ret != EOK) {
273 0 : goto done;
274 : }
275 0 : in_transaction = true;
276 :
277 : /* purge untouched users */
278 0 : ret = sysdb_search_users(tmp_ctx, domain, "(!("SYSDB_USN"=*))",
279 : attrs, &msgs_num, &msgs);
280 0 : if (ret != EOK) {
281 0 : goto done;
282 : }
283 0 : sdap_delete_msgs_dn(sysdb, msgs, msgs_num);
284 0 : talloc_zfree(msgs);
285 0 : msgs_num = 0;
286 :
287 : /* purge untouched groups */
288 0 : ret = sysdb_search_groups(tmp_ctx, domain, "(!("SYSDB_USN"=*))",
289 : attrs, &msgs_num, &msgs);
290 0 : if (ret != EOK) {
291 0 : goto done;
292 : }
293 0 : sdap_delete_msgs_dn(sysdb, msgs, msgs_num);
294 0 : talloc_zfree(msgs);
295 0 : msgs_num = 0;
296 :
297 : /* purge untouched services */
298 0 : ret = sysdb_search_services(tmp_ctx, domain, "(!("SYSDB_USN"=*))",
299 : attrs, &msgs_num, &msgs);
300 0 : if (ret != EOK) {
301 0 : DEBUG(SSSDBG_OP_FAILURE,
302 : "Cannot search services [%d]: %s\n", ret, strerror(ret));
303 0 : goto done;
304 : }
305 :
306 0 : sdap_delete_msgs_dn(sysdb, msgs, msgs_num);
307 0 : talloc_zfree(msgs);
308 0 : msgs_num = 0;
309 :
310 0 : ret = sysdb_transaction_commit(sysdb);
311 0 : if (ret == EOK) {
312 0 : in_transaction = false;
313 : } else {
314 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Could not commit transaction\n");
315 : }
316 :
317 : done:
318 0 : if (in_transaction) {
319 0 : sret = sysdb_transaction_cancel(sysdb);
320 0 : if (sret != EOK) {
321 0 : DEBUG(SSSDBG_OP_FAILURE, "Could not cancel transaction\n");
322 : }
323 : }
324 :
325 0 : talloc_free(tmp_ctx);
326 :
327 0 : return ret;
328 : }
329 :
330 0 : errno_t sdap_reinit_cleanup_recv(struct tevent_req *req)
331 : {
332 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
333 :
334 0 : return EOK;
335 : }
|