Line data Source code
1 : /*
2 : Authors:
3 : Pavel Březina <pbrezina@redhat.com>
4 :
5 : Copyright (C) 2014 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 <dbus/dbus.h>
22 : #include <ldb.h>
23 : #include <talloc.h>
24 : #include <tevent.h>
25 :
26 : #include "util/util.h"
27 : #include "db/sysdb.h"
28 : #include "responder/common/responder_cache_req.h"
29 : #include "providers/data_provider.h"
30 :
31 6 : static errno_t updated_users_by_filter(TALLOC_CTX *mem_ctx,
32 : struct sss_domain_info *domain,
33 : const char *name_filter,
34 : time_t since,
35 : struct ldb_result **_res)
36 : {
37 : int ret;
38 : char *recent_filter;
39 :
40 6 : recent_filter = talloc_asprintf(mem_ctx, "(%s>=%lu)",
41 : SYSDB_LAST_UPDATE, since);
42 6 : ret = sysdb_enumpwent_filter_with_views(mem_ctx, domain,
43 : name_filter, recent_filter,
44 : _res);
45 6 : talloc_free(recent_filter);
46 :
47 6 : return ret;
48 : }
49 :
50 4 : static errno_t updated_groups_by_filter(TALLOC_CTX *mem_ctx,
51 : struct sss_domain_info *domain,
52 : const char *name_filter,
53 : time_t since,
54 : struct ldb_result **_res)
55 : {
56 : int ret;
57 : char *recent_filter;
58 :
59 4 : recent_filter = talloc_asprintf(mem_ctx, "(%s>=%lu)",
60 : SYSDB_LAST_UPDATE, since);
61 4 : ret = sysdb_enumgrent_filter_with_views(mem_ctx, domain,
62 : name_filter, recent_filter,
63 : _res);
64 4 : talloc_free(recent_filter);
65 :
66 4 : return ret;
67 : }
68 :
69 : struct cache_req_input {
70 : enum cache_req_type type;
71 :
72 : /* Provided input. */
73 : const char *orig_name;
74 : uint32_t id;
75 : const char *cert;
76 :
77 : /* Parsed name or UPN. */
78 : const char *name;
79 :
80 : /* Data Provider request type resolved from @type.
81 : * FIXME: This is currently needed for data provider calls. We should
82 : * refactor responder_dp.c to get rid of this member. */
83 : enum sss_dp_acct_type dp_type;
84 :
85 : /* Domain related informations. */
86 : struct sss_domain_info *domain;
87 :
88 : /* Name sanitized according to domain rules such as case sensitivity and
89 : * replacement of space character. This needs to be set up for each
90 : * domain separately. */
91 : const char *dom_objname;
92 :
93 : /* Fully qualified object name used in debug messages. */
94 : const char *debug_fqn;
95 : /* Time when the request started. Useful for by-filter lookups */
96 : time_t req_start;
97 : };
98 :
99 : struct cache_req_input *
100 53 : cache_req_input_create(TALLOC_CTX *mem_ctx,
101 : enum cache_req_type type,
102 : const char *name,
103 : uint32_t id,
104 : const char *cert)
105 : {
106 : struct cache_req_input *input;
107 :
108 53 : input = talloc_zero(mem_ctx, struct cache_req_input);
109 53 : if (input == NULL) {
110 0 : return NULL;
111 : }
112 :
113 53 : input->type = type;
114 53 : input->req_start = time(NULL);
115 :
116 : /* Check that input parameters match selected type. */
117 53 : switch (input->type) {
118 : case CACHE_REQ_USER_BY_NAME:
119 : case CACHE_REQ_USER_BY_UPN:
120 : case CACHE_REQ_GROUP_BY_NAME:
121 : case CACHE_REQ_USER_BY_FILTER:
122 : case CACHE_REQ_GROUP_BY_FILTER:
123 : case CACHE_REQ_INITGROUPS:
124 : case CACHE_REQ_INITGROUPS_BY_UPN:
125 31 : if (name == NULL) {
126 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Bug: name cannot be NULL!\n");
127 0 : goto fail;
128 : }
129 :
130 31 : input->orig_name = talloc_strdup(input, name);
131 31 : if (input->orig_name == NULL) {
132 0 : goto fail;
133 : }
134 31 : break;
135 : case CACHE_REQ_USER_BY_CERT:
136 6 : if (cert == NULL) {
137 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Bug: certificate cannot be NULL!\n");
138 0 : goto fail;
139 : }
140 :
141 6 : input->cert = talloc_strdup(input, cert);
142 6 : if (input->cert == NULL) {
143 0 : goto fail;
144 : }
145 6 : break;
146 : case CACHE_REQ_USER_BY_ID:
147 : case CACHE_REQ_GROUP_BY_ID:
148 16 : if (id == 0) {
149 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Bug: id cannot be 0!\n");
150 0 : goto fail;
151 : }
152 :
153 16 : input->id = id;
154 16 : break;
155 : }
156 :
157 : /* Resolve Data Provider request type. */
158 53 : switch (type) {
159 : case CACHE_REQ_USER_BY_NAME:
160 : case CACHE_REQ_USER_BY_UPN:
161 : case CACHE_REQ_USER_BY_ID:
162 25 : input->dp_type = SSS_DP_USER;
163 25 : break;
164 :
165 : case CACHE_REQ_GROUP_BY_NAME:
166 : case CACHE_REQ_GROUP_BY_ID:
167 17 : input->dp_type = SSS_DP_GROUP;
168 17 : break;
169 :
170 : case CACHE_REQ_INITGROUPS:
171 : case CACHE_REQ_INITGROUPS_BY_UPN:
172 0 : input->dp_type = SSS_DP_INITGROUPS;
173 0 : break;
174 :
175 : case CACHE_REQ_USER_BY_CERT:
176 6 : input->dp_type = SSS_DP_CERT;
177 6 : break;
178 :
179 : case CACHE_REQ_USER_BY_FILTER:
180 3 : input->dp_type = SSS_DP_WILDCARD_USER;
181 3 : break;
182 :
183 : case CACHE_REQ_GROUP_BY_FILTER:
184 2 : input->dp_type = SSS_DP_WILDCARD_GROUP;
185 2 : break;
186 : }
187 :
188 53 : return input;
189 :
190 : fail:
191 0 : talloc_free(input);
192 0 : return NULL;
193 : }
194 :
195 : static errno_t
196 31 : cache_req_input_set_name(struct cache_req_input *input,
197 : const char *name)
198 : {
199 : const char *dup;
200 :
201 31 : dup = talloc_strdup(input, name);
202 31 : if (dup == NULL) {
203 0 : return ENOMEM;
204 : }
205 :
206 31 : talloc_zfree(input->name);
207 31 : input->name = dup;
208 :
209 31 : return EOK;
210 : }
211 :
212 : static errno_t
213 83 : cache_req_input_set_domain(struct cache_req_input *input,
214 : struct sss_domain_info *domain,
215 : struct resp_ctx *rctx)
216 : {
217 83 : TALLOC_CTX *tmp_ctx = NULL;
218 83 : const char *name = NULL;
219 83 : const char *debug_fqn = NULL;
220 : errno_t ret;
221 :
222 83 : tmp_ctx = talloc_new(NULL);
223 83 : if (tmp_ctx == NULL) {
224 0 : return ENOMEM;
225 : }
226 :
227 83 : talloc_zfree(input->dom_objname);
228 83 : talloc_zfree(input->debug_fqn);
229 :
230 83 : switch (input->type) {
231 : case CACHE_REQ_USER_BY_NAME:
232 : case CACHE_REQ_USER_BY_UPN:
233 : case CACHE_REQ_GROUP_BY_NAME:
234 : case CACHE_REQ_USER_BY_FILTER:
235 : case CACHE_REQ_GROUP_BY_FILTER:
236 : case CACHE_REQ_INITGROUPS:
237 : case CACHE_REQ_INITGROUPS_BY_UPN:
238 49 : if (input->name == NULL) {
239 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Bug: input->name is NULL?\n");
240 0 : ret = ERR_INTERNAL;
241 0 : goto done;
242 : }
243 :
244 49 : name = sss_get_cased_name(tmp_ctx, input->name, domain->case_sensitive);
245 49 : if (name == NULL) {
246 0 : ret = ENOMEM;
247 0 : goto done;
248 : }
249 :
250 49 : name = sss_reverse_replace_space(tmp_ctx, name, rctx->override_space);
251 49 : if (name == NULL) {
252 0 : ret = ENOMEM;
253 0 : goto done;
254 : }
255 :
256 49 : debug_fqn = talloc_asprintf(tmp_ctx, "%s@%s", name, domain->name);
257 49 : if (debug_fqn == NULL) {
258 0 : ret = ENOMEM;
259 0 : goto done;
260 : }
261 :
262 49 : break;
263 :
264 : case CACHE_REQ_USER_BY_ID:
265 14 : debug_fqn = talloc_asprintf(tmp_ctx, "UID:%d@%s", input->id, domain->name);
266 14 : if (debug_fqn == NULL) {
267 0 : ret = ENOMEM;
268 0 : goto done;
269 : }
270 14 : break;
271 :
272 : case CACHE_REQ_GROUP_BY_ID:
273 14 : debug_fqn = talloc_asprintf(tmp_ctx, "GID:%d@%s", input->id, domain->name);
274 14 : if (debug_fqn == NULL) {
275 0 : ret = ENOMEM;
276 0 : goto done;
277 : }
278 14 : break;
279 : case CACHE_REQ_USER_BY_CERT:
280 : /* certificates might be quite long, only use the last 10 charcters
281 : * for logging */
282 6 : debug_fqn = talloc_asprintf(tmp_ctx, "CERT:%s@%s",
283 : get_last_x_chars(input->cert, 10),
284 : domain->name);
285 6 : if (debug_fqn == NULL) {
286 0 : ret = ENOMEM;
287 0 : goto done;
288 : }
289 6 : break;
290 : }
291 :
292 83 : input->domain = domain;
293 83 : input->dom_objname = talloc_steal(input, name);
294 83 : input->debug_fqn = talloc_steal(input, debug_fqn);
295 :
296 83 : ret = EOK;
297 :
298 : done:
299 83 : talloc_free(tmp_ctx);
300 83 : return ret;
301 : }
302 :
303 : static bool
304 130 : cache_req_input_is_upn(struct cache_req_input *input)
305 : {
306 130 : switch (input->type) {
307 : case CACHE_REQ_USER_BY_UPN:
308 : case CACHE_REQ_INITGROUPS_BY_UPN:
309 27 : return true;
310 : default:
311 103 : return false;
312 : }
313 : }
314 :
315 : static bool
316 20 : cache_req_input_assume_upn(struct cache_req_input *input)
317 : {
318 : errno_t ret;
319 : bool bret;
320 :
321 20 : if (input->orig_name == NULL || strchr(input->orig_name, '@') == NULL) {
322 12 : return false;
323 : }
324 :
325 8 : switch (input->type) {
326 : case CACHE_REQ_USER_BY_NAME:
327 8 : input->type = CACHE_REQ_USER_BY_UPN;
328 8 : bret = true;
329 8 : break;
330 : case CACHE_REQ_INITGROUPS:
331 0 : input->type = CACHE_REQ_INITGROUPS_BY_UPN;
332 0 : bret = true;
333 0 : break;
334 : default:
335 0 : bret = false;
336 0 : break;
337 : }
338 :
339 8 : if (bret == true) {
340 8 : ret = cache_req_input_set_name(input, input->orig_name);
341 8 : if (ret != EOK) {
342 0 : DEBUG(SSSDBG_CRIT_FAILURE,
343 : "cache_req_input_set_orig_name() failed\n");
344 0 : return false;
345 : }
346 :
347 8 : DEBUG(SSSDBG_TRACE_FUNC, "Assuming UPN %s\n", input->orig_name);
348 : }
349 :
350 8 : return bret;
351 : }
352 :
353 83 : static errno_t cache_req_check_ncache(struct cache_req_input *input,
354 : struct sss_nc_ctx *ncache,
355 : int neg_timeout)
356 : {
357 83 : errno_t ret = ERR_INTERNAL;
358 :
359 83 : switch (input->type) {
360 : case CACHE_REQ_USER_BY_NAME:
361 : case CACHE_REQ_USER_BY_UPN:
362 : case CACHE_REQ_INITGROUPS:
363 : case CACHE_REQ_INITGROUPS_BY_UPN:
364 29 : ret = sss_ncache_check_user(ncache, neg_timeout,
365 : input->domain, input->dom_objname);
366 29 : break;
367 : case CACHE_REQ_GROUP_BY_NAME:
368 15 : ret = sss_ncache_check_group(ncache, neg_timeout,
369 : input->domain, input->dom_objname);
370 15 : break;
371 : case CACHE_REQ_USER_BY_ID:
372 14 : ret = sss_ncache_check_uid(ncache, neg_timeout, NULL, input->id);
373 14 : break;
374 : case CACHE_REQ_GROUP_BY_ID:
375 14 : ret = sss_ncache_check_gid(ncache, neg_timeout, NULL, input->id);
376 14 : break;
377 : case CACHE_REQ_USER_BY_CERT:
378 6 : ret = sss_ncache_check_cert(ncache, neg_timeout, input->cert);
379 6 : break;
380 : case CACHE_REQ_USER_BY_FILTER:
381 : case CACHE_REQ_GROUP_BY_FILTER:
382 5 : ret = EOK;
383 5 : break;
384 : }
385 :
386 83 : if (ret == EEXIST) {
387 5 : DEBUG(SSSDBG_TRACE_FUNC, "[%s] does not exist (negative cache)\n",
388 : input->debug_fqn);
389 : }
390 :
391 83 : return ret;
392 : }
393 :
394 46 : static void cache_req_add_to_ncache(struct cache_req_input *input,
395 : struct sss_nc_ctx *ncache)
396 : {
397 46 : errno_t ret = ERR_INTERNAL;
398 :
399 46 : switch (input->type) {
400 : case CACHE_REQ_USER_BY_NAME:
401 : case CACHE_REQ_USER_BY_UPN:
402 : case CACHE_REQ_INITGROUPS:
403 : case CACHE_REQ_INITGROUPS_BY_UPN:
404 16 : ret = sss_ncache_set_user(ncache, false, input->domain,
405 : input->dom_objname);
406 16 : break;
407 : case CACHE_REQ_GROUP_BY_NAME:
408 8 : ret = sss_ncache_set_group(ncache, false, input->domain,
409 : input->dom_objname);
410 8 : break;
411 : case CACHE_REQ_USER_BY_FILTER:
412 : case CACHE_REQ_GROUP_BY_FILTER:
413 : /* Nothing to do, adding a wildcard request to ncache doesn't
414 : * make sense */
415 : case CACHE_REQ_USER_BY_ID:
416 : case CACHE_REQ_GROUP_BY_ID:
417 : case CACHE_REQ_USER_BY_CERT:
418 : /* Nothing to do. Those types must be unique among all domains so
419 : * the don't contain domain part. Therefore they must be set only
420 : * if all domains are search and the entry is not found. */
421 22 : ret = EOK;
422 22 : break;
423 : }
424 :
425 46 : if (ret != EOK) {
426 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Cannot set negcache for [%s] [%d]: %s\n",
427 : input->debug_fqn, ret, sss_strerror(ret));
428 :
429 : /* not fatal */
430 : }
431 :
432 46 : return;
433 : }
434 :
435 9 : static void cache_req_add_to_ncache_global(struct cache_req_input *input,
436 : struct sss_nc_ctx *ncache)
437 : {
438 9 : errno_t ret = ERR_INTERNAL;
439 :
440 9 : switch (input->type) {
441 : case CACHE_REQ_USER_BY_FILTER:
442 : case CACHE_REQ_GROUP_BY_FILTER:
443 : /* Nothing to do, adding a wildcard request to ncache doesn't
444 : * make sense */
445 : case CACHE_REQ_USER_BY_NAME:
446 : case CACHE_REQ_USER_BY_UPN:
447 : case CACHE_REQ_GROUP_BY_NAME:
448 : case CACHE_REQ_INITGROUPS:
449 : case CACHE_REQ_INITGROUPS_BY_UPN:
450 : /* Nothing to do. Those types are already in ncache for selected
451 : * domains. */
452 5 : ret = EOK;
453 5 : break;
454 : case CACHE_REQ_USER_BY_ID:
455 1 : ret = sss_ncache_set_uid(ncache, false, NULL, input->id);
456 1 : break;
457 : case CACHE_REQ_GROUP_BY_ID:
458 1 : ret = sss_ncache_set_gid(ncache, false, NULL, input->id);
459 1 : break;
460 : case CACHE_REQ_USER_BY_CERT:
461 2 : ret = sss_ncache_set_cert(ncache, false, input->cert);
462 2 : break;
463 : }
464 :
465 9 : if (ret != EOK) {
466 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Cannot set negcache for [%s] [%d]: %s\n",
467 : input->debug_fqn, ret, sss_strerror(ret));
468 :
469 : /* not fatal */
470 : }
471 :
472 9 : return;
473 : }
474 :
475 139 : static errno_t cache_req_get_object(TALLOC_CTX *mem_ctx,
476 : struct cache_req_input *input,
477 : struct ldb_result **_result)
478 : {
479 139 : struct ldb_result *result = NULL;
480 139 : bool one_item_only = false;
481 139 : errno_t ret = ERR_INTERNAL;
482 :
483 139 : DEBUG(SSSDBG_FUNC_DATA, "Requesting info for [%s]\n", input->debug_fqn);
484 :
485 139 : switch (input->type) {
486 : case CACHE_REQ_USER_BY_NAME:
487 24 : one_item_only = true;
488 24 : ret = sysdb_getpwnam_with_views(mem_ctx, input->domain,
489 : input->dom_objname, &result);
490 24 : break;
491 : case CACHE_REQ_USER_BY_UPN:
492 23 : one_item_only = true;
493 23 : ret = sysdb_getpwupn(mem_ctx, input->domain,
494 : input->dom_objname, &result);
495 23 : break;
496 : case CACHE_REQ_USER_BY_ID:
497 23 : one_item_only = true;
498 23 : ret = sysdb_getpwuid_with_views(mem_ctx, input->domain,
499 : input->id, &result);
500 23 : break;
501 : case CACHE_REQ_GROUP_BY_NAME:
502 24 : one_item_only = true;
503 24 : ret = sysdb_getgrnam_with_views(mem_ctx, input->domain,
504 : input->dom_objname, &result);
505 24 : break;
506 : case CACHE_REQ_GROUP_BY_ID:
507 23 : one_item_only = true;
508 23 : ret = sysdb_getgrgid_with_views(mem_ctx, input->domain,
509 : input->id, &result);
510 23 : break;
511 : case CACHE_REQ_INITGROUPS:
512 0 : one_item_only = false;
513 0 : ret = sysdb_initgroups_with_views(mem_ctx, input->domain,
514 : input->dom_objname, &result);
515 0 : break;
516 : case CACHE_REQ_INITGROUPS_BY_UPN:
517 0 : one_item_only = false;
518 0 : ret = sysdb_initgroups_by_upn(mem_ctx, input->domain,
519 : input->dom_objname, &result);
520 0 : break;
521 : case CACHE_REQ_USER_BY_CERT:
522 12 : one_item_only = true;
523 12 : ret = sysdb_search_user_by_cert(mem_ctx, input->domain,
524 : input->cert, &result);
525 12 : break;
526 : case CACHE_REQ_USER_BY_FILTER:
527 6 : one_item_only = false;
528 6 : ret = updated_users_by_filter(mem_ctx, input->domain,
529 : input->dom_objname, input->req_start,
530 : &result);
531 6 : break;
532 : case CACHE_REQ_GROUP_BY_FILTER:
533 4 : one_item_only = false;
534 4 : ret = updated_groups_by_filter(mem_ctx, input->domain,
535 : input->dom_objname, input->req_start,
536 : &result);
537 4 : break;
538 : }
539 :
540 139 : if (ret != EOK) {
541 25 : goto done;
542 114 : } else if (result->count == 0) {
543 77 : ret = ENOENT;
544 77 : goto done;
545 37 : } else if (one_item_only && result->count > 1) {
546 0 : ret = ERR_INTERNAL;
547 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Multiple objects were found when"
548 : "sysdb search expected only one!\n");
549 0 : goto done;
550 : }
551 :
552 37 : *_result = result;
553 :
554 : done:
555 139 : return ret;
556 : }
557 :
558 : /* Return true if the request bypasses cache or false if the cache_req
559 : * code can leverage sysdb for this request.
560 : */
561 22 : static bool cache_req_bypass_cache(struct cache_req_input *input)
562 : {
563 44 : if (input->type == CACHE_REQ_USER_BY_FILTER ||
564 22 : input->type == CACHE_REQ_GROUP_BY_FILTER) {
565 0 : return true;
566 : }
567 :
568 22 : return false;
569 : }
570 :
571 : struct cache_req_cache_state {
572 : /* input data */
573 : struct tevent_context *ev;
574 : struct resp_ctx *rctx;
575 : struct sss_nc_ctx *ncache;
576 : int neg_timeout;
577 : int cache_refresh_percent;
578 : struct cache_req_input *input;
579 :
580 : /* output data */
581 : struct ldb_result *result;
582 : };
583 :
584 : static errno_t cache_req_cache_search(struct tevent_req *req);
585 : static errno_t cache_req_cache_check(struct tevent_req *req);
586 : static void cache_req_cache_done(struct tevent_req *subreq);
587 :
588 83 : static struct tevent_req *cache_req_cache_send(TALLOC_CTX *mem_ctx,
589 : struct tevent_context *ev,
590 : struct resp_ctx *rctx,
591 : struct sss_nc_ctx *ncache,
592 : int neg_timeout,
593 : int cache_refresh_percent,
594 : struct cache_req_input *input)
595 : {
596 83 : struct cache_req_cache_state *state = NULL;
597 83 : struct tevent_req *req = NULL;
598 : errno_t ret;
599 :
600 83 : req = tevent_req_create(mem_ctx, &state, struct cache_req_cache_state);
601 83 : if (req == NULL) {
602 0 : DEBUG(SSSDBG_CRIT_FAILURE, ("tevent_req_create() failed\n"));
603 0 : return NULL;
604 : }
605 :
606 83 : state->ev = ev;
607 83 : state->rctx = rctx;
608 83 : state->ncache = ncache;
609 83 : state->neg_timeout = neg_timeout;
610 83 : state->cache_refresh_percent = cache_refresh_percent;
611 83 : state->input = input;
612 :
613 : /* Check negative cache first. */
614 83 : ret = cache_req_check_ncache(state->input, state->ncache,
615 83 : state->neg_timeout);
616 83 : if (ret == EEXIST) {
617 5 : ret = ENOENT;
618 5 : goto immediately;
619 : }
620 :
621 : /* We will first search the cache. If we get cache miss or the entry
622 : * is expired we will contact data provider and then search again. */
623 78 : ret = cache_req_cache_search(req);
624 78 : if (ret != EAGAIN) {
625 17 : goto immediately;
626 : }
627 :
628 61 : return req;
629 :
630 : immediately:
631 22 : if (ret == EOK) {
632 17 : tevent_req_done(req);
633 : } else {
634 5 : tevent_req_error(req, ret);
635 : }
636 22 : tevent_req_post(req, ev);
637 :
638 22 : return req;
639 : }
640 :
641 78 : static errno_t cache_req_cache_search(struct tevent_req *req)
642 : {
643 78 : struct cache_req_cache_state *state = NULL;
644 : errno_t ret;
645 :
646 78 : state = tevent_req_data(req, struct cache_req_cache_state);
647 :
648 78 : ret = cache_req_get_object(state, state->input, &state->result);
649 78 : if (ret != EOK && ret != ENOENT) {
650 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to make request to our cache "
651 : "[%d]: %s\n", ret, sss_strerror(ret));
652 0 : return ret;
653 : }
654 :
655 : /* Verify that the cache is up to date. */
656 78 : ret = cache_req_cache_check(req);
657 78 : if (req != EOK) {
658 78 : return ret;
659 : }
660 :
661 : /* One result found */
662 0 : DEBUG(SSSDBG_TRACE_FUNC, "Returning info for [%s]\n",
663 : state->input->debug_fqn);
664 0 : return EOK;
665 : }
666 :
667 78 : static errno_t cache_req_cache_check(struct tevent_req *req)
668 : {
669 78 : struct cache_req_cache_state *state = NULL;
670 78 : struct tevent_req *subreq = NULL;
671 78 : const char *extra_flag = NULL;
672 78 : uint64_t cache_expire = 0;
673 : errno_t ret;
674 : const char *search_str;
675 :
676 78 : state = tevent_req_data(req, struct cache_req_cache_state);
677 :
678 100 : if (state->result == NULL || state->result->count == 0 ||
679 22 : cache_req_bypass_cache(state->input) == true) {
680 56 : ret = ENOENT;
681 : } else {
682 22 : if (state->input->type == CACHE_REQ_INITGROUPS) {
683 0 : cache_expire = ldb_msg_find_attr_as_uint64(state->result->msgs[0],
684 : SYSDB_INITGR_EXPIRE, 0);
685 : } else {
686 22 : cache_expire = ldb_msg_find_attr_as_uint64(state->result->msgs[0],
687 : SYSDB_CACHE_EXPIRE, 0);
688 : }
689 :
690 22 : ret = sss_cmd_check_cache(state->result->msgs[0],
691 : state->cache_refresh_percent, cache_expire);
692 : }
693 :
694 78 : search_str = state->input->dom_objname;
695 78 : if (state->input->type == CACHE_REQ_USER_BY_CERT) {
696 6 : search_str = state->input->cert;
697 : }
698 :
699 78 : if (DOM_HAS_VIEWS(state->input->domain)) {
700 0 : extra_flag = EXTRA_INPUT_MAYBE_WITH_VIEW;
701 78 : } else if (cache_req_input_is_upn(state->input)) {
702 13 : extra_flag = EXTRA_NAME_IS_UPN;
703 : }
704 :
705 78 : switch (ret) {
706 : case EOK:
707 12 : DEBUG(SSSDBG_TRACE_FUNC, "Cached entry is valid, returning...\n");
708 12 : return EOK;
709 : case EAGAIN:
710 : /* Out of band update. The calling function will return the cached
711 : * entry immediately. No callback is required. */
712 :
713 5 : DEBUG(SSSDBG_TRACE_FUNC, "Performing midpoint cache update\n");
714 :
715 15 : subreq = sss_dp_get_account_send(state, state->rctx,
716 5 : state->input->domain, true,
717 5 : state->input->dp_type,
718 : search_str,
719 5 : state->input->id, extra_flag);
720 5 : if (subreq == NULL) {
721 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory sending out-of-band "
722 : "data provider request\n");
723 : /* This is non-fatal, so we'll continue here */
724 : } else {
725 5 : DEBUG(SSSDBG_TRACE_FUNC, "Updating cache out-of-band\n");
726 : }
727 :
728 5 : return EOK;
729 : case ENOENT:
730 : /* Cache miss or the cache is expired. We need to get the updated
731 : * information before returning it. */
732 :
733 183 : subreq = sss_dp_get_account_send(state, state->rctx,
734 61 : state->input->domain, true,
735 61 : state->input->dp_type,
736 : search_str,
737 61 : state->input->id, extra_flag);
738 61 : if (subreq == NULL) {
739 0 : DEBUG(SSSDBG_CRIT_FAILURE,
740 : "Out of memory sending data provider request\n");
741 0 : return ENOMEM;
742 : }
743 :
744 61 : tevent_req_set_callback(subreq, cache_req_cache_done, req);
745 61 : return EAGAIN;
746 : default:
747 : /* error */
748 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Error checking cache [%d]: %s\n",
749 : ret, sss_strerror(ret));
750 0 : return ret;
751 : }
752 : }
753 :
754 61 : static void cache_req_cache_done(struct tevent_req *subreq)
755 : {
756 61 : struct cache_req_cache_state *state = NULL;
757 61 : struct tevent_req *req = NULL;
758 61 : char *err_msg = NULL;
759 : dbus_uint16_t err_maj;
760 : dbus_uint32_t err_min;
761 : errno_t ret;
762 :
763 61 : req = tevent_req_callback_data(subreq, struct tevent_req);
764 61 : state = tevent_req_data(req, struct cache_req_cache_state);
765 :
766 61 : ret = sss_dp_get_account_recv(state, subreq, &err_maj, &err_min, &err_msg);
767 61 : talloc_zfree(subreq);
768 61 : if (ret != EOK) {
769 0 : DEBUG(SSSDBG_OP_FAILURE, "Could not get account info [%d]: %s\n",
770 : ret, sss_strerror(ret));
771 : }
772 :
773 61 : if (err_maj) {
774 0 : DEBUG(SSSDBG_MINOR_FAILURE,
775 : "Unable to get information from Data Provider\n"
776 : "Error: %u, %u, %s\n"
777 : "Will try to return what we have in cache\n",
778 : (unsigned int)err_maj, (unsigned int)err_min, err_msg);
779 : }
780 :
781 : /* Get result from cache again. */
782 61 : ret = cache_req_get_object(state, state->input, &state->result);
783 61 : if (ret == ENOENT) {
784 46 : cache_req_add_to_ncache(state->input, state->ncache);
785 46 : ret = ENOENT;
786 15 : } else if (ret != EOK) {
787 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to make request to our cache "
788 : "[%d]: %s\n", ret, sss_strerror(ret));
789 : }
790 :
791 61 : if (ret != EOK) {
792 46 : tevent_req_error(req, ret);
793 46 : return;
794 : }
795 :
796 : /* One result found */
797 15 : DEBUG(SSSDBG_TRACE_FUNC, "Returning info for [%s]\n",
798 : state->input->debug_fqn);
799 :
800 15 : tevent_req_done(req);
801 : }
802 :
803 83 : static errno_t cache_req_cache_recv(TALLOC_CTX *mem_ctx,
804 : struct tevent_req *req,
805 : struct ldb_result **_result)
806 : {
807 83 : struct cache_req_cache_state *state = NULL;
808 83 : state = tevent_req_data(req, struct cache_req_cache_state);
809 :
810 134 : TEVENT_REQ_RETURN_ON_ERROR(req);
811 :
812 32 : *_result = talloc_steal(mem_ctx, state->result);
813 :
814 32 : return EOK;
815 : }
816 :
817 :
818 : struct cache_req_state {
819 : /* input data */
820 : struct tevent_context *ev;
821 : struct resp_ctx *rctx;
822 : struct sss_nc_ctx *ncache;
823 : int neg_timeout;
824 : int cache_refresh_percent;
825 : struct cache_req_input *input;
826 :
827 : /* work data */
828 : struct ldb_result *result;
829 : struct sss_domain_info *domain;
830 : struct sss_domain_info *selected_domain;
831 : bool check_next;
832 : };
833 :
834 : static void cache_req_input_parsed(struct tevent_req *subreq);
835 :
836 : static errno_t cache_req_select_domains(struct tevent_req *req,
837 : const char *domain);
838 :
839 : static errno_t cache_req_next_domain(struct tevent_req *req);
840 :
841 : static void cache_req_done(struct tevent_req *subreq);
842 :
843 53 : struct tevent_req *cache_req_send(TALLOC_CTX *mem_ctx,
844 : struct tevent_context *ev,
845 : struct resp_ctx *rctx,
846 : struct sss_nc_ctx *ncache,
847 : int neg_timeout,
848 : int cache_refresh_percent,
849 : const char *domain,
850 : struct cache_req_input *input)
851 : {
852 53 : struct cache_req_state *state = NULL;
853 53 : struct tevent_req *req = NULL;
854 53 : struct tevent_req *subreq = NULL;
855 : errno_t ret;
856 :
857 53 : req = tevent_req_create(mem_ctx, &state, struct cache_req_state);
858 53 : if (req == NULL) {
859 0 : DEBUG(SSSDBG_CRIT_FAILURE, ("tevent_req_create() failed\n"));
860 0 : return NULL;
861 : }
862 :
863 53 : state->ev = ev;
864 53 : state->rctx = rctx;
865 53 : state->ncache = ncache;
866 53 : state->neg_timeout = neg_timeout;
867 53 : state->cache_refresh_percent = cache_refresh_percent;
868 53 : state->input = input;
869 :
870 53 : if (state->input->orig_name != NULL && domain == NULL) {
871 : /* Parse input name first, since it may contain domain name. */
872 14 : subreq = sss_parse_inp_send(state, rctx, input->orig_name);
873 14 : if (subreq == NULL) {
874 0 : ret = ENOMEM;
875 0 : goto immediately;
876 : }
877 :
878 14 : tevent_req_set_callback(subreq, cache_req_input_parsed, req);
879 : } else {
880 39 : if (input->orig_name != NULL) {
881 17 : ret = cache_req_input_set_name(input, input->orig_name);
882 17 : if (ret != EOK) {
883 0 : goto immediately;
884 : }
885 : }
886 :
887 39 : ret = cache_req_select_domains(req, domain);
888 39 : if (ret != EAGAIN) {
889 0 : goto immediately;
890 : }
891 : }
892 :
893 53 : return req;
894 :
895 : immediately:
896 0 : if (ret == EOK) {
897 0 : tevent_req_done(req);
898 : } else {
899 0 : tevent_req_error(req, ret);
900 : }
901 0 : tevent_req_post(req, ev);
902 :
903 0 : return req;
904 : }
905 :
906 14 : static void cache_req_input_parsed(struct tevent_req *subreq)
907 : {
908 : struct tevent_req *req;
909 : struct cache_req_state *state;
910 : char *name;
911 : char *domain;
912 : errno_t ret;
913 : bool maybe_upn;
914 :
915 14 : req = tevent_req_callback_data(subreq, struct tevent_req);
916 14 : state = tevent_req_data(req, struct cache_req_state);
917 :
918 14 : ret = sss_parse_inp_recv(subreq, state, &name, &domain);
919 14 : switch (ret) {
920 : case EOK:
921 6 : ret = cache_req_input_set_name(state->input, name);
922 6 : if (ret != EOK) {
923 0 : tevent_req_error(req, ret);
924 0 : return;
925 : }
926 6 : break;
927 : case ERR_DOMAIN_NOT_FOUND:
928 8 : maybe_upn = cache_req_input_assume_upn(state->input);
929 8 : if (!maybe_upn) {
930 0 : tevent_req_error(req, ret);
931 0 : return;
932 : }
933 :
934 8 : domain = NULL;
935 8 : break;
936 : default:
937 0 : tevent_req_error(req, ret);
938 0 : return;
939 : }
940 :
941 14 : ret = cache_req_select_domains(req, domain);
942 14 : if (ret != EAGAIN) {
943 0 : tevent_req_error(req, ret);
944 0 : return;
945 : }
946 : }
947 :
948 53 : static errno_t cache_req_select_domains(struct tevent_req *req,
949 : const char *domain)
950 : {
951 53 : struct cache_req_state *state = NULL;
952 :
953 53 : state = tevent_req_data(req, struct cache_req_state);
954 :
955 53 : if (domain != NULL) {
956 : /* single-domain search */
957 31 : state->domain = responder_get_domain(state->rctx, domain);
958 31 : if (state->domain == NULL) {
959 0 : return ERR_DOMAIN_NOT_FOUND;
960 : }
961 :
962 31 : state->check_next = false;
963 : } else {
964 : /* multi-domain search */
965 22 : state->domain = state->rctx->domains;
966 22 : state->check_next = true;
967 : }
968 :
969 53 : return cache_req_next_domain(req);
970 : }
971 :
972 92 : static errno_t cache_req_next_domain(struct tevent_req *req)
973 : {
974 92 : struct cache_req_state *state = NULL;
975 92 : struct tevent_req *subreq = NULL;
976 : errno_t ret;
977 :
978 92 : state = tevent_req_data(req, struct cache_req_state);
979 :
980 92 : while (state->domain != NULL) {
981 : /* If it is a domainless search, skip domains that require fully
982 : * qualified names instead. */
983 166 : while (state->domain != NULL && state->check_next
984 52 : && state->domain->fqnames
985 0 : && !cache_req_input_is_upn(state->input)) {
986 0 : state->domain = get_next_domain(state->domain, false);
987 : }
988 :
989 83 : state->selected_domain = state->domain;
990 :
991 83 : if (state->domain == NULL) {
992 0 : break;
993 : }
994 :
995 83 : ret = cache_req_input_set_domain(state->input, state->domain,
996 : state->rctx);
997 83 : if (ret != EOK) {
998 0 : return ret;
999 : }
1000 :
1001 83 : subreq = cache_req_cache_send(state, state->ev, state->rctx,
1002 : state->ncache, state->neg_timeout,
1003 : state->cache_refresh_percent,
1004 : state->input);
1005 83 : if (subreq == NULL) {
1006 0 : return ENOMEM;
1007 : }
1008 :
1009 83 : tevent_req_set_callback(subreq, cache_req_done, req);
1010 :
1011 : /* we will continue with the following domain the next time */
1012 83 : if (state->check_next) {
1013 52 : if (cache_req_input_is_upn(state->input)) {
1014 14 : state->domain = get_next_domain(state->domain, true);
1015 : } else {
1016 38 : state->domain = get_next_domain(state->domain, false);
1017 : }
1018 : }
1019 :
1020 83 : return EAGAIN;
1021 : }
1022 :
1023 : /* If the object searched has to be unique among all maintained domains,
1024 : * we have to add it into negative cache here when all domains have
1025 : * been searched. */
1026 :
1027 9 : cache_req_add_to_ncache_global(state->input, state->ncache);
1028 :
1029 9 : return ENOENT;
1030 : }
1031 :
1032 83 : static void cache_req_done(struct tevent_req *subreq)
1033 : {
1034 83 : struct cache_req_state *state = NULL;
1035 83 : struct tevent_req *req = NULL;
1036 : errno_t ret;
1037 :
1038 83 : req = tevent_req_callback_data(subreq, struct tevent_req);
1039 83 : state = tevent_req_data(req, struct cache_req_state);
1040 :
1041 83 : ret = cache_req_cache_recv(state, subreq, &state->result);
1042 83 : talloc_zfree(subreq);
1043 83 : if (ret == EOK) {
1044 32 : tevent_req_done(req);
1045 32 : return;
1046 : }
1047 :
1048 51 : if (state->check_next == false) {
1049 12 : if (ret == ENOENT && cache_req_input_assume_upn(state->input)) {
1050 : /* search by upn now */
1051 0 : cache_req_select_domains(req, NULL);
1052 0 : return;
1053 : }
1054 :
1055 12 : tevent_req_error(req, ret);
1056 12 : return;
1057 : }
1058 :
1059 39 : ret = cache_req_next_domain(req);
1060 39 : if (ret != EAGAIN) {
1061 9 : tevent_req_error(req, ret);
1062 : }
1063 :
1064 39 : return;
1065 : }
1066 :
1067 53 : errno_t cache_req_recv(TALLOC_CTX *mem_ctx,
1068 : struct tevent_req *req,
1069 : struct ldb_result **_result,
1070 : struct sss_domain_info **_domain,
1071 : char **_name)
1072 : {
1073 53 : struct cache_req_state *state = NULL;
1074 : char *name;
1075 :
1076 53 : state = tevent_req_data(req, struct cache_req_state);
1077 :
1078 74 : TEVENT_REQ_RETURN_ON_ERROR(req);
1079 :
1080 32 : if (_name != NULL) {
1081 17 : if (state->input->dom_objname == NULL) {
1082 0 : *_name = NULL;
1083 : } else {
1084 17 : name = talloc_strdup(mem_ctx, state->input->name);
1085 17 : if (name == NULL) {
1086 0 : return ENOMEM;
1087 : }
1088 :
1089 17 : *_name = name;
1090 : }
1091 : }
1092 :
1093 32 : if (_result != NULL) {
1094 32 : *_result = talloc_steal(mem_ctx, state->result);
1095 : }
1096 :
1097 32 : if (_domain != NULL) {
1098 32 : *_domain = state->selected_domain;
1099 : }
1100 :
1101 32 : return EOK;
1102 : }
1103 :
1104 : static struct tevent_req *
1105 53 : cache_req_steal_input_and_send(TALLOC_CTX *mem_ctx,
1106 : struct tevent_context *ev,
1107 : struct resp_ctx *rctx,
1108 : struct sss_nc_ctx *ncache,
1109 : int neg_timeout,
1110 : int cache_refresh_percent,
1111 : const char *domain,
1112 : struct cache_req_input *input)
1113 : {
1114 : struct tevent_req *req;
1115 :
1116 53 : req = cache_req_send(mem_ctx, ev, rctx, ncache, neg_timeout,
1117 : cache_refresh_percent, domain, input);
1118 53 : if (req == NULL) {
1119 0 : talloc_zfree(input);
1120 : }
1121 :
1122 53 : talloc_steal(req, input);
1123 :
1124 53 : return req;
1125 : }
1126 :
1127 : struct tevent_req *
1128 17 : cache_req_user_by_name_send(TALLOC_CTX *mem_ctx,
1129 : struct tevent_context *ev,
1130 : struct resp_ctx *rctx,
1131 : struct sss_nc_ctx *ncache,
1132 : int neg_timeout,
1133 : int cache_refresh_percent,
1134 : const char *domain,
1135 : const char *name)
1136 : {
1137 : struct cache_req_input *input;
1138 :
1139 17 : input = cache_req_input_create(mem_ctx, CACHE_REQ_USER_BY_NAME, name, 0,
1140 : NULL);
1141 17 : if (input == NULL) {
1142 0 : return NULL;
1143 : }
1144 :
1145 17 : return cache_req_steal_input_and_send(mem_ctx, ev, rctx, ncache,
1146 : neg_timeout, cache_refresh_percent,
1147 : domain, input);
1148 : }
1149 :
1150 : struct tevent_req *
1151 8 : cache_req_user_by_id_send(TALLOC_CTX *mem_ctx,
1152 : struct tevent_context *ev,
1153 : struct resp_ctx *rctx,
1154 : struct sss_nc_ctx *ncache,
1155 : int neg_timeout,
1156 : int cache_refresh_percent,
1157 : const char *domain,
1158 : uid_t uid)
1159 : {
1160 : struct cache_req_input *input;
1161 :
1162 8 : input = cache_req_input_create(mem_ctx, CACHE_REQ_USER_BY_ID, NULL, uid,
1163 : NULL);
1164 8 : if (input == NULL) {
1165 0 : return NULL;
1166 : }
1167 :
1168 8 : return cache_req_steal_input_and_send(mem_ctx, ev, rctx, ncache,
1169 : neg_timeout, cache_refresh_percent,
1170 : domain, input);
1171 : }
1172 :
1173 : struct tevent_req *
1174 6 : cache_req_user_by_cert_send(TALLOC_CTX *mem_ctx,
1175 : struct tevent_context *ev,
1176 : struct resp_ctx *rctx,
1177 : struct sss_nc_ctx *ncache,
1178 : int neg_timeout,
1179 : int cache_refresh_percent,
1180 : const char *domain,
1181 : const char *pem_cert)
1182 : {
1183 : struct cache_req_input *input;
1184 :
1185 6 : input = cache_req_input_create(mem_ctx, CACHE_REQ_USER_BY_CERT,
1186 : NULL, 0, pem_cert);
1187 6 : if (input == NULL) {
1188 0 : return NULL;
1189 : }
1190 :
1191 6 : return cache_req_steal_input_and_send(mem_ctx, ev, rctx, ncache,
1192 : neg_timeout, cache_refresh_percent,
1193 : domain, input);
1194 : }
1195 :
1196 : struct tevent_req *
1197 9 : cache_req_group_by_name_send(TALLOC_CTX *mem_ctx,
1198 : struct tevent_context *ev,
1199 : struct resp_ctx *rctx,
1200 : struct sss_nc_ctx *ncache,
1201 : int neg_timeout,
1202 : int cache_refresh_percent,
1203 : const char *domain,
1204 : const char *name)
1205 : {
1206 : struct cache_req_input *input;
1207 :
1208 9 : input = cache_req_input_create(mem_ctx, CACHE_REQ_GROUP_BY_NAME, name, 0,
1209 : NULL);
1210 9 : if (input == NULL) {
1211 0 : return NULL;
1212 : }
1213 :
1214 9 : return cache_req_steal_input_and_send(mem_ctx, ev, rctx, ncache,
1215 : neg_timeout, cache_refresh_percent,
1216 : domain, input);
1217 : }
1218 :
1219 : struct tevent_req *
1220 8 : cache_req_group_by_id_send(TALLOC_CTX *mem_ctx,
1221 : struct tevent_context *ev,
1222 : struct resp_ctx *rctx,
1223 : struct sss_nc_ctx *ncache,
1224 : int neg_timeout,
1225 : int cache_refresh_percent,
1226 : const char *domain,
1227 : gid_t gid)
1228 : {
1229 : struct cache_req_input *input;
1230 :
1231 8 : input = cache_req_input_create(mem_ctx, CACHE_REQ_GROUP_BY_ID, NULL, gid,
1232 : NULL);
1233 8 : if (input == NULL) {
1234 0 : return NULL;
1235 : }
1236 :
1237 8 : return cache_req_steal_input_and_send(mem_ctx, ev, rctx, ncache,
1238 : neg_timeout, cache_refresh_percent,
1239 : domain, input);
1240 : }
1241 :
1242 : struct tevent_req *
1243 0 : cache_req_initgr_by_name_send(TALLOC_CTX *mem_ctx,
1244 : struct tevent_context *ev,
1245 : struct resp_ctx *rctx,
1246 : struct sss_nc_ctx *ncache,
1247 : int neg_timeout,
1248 : int cache_refresh_percent,
1249 : const char *domain,
1250 : const char *name)
1251 : {
1252 : struct cache_req_input *input;
1253 :
1254 0 : input = cache_req_input_create(mem_ctx, CACHE_REQ_INITGROUPS, name, 0,
1255 : NULL);
1256 0 : if (input == NULL) {
1257 0 : return NULL;
1258 : }
1259 :
1260 0 : return cache_req_steal_input_and_send(mem_ctx, ev, rctx, ncache,
1261 : neg_timeout, cache_refresh_percent,
1262 : domain, input);
1263 : }
1264 :
1265 : struct tevent_req *
1266 3 : cache_req_user_by_filter_send(TALLOC_CTX *mem_ctx,
1267 : struct tevent_context *ev,
1268 : struct resp_ctx *rctx,
1269 : const char *domain,
1270 : const char *filter)
1271 : {
1272 : struct cache_req_input *input;
1273 :
1274 3 : input = cache_req_input_create(mem_ctx, CACHE_REQ_USER_BY_FILTER,
1275 : filter, 0, NULL);
1276 3 : if (input == NULL) {
1277 0 : return NULL;
1278 : }
1279 :
1280 3 : return cache_req_steal_input_and_send(mem_ctx, ev, rctx, NULL,
1281 : 0, 0, domain, input);
1282 : }
1283 :
1284 : struct tevent_req *
1285 2 : cache_req_group_by_filter_send(TALLOC_CTX *mem_ctx,
1286 : struct tevent_context *ev,
1287 : struct resp_ctx *rctx,
1288 : const char *domain,
1289 : const char *filter)
1290 : {
1291 : struct cache_req_input *input;
1292 :
1293 2 : input = cache_req_input_create(mem_ctx, CACHE_REQ_GROUP_BY_FILTER,
1294 : filter, 0, NULL);
1295 2 : if (input == NULL) {
1296 0 : return NULL;
1297 : }
1298 :
1299 2 : return cache_req_steal_input_and_send(mem_ctx, ev, rctx, NULL,
1300 : 0, 0, domain, input);
1301 : }
|