Line data Source code
1 : /*
2 : Authors:
3 : Pavel Březina <pbrezina@redhat.com>
4 :
5 : Copyright (C) 2016 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 <dlfcn.h>
23 :
24 : #include "config.h"
25 : #include "providers/data_provider/dp.h"
26 : #include "providers/data_provider/dp_private.h"
27 : #include "providers/data_provider/dp_builtin.h"
28 : #include "providers/backend.h"
29 : #include "util/util.h"
30 :
31 : #define DP_TARGET_INIT_FN "sssm_%s_%s_init"
32 :
33 : #define DP_PROVIDER_OPT "%s_provider"
34 : #define DP_ACCESS_PERMIT "permit"
35 : #define DP_ACCESS_DENY "deny"
36 : #define DP_NO_PROVIDER "none"
37 :
38 0 : bool _dp_target_enabled(struct data_provider *provider,
39 : const char *module_name,
40 : ...)
41 : {
42 : struct dp_target *target;
43 : enum dp_targets type;
44 : va_list ap;
45 : bool bret;
46 :
47 0 : if (provider == NULL || provider->targets == NULL) {
48 0 : return false;
49 : }
50 :
51 0 : bret = false;
52 0 : va_start(ap, module_name);
53 0 : while ((type = va_arg(ap, enum dp_targets)) != DP_TARGET_SENTINEL) {
54 0 : target = provider->targets[type];
55 0 : if (target == NULL || target->module_name == NULL) {
56 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Uninitialized target %s\n",
57 : dp_target_to_string(type));
58 0 : continue;
59 : }
60 :
61 0 : if (module_name == NULL) {
62 0 : bret = true;
63 0 : goto done;
64 : }
65 :
66 0 : if (strcmp(target->module_name, module_name) == 0) {
67 0 : bret = true;
68 0 : goto done;
69 : }
70 : }
71 :
72 : done:
73 0 : va_end(ap);
74 0 : return bret;
75 : }
76 :
77 0 : struct dp_module *dp_target_module(struct data_provider *provider,
78 : enum dp_targets target)
79 : {
80 0 : if (provider == NULL || provider->targets == NULL) {
81 0 : return NULL;
82 : }
83 :
84 0 : if (target >= DP_TARGET_SENTINEL || provider->targets[target] == NULL) {
85 0 : return NULL;
86 : }
87 :
88 0 : return provider->targets[target]->module;
89 : }
90 :
91 36 : const char *dp_target_to_string(enum dp_targets target)
92 : {
93 36 : switch (target) {
94 : case DPT_ID:
95 4 : return "id";
96 : case DPT_AUTH:
97 4 : return "auth";
98 : case DPT_ACCESS:
99 4 : return "access";
100 : case DPT_CHPASS:
101 4 : return "chpass";
102 : case DPT_SUDO:
103 4 : return "sudo";
104 : case DPT_AUTOFS:
105 4 : return "autofs";
106 : case DPT_SELINUX:
107 4 : return "selinux";
108 : case DPT_HOSTID:
109 4 : return "hostid";
110 : case DPT_SUBDOMAINS:
111 4 : return "subdomains";
112 : case DP_TARGET_SENTINEL:
113 0 : return NULL;
114 : }
115 :
116 0 : return NULL;
117 : }
118 :
119 5 : bool dp_target_initialized(struct dp_target **targets, enum dp_targets type)
120 : {
121 5 : if (targets == NULL || targets[type] == NULL) {
122 0 : return false;
123 : }
124 :
125 5 : return targets[type]->initialized;
126 : }
127 :
128 0 : static bool dp_target_sudo_enabled(struct be_ctx *be_ctx)
129 : {
130 : TALLOC_CTX *tmp_ctx;
131 : char **services;
132 : char *module;
133 : bool responder_enabled;
134 : bool enable;
135 : errno_t ret;
136 : int i;
137 :
138 : /* Do not disable it in case of error. */
139 0 : enable = true;
140 :
141 0 : tmp_ctx = talloc_new(NULL);
142 0 : if (tmp_ctx == NULL) {
143 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
144 0 : return enable;
145 : }
146 :
147 0 : ret = confdb_get_string_as_list(be_ctx->cdb, tmp_ctx,
148 : CONFDB_MONITOR_CONF_ENTRY,
149 : CONFDB_MONITOR_ACTIVE_SERVICES, &services);
150 0 : if (ret != EOK) {
151 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Unable to read from confdb [%d]: %s\n",
152 : ret, sss_strerror(ret));
153 0 : goto done;
154 : }
155 :
156 0 : responder_enabled = false;
157 0 : for (i = 0; services[i] != NULL; i++) {
158 0 : if (strcmp(services[i], "sudo") == 0) {
159 0 : responder_enabled = true;
160 0 : break;
161 : }
162 : }
163 :
164 0 : ret = confdb_get_string(be_ctx->cdb, tmp_ctx, be_ctx->conf_path,
165 : CONFDB_DOMAIN_SUDO_PROVIDER, NULL, &module);
166 0 : if (ret != EOK) {
167 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Unable to read from confdb [%d]: %s\n",
168 : ret, sss_strerror(ret));
169 0 : goto done;
170 : }
171 :
172 0 : if (!responder_enabled) {
173 0 : if (module == NULL) {
174 0 : DEBUG(SSSDBG_TRACE_FUNC, "SUDO is not listed in services, "
175 : "disabling SUDO module.\n");
176 0 : enable = false;
177 0 : goto done;
178 0 : } else if (strcmp(module, DP_NO_PROVIDER) != 0) {
179 0 : DEBUG(SSSDBG_MINOR_FAILURE, "SUDO provider is set, but it is not "
180 : "listed in active services. SUDO support will not work!\n");
181 0 : enable = true;
182 0 : goto done;
183 : }
184 : }
185 :
186 0 : enable = true;
187 :
188 : done:
189 0 : talloc_free(tmp_ctx);
190 0 : return enable;
191 : }
192 :
193 0 : static const char *dp_target_module_name(struct dp_target **targets,
194 : enum dp_targets type)
195 : {
196 0 : if (targets[type] == NULL) {
197 0 : return NULL;
198 : }
199 :
200 0 : return targets[type]->module_name;
201 : }
202 :
203 0 : static const char *dp_target_default_module(struct dp_target **targets,
204 : enum dp_targets target)
205 : {
206 0 : switch (target) {
207 : case DPT_ID:
208 0 : return NULL;
209 : case DPT_ACCESS:
210 0 : return "permit";
211 : case DPT_CHPASS:
212 0 : return dp_target_module_name(targets, DPT_AUTH);
213 : case DP_TARGET_SENTINEL:
214 0 : return NULL;
215 : default:
216 0 : return dp_target_module_name(targets, DPT_ID);
217 : }
218 : }
219 :
220 0 : static errno_t dp_target_run_constructor(struct dp_target *target,
221 : struct be_ctx *be_ctx)
222 : {
223 0 : char *fn_name = NULL;
224 : dp_target_init_fn fn;
225 : char *error;
226 : errno_t ret;
227 :
228 0 : fn_name = talloc_asprintf(target, DP_TARGET_INIT_FN,
229 0 : target->module->name, target->name);
230 0 : if (fn_name == NULL) {
231 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed\n");
232 0 : return ENOMEM;
233 : }
234 :
235 0 : dlerror(); /* clear any error */
236 0 : fn = (dp_target_init_fn)dlsym(target->module->libhandle, fn_name);
237 0 : if (fn != NULL) {
238 0 : DEBUG(SSSDBG_TRACE_FUNC, "Executing target [%s] constructor\n",
239 : target->name);
240 :
241 0 : ret = fn(target, be_ctx, target->module->module_data, target->methods);
242 0 : if (ret != EOK) {
243 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Target [%s] constructor failed "
244 : "[%d]: %s\n", target->name, ret, sss_strerror(ret));
245 0 : goto done;
246 : }
247 : } else {
248 0 : error = dlerror();
249 0 : if (error == NULL || !target->explicitly_configured) {
250 : /* Not found. */
251 0 : ret = ELIBBAD;
252 0 : goto done;
253 : } else {
254 : /* Error. */
255 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Unable to load target [%s] "
256 : "constructor: %s\n", target->name, error);
257 0 : ret = ELIBBAD;
258 0 : goto done;
259 : }
260 : }
261 :
262 0 : target->initialized = true;
263 0 : ret = EOK;
264 :
265 : done:
266 0 : talloc_free(fn_name);
267 0 : return ret;
268 : }
269 :
270 0 : static errno_t dp_target_special(struct be_ctx *be_ctx,
271 : struct dp_target *target,
272 : const char *module_name)
273 : {
274 0 : if (strcasecmp(module_name, DP_NO_PROVIDER) == 0) {
275 0 : DEBUG(SSSDBG_TRACE_FUNC, "Target [%s] is explicitly disabled.\n",
276 : target->name);
277 0 : target->initialized = false;
278 0 : target->module = NULL;
279 0 : return EOK;
280 : }
281 :
282 0 : if (target->target == DPT_ACCESS) {
283 0 : if (strcmp(module_name, DP_ACCESS_PERMIT) == 0) {
284 0 : dp_set_method(target->methods, DPM_ACCESS_HANDLER,
285 : dp_access_permit_handler_send, dp_access_permit_handler_recv, NULL,
286 : void, struct pam_data, struct pam_data *);
287 0 : target->module = NULL;
288 0 : target->initialized = true;
289 0 : return EOK;
290 : }
291 :
292 0 : if (strcmp(module_name, DP_ACCESS_DENY) == 0) {
293 0 : dp_set_method(target->methods, DPM_ACCESS_HANDLER,
294 : dp_access_deny_handler_send, dp_access_deny_handler_recv, NULL,
295 : void, struct pam_data, struct pam_data *);
296 0 : target->module = NULL;
297 0 : target->initialized = true;
298 0 : return EOK;
299 : }
300 : }
301 :
302 0 : if (target->target == DPT_SUDO) {
303 0 : if (dp_target_sudo_enabled(be_ctx)) {
304 0 : return EAGAIN;
305 : } else {
306 0 : target->module = NULL;
307 0 : target->initialized = false;
308 0 : return EOK;
309 : }
310 : }
311 :
312 0 : return EAGAIN;
313 : }
314 :
315 0 : static errno_t dp_target_init(struct be_ctx *be_ctx,
316 : struct data_provider *provider,
317 : struct dp_module **modules,
318 : struct dp_target *target)
319 : {
320 : errno_t ret;
321 :
322 0 : DEBUG(SSSDBG_TRACE_FUNC, "Initializing target [%s] with module [%s]\n",
323 : target->name, target->module_name);
324 :
325 : /* We have already name, module name and target set. We just load
326 : * the module and initialize it. */
327 :
328 0 : target->methods = talloc_zero_array(target, struct dp_method,
329 : DP_METHOD_SENTINEL + 1);
330 0 : if (target->methods == NULL) {
331 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero_array() failed\n");
332 0 : ret = ENOMEM;
333 0 : goto done;
334 : }
335 :
336 : /* Handle special cases that do not require opening a module. */
337 0 : ret = dp_target_special(be_ctx, target, target->module_name);
338 0 : if (ret == EOK || ret != EAGAIN) {
339 : goto done;
340 : }
341 :
342 : /* Load module first. Memory context is modules, not target here. */
343 0 : target->module = dp_load_module(modules, be_ctx, provider, modules,
344 : target->module_name);
345 0 : if (target->module == NULL) {
346 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Unable to load module %s\n",
347 : target->module_name);
348 0 : ret = ELIBBAD;
349 0 : goto done;
350 : }
351 :
352 : /* Run constructor. */
353 0 : ret = dp_target_run_constructor(target, be_ctx);
354 0 : if (!target->explicitly_configured && (ret == ELIBBAD || ret == ENOTSUP)) {
355 : /* Target not found but it wasn't explicitly
356 : * configured so we shall just continue. */
357 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Target [%s] is not supported by "
358 : "module [%s].\n", target->name, target->module_name);
359 0 : ret = EOK;
360 0 : goto done;
361 0 : } else if (ret != EOK) {
362 0 : goto done;
363 : }
364 :
365 0 : ret = EOK;
366 :
367 : done:
368 0 : if (ret != EOK) {
369 0 : talloc_free(target->methods);
370 : }
371 :
372 0 : return ret;
373 : }
374 :
375 0 : static char *dp_get_module_name(TALLOC_CTX *mem_ctx,
376 : struct confdb_ctx *confdb_ctx,
377 : const char *conf_path,
378 : struct dp_target **targets,
379 : enum dp_targets type,
380 : bool *_is_default)
381 : {
382 : const char *name;
383 : const char *default_module;
384 : char *module;
385 : char *option;
386 : errno_t ret;
387 :
388 0 : name = dp_target_to_string(type);
389 0 : if (name == NULL) {
390 0 : return NULL;
391 : }
392 :
393 0 : option = talloc_asprintf(mem_ctx, DP_PROVIDER_OPT, name);
394 0 : if (option == NULL) {
395 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed\n");
396 0 : return NULL;
397 : }
398 :
399 0 : ret = confdb_get_string(confdb_ctx, mem_ctx, conf_path,
400 : option, NULL, &module);
401 0 : talloc_free(option);
402 0 : if (ret != EOK) {
403 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to read provider value "
404 : "[%d]: %s\n", ret, sss_strerror(ret));
405 0 : return NULL;
406 : }
407 :
408 0 : if (module != NULL) {
409 0 : *_is_default = false;
410 0 : return module;
411 : }
412 :
413 0 : *_is_default = true;
414 0 : default_module = dp_target_default_module(targets, type);
415 :
416 0 : return talloc_strdup(mem_ctx, default_module);
417 : }
418 :
419 0 : static errno_t dp_load_configuration(struct confdb_ctx *cdb,
420 : const char *conf_path,
421 : struct dp_target **targets)
422 : {
423 : enum dp_targets type;
424 : const char *name;
425 : bool is_default;
426 : char *module;
427 : errno_t ret;
428 :
429 0 : for (type = 0; type < DP_TARGET_SENTINEL; type++) {
430 0 : name = dp_target_to_string(type);
431 0 : if (name == NULL) {
432 0 : ret = ERR_INTERNAL;
433 0 : goto done;
434 : }
435 :
436 0 : module = dp_get_module_name(NULL, cdb, conf_path, targets,
437 : type, &is_default);
438 0 : if (module == NULL) {
439 0 : DEBUG(SSSDBG_CONF_SETTINGS, "No provider is specified for"
440 : " [%s]\n", name);
441 0 : continue;
442 : } else {
443 0 : DEBUG(SSSDBG_CONF_SETTINGS, "Using [%s] provider for [%s]\n",
444 : module, name);
445 : }
446 :
447 0 : targets[type]->explicitly_configured = is_default == false;
448 0 : targets[type]->name = name;
449 0 : targets[type]->target = type;
450 0 : targets[type]->module_name = talloc_steal(targets[type], module);
451 : }
452 :
453 0 : ret = EOK;
454 :
455 : done:
456 0 : return ret;
457 : }
458 :
459 0 : static errno_t dp_load_targets(struct be_ctx *be_ctx,
460 : struct data_provider *provider,
461 : struct dp_target **targets,
462 : struct dp_module **modules)
463 : {
464 : enum dp_targets type;
465 : errno_t ret;
466 :
467 : /* We load the configuration first and store module name to each target.
468 : * This way we ensure that we have this information available during
469 : * module initialization. */
470 :
471 0 : ret = dp_load_configuration(be_ctx->cdb, be_ctx->conf_path, targets);
472 0 : if (ret != EOK) {
473 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to load DP configuration "
474 : "[%d]: %s\n", ret, sss_strerror(ret));
475 0 : goto done;
476 : }
477 :
478 0 : for (type = 0; type < DP_TARGET_SENTINEL; type++) {
479 0 : ret = dp_target_init(be_ctx, provider, modules, targets[type]);
480 0 : if (ret != EOK) {
481 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to load target [%s] "
482 : "[%d]: %s.\n", targets[type]->name, ret, sss_strerror(ret));
483 0 : ret = ERR_INTERNAL;
484 0 : goto done;
485 : }
486 : }
487 :
488 0 : ret = EOK;
489 :
490 : done:
491 0 : return ret;
492 : }
493 :
494 0 : errno_t dp_init_targets(TALLOC_CTX *mem_ctx,
495 : struct be_ctx *be_ctx,
496 : struct data_provider *provider,
497 : struct dp_module **modules)
498 : {
499 : struct dp_target **targets;
500 : enum dp_targets type;
501 : errno_t ret;
502 :
503 : /* Even though we know the exact number of targets we will allocate
504 : * them all dynamically so we can have correct talloc hierarchy where
505 : * all private data are attached to the target they belong to. */
506 :
507 0 : targets = talloc_zero_array(mem_ctx, struct dp_target *,
508 : DP_TARGET_SENTINEL + 1);
509 0 : if (targets == NULL) {
510 0 : ret = ENOMEM;
511 0 : goto done;
512 : }
513 :
514 0 : for (type = 0; type != DP_TARGET_SENTINEL; type++) {
515 0 : targets[type] = talloc_zero(targets, struct dp_target);
516 0 : if (targets[type] == NULL) {
517 0 : ret = ENOMEM;
518 0 : goto done;
519 : }
520 : }
521 :
522 : /* We want this to be already available. */
523 0 : provider->targets = targets;
524 :
525 0 : ret = dp_load_targets(be_ctx, provider, targets, modules);
526 :
527 : done:
528 0 : if (ret != EOK) {
529 0 : provider->targets = NULL;
530 0 : talloc_free(targets);
531 : }
532 :
533 0 : return ret;
534 : }
|