Line data Source code
1 : /*
2 : Authors:
3 : Pavel Březina <pbrezina@redhat.com>
4 :
5 : Copyright (C) 2013 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 <tevent.h>
22 : #include <talloc.h>
23 : #include <time.h>
24 : #include <ldb.h>
25 :
26 : #include "providers/backend.h"
27 : #include "providers/be_ptask.h"
28 : #include "providers/be_refresh.h"
29 : #include "util/util_errors.h"
30 : #include "db/sysdb.h"
31 :
32 0 : static errno_t be_refresh_get_values_ex(TALLOC_CTX *mem_ctx,
33 : struct sss_domain_info *domain,
34 : time_t period,
35 : const char *objectclass,
36 : struct ldb_dn *base_dn,
37 : const char *attr,
38 : char ***_values)
39 : {
40 0 : TALLOC_CTX *tmp_ctx = NULL;
41 0 : const char *attrs[] = {attr, NULL};
42 0 : const char *filter = NULL;
43 0 : char **values = NULL;
44 0 : struct ldb_message **msgs = NULL;
45 0 : struct sysdb_attrs **records = NULL;
46 : size_t count;
47 0 : time_t now = time(NULL);
48 : errno_t ret;
49 :
50 0 : tmp_ctx = talloc_new(NULL);
51 0 : if (tmp_ctx == NULL) {
52 0 : return ENOMEM;
53 : }
54 :
55 0 : filter = talloc_asprintf(tmp_ctx, "(&(%s<=%lld))",
56 : SYSDB_CACHE_EXPIRE, (long long) now + period);
57 0 : if (filter == NULL) {
58 0 : ret = ENOMEM;
59 0 : goto done;
60 : }
61 :
62 0 : ret = sysdb_search_entry(tmp_ctx, domain->sysdb, base_dn,
63 : LDB_SCOPE_SUBTREE, filter, attrs,
64 : &count, &msgs);
65 0 : if (ret == ENOENT) {
66 0 : count = 0;
67 0 : } else if (ret != EOK) {
68 0 : goto done;
69 : }
70 :
71 0 : ret = sysdb_msg2attrs(tmp_ctx, count, msgs, &records);
72 0 : if (ret != EOK) {
73 0 : DEBUG(SSSDBG_CRIT_FAILURE,
74 : "Could not convert ldb message to sysdb_attrs\n");
75 0 : goto done;
76 : }
77 :
78 0 : ret = sysdb_attrs_to_list(tmp_ctx, records, count, attr, &values);
79 0 : if (ret != EOK) {
80 0 : goto done;
81 : }
82 :
83 0 : *_values = talloc_steal(mem_ctx, values);
84 0 : ret = EOK;
85 :
86 : done:
87 0 : talloc_free(tmp_ctx);
88 :
89 0 : return ret;
90 : }
91 :
92 0 : static errno_t be_refresh_get_values(TALLOC_CTX *mem_ctx,
93 : enum be_refresh_type type,
94 : struct sss_domain_info *domain,
95 : time_t period,
96 : char ***_values)
97 : {
98 0 : struct ldb_dn *base_dn = NULL;
99 0 : const char *class = NULL;
100 : errno_t ret;
101 :
102 0 : switch (type) {
103 : case BE_REFRESH_TYPE_USERS:
104 0 : base_dn = sysdb_user_base_dn(mem_ctx, domain);
105 0 : class = SYSDB_USER_CLASS;
106 0 : break;
107 : case BE_REFRESH_TYPE_GROUPS:
108 0 : base_dn = sysdb_group_base_dn(mem_ctx, domain);
109 0 : class = SYSDB_GROUP_CLASS;
110 0 : break;
111 : case BE_REFRESH_TYPE_NETGROUPS:
112 0 : base_dn = sysdb_netgroup_base_dn(mem_ctx, domain);
113 0 : class = SYSDB_NETGROUP_CLASS;
114 0 : break;
115 : case BE_REFRESH_TYPE_SENTINEL:
116 0 : return ERR_INTERNAL;
117 : break;
118 : }
119 :
120 0 : if (base_dn == NULL) {
121 0 : return ENOMEM;
122 : }
123 :
124 0 : ret = be_refresh_get_values_ex(mem_ctx, domain, period, class,
125 : base_dn, SYSDB_NAME, _values);
126 :
127 0 : talloc_free(base_dn);
128 0 : return ret;
129 : }
130 :
131 : struct be_refresh_cb {
132 : const char *name;
133 : bool enabled;
134 : be_refresh_send_t send_fn;
135 : be_refresh_recv_t recv_fn;
136 : void *pvt;
137 : };
138 :
139 : struct be_refresh_ctx {
140 : struct be_refresh_cb callbacks[BE_REFRESH_TYPE_SENTINEL];
141 : };
142 :
143 0 : struct be_refresh_ctx *be_refresh_ctx_init(TALLOC_CTX *mem_ctx)
144 : {
145 0 : struct be_refresh_ctx *ctx = NULL;
146 :
147 0 : ctx = talloc_zero(mem_ctx, struct be_refresh_ctx);
148 0 : if (ctx == NULL) {
149 0 : return NULL;
150 : }
151 :
152 0 : ctx->callbacks[BE_REFRESH_TYPE_USERS].name = "users";
153 0 : ctx->callbacks[BE_REFRESH_TYPE_GROUPS].name = "groups";
154 0 : ctx->callbacks[BE_REFRESH_TYPE_NETGROUPS].name = "netgroups";
155 :
156 0 : return ctx;
157 : }
158 :
159 0 : errno_t be_refresh_add_cb(struct be_refresh_ctx *ctx,
160 : enum be_refresh_type type,
161 : be_refresh_send_t send_fn,
162 : be_refresh_recv_t recv_fn,
163 : void *pvt)
164 : {
165 0 : if (ctx == NULL || send_fn == NULL || recv_fn == NULL
166 0 : || type >= BE_REFRESH_TYPE_SENTINEL) {
167 0 : return EINVAL;
168 : }
169 :
170 0 : if (ctx->callbacks[type].enabled) {
171 0 : return EEXIST;
172 : }
173 :
174 0 : ctx->callbacks[type].enabled = true;
175 0 : ctx->callbacks[type].send_fn = send_fn;
176 0 : ctx->callbacks[type].recv_fn = recv_fn;
177 0 : ctx->callbacks[type].pvt = pvt;
178 :
179 0 : return EOK;
180 : }
181 :
182 : struct be_refresh_state {
183 : struct tevent_context *ev;
184 : struct be_ctx *be_ctx;
185 : struct be_refresh_ctx *ctx;
186 : struct be_refresh_cb *cb;
187 :
188 : struct sss_domain_info *domain;
189 : enum be_refresh_type index;
190 : time_t period;
191 : };
192 :
193 : static errno_t be_refresh_step(struct tevent_req *req);
194 : static void be_refresh_done(struct tevent_req *subreq);
195 :
196 0 : struct tevent_req *be_refresh_send(TALLOC_CTX *mem_ctx,
197 : struct tevent_context *ev,
198 : struct be_ctx *be_ctx,
199 : struct be_ptask *be_ptask,
200 : void *pvt)
201 : {
202 0 : struct be_refresh_state *state = NULL;
203 0 : struct tevent_req *req = NULL;
204 : errno_t ret;
205 :
206 0 : req = tevent_req_create(mem_ctx, &state,
207 : struct be_refresh_state);
208 0 : if (req == NULL) {
209 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
210 0 : return NULL;
211 : }
212 :
213 0 : state->ev = ev;
214 0 : state->be_ctx = be_ctx;
215 0 : state->domain = be_ctx->domain;
216 0 : state->period = be_ptask_get_period(be_ptask);
217 0 : state->ctx = talloc_get_type(pvt, struct be_refresh_ctx);
218 0 : if (state->ctx == NULL) {
219 0 : ret = EINVAL;
220 0 : goto immediately;
221 : }
222 :
223 0 : ret = be_refresh_step(req);
224 0 : if (ret == EOK) {
225 0 : goto immediately;
226 0 : } else if (ret != EAGAIN) {
227 0 : DEBUG(SSSDBG_CRIT_FAILURE, "be_refresh_step() failed [%d]: %s\n",
228 : ret, sss_strerror(ret));
229 0 : goto immediately;
230 : }
231 :
232 0 : return req;
233 :
234 : immediately:
235 0 : if (ret == EOK) {
236 0 : tevent_req_done(req);
237 : } else {
238 0 : tevent_req_error(req, ret);
239 : }
240 0 : tevent_req_post(req, ev);
241 :
242 0 : return req;
243 : }
244 :
245 0 : static errno_t be_refresh_step(struct tevent_req *req)
246 : {
247 0 : struct be_refresh_state *state = NULL;
248 0 : struct tevent_req *subreq = NULL;
249 0 : char **values = NULL;
250 : errno_t ret;
251 :
252 0 : state = tevent_req_data(req, struct be_refresh_state);
253 :
254 0 : while (state->domain != NULL) {
255 : /* find first enabled callback */
256 0 : state->cb = &state->ctx->callbacks[state->index];
257 0 : while (state->index != BE_REFRESH_TYPE_SENTINEL && !state->cb->enabled) {
258 0 : state->index++;
259 0 : state->cb = &state->ctx->callbacks[state->index];
260 : }
261 :
262 : /* if not found than continue with next domain */
263 0 : if (state->index == BE_REFRESH_TYPE_SENTINEL) {
264 0 : state->domain = get_next_domain(state->domain, 0);
265 0 : continue;
266 : }
267 :
268 0 : if (state->cb->send_fn == NULL || state->cb->recv_fn == NULL) {
269 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Invalid parameters!\n");
270 0 : ret = ERR_INTERNAL;
271 0 : goto done;
272 : }
273 :
274 0 : ret = be_refresh_get_values(state, state->index, state->domain,
275 : state->period, &values);
276 0 : if (ret != EOK) {
277 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to obtain DN list [%d]: %s\n",
278 : ret, sss_strerror(ret));
279 0 : goto done;
280 : }
281 :
282 0 : DEBUG(SSSDBG_TRACE_FUNC, "Refreshing %s in domain %s\n",
283 : state->cb->name, state->domain->name);
284 :
285 0 : subreq = state->cb->send_fn(state, state->ev, state->be_ctx,
286 0 : state->domain, values, state->cb->pvt);
287 0 : if (subreq == NULL) {
288 0 : ret = ENOMEM;
289 0 : goto done;
290 : }
291 :
292 : /* make the list disappear with subreq */
293 0 : talloc_steal(subreq, values);
294 :
295 0 : tevent_req_set_callback(subreq, be_refresh_done, req);
296 :
297 0 : state->index++;
298 0 : ret = EAGAIN;
299 0 : goto done;
300 : }
301 :
302 0 : ret = EOK;
303 :
304 : done:
305 0 : if (ret != EOK && ret != EAGAIN) {
306 0 : talloc_free(values);
307 : }
308 :
309 0 : return ret;
310 : }
311 :
312 0 : static void be_refresh_done(struct tevent_req *subreq)
313 : {
314 0 : struct be_refresh_state *state = NULL;
315 0 : struct tevent_req *req = NULL;
316 : errno_t ret;
317 :
318 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
319 0 : state = tevent_req_data(req, struct be_refresh_state);
320 :
321 0 : ret = state->cb->recv_fn(subreq);
322 0 : talloc_zfree(subreq);
323 0 : if (ret != EOK) {
324 0 : goto done;
325 : }
326 :
327 0 : ret = be_refresh_step(req);
328 0 : if (ret == EAGAIN) {
329 0 : return;
330 : }
331 :
332 : done:
333 0 : if (ret != EOK) {
334 0 : tevent_req_error(req, ret);
335 0 : return;
336 : }
337 :
338 0 : tevent_req_done(req);
339 : }
340 :
341 0 : errno_t be_refresh_recv(struct tevent_req *req)
342 : {
343 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
344 :
345 0 : return EOK;
346 : }
|