Line data Source code
1 : /*
2 : SSSD
3 :
4 : proxy_init.c
5 :
6 : Authors:
7 : Stephen Gallagher <sgallagh@redhat.com>
8 :
9 : Copyright (C) 2010 Red Hat
10 :
11 : This program is free software; you can redistribute it and/or modify
12 : it under the terms of the GNU General Public License as published by
13 : the Free Software Foundation; either version 3 of the License, or
14 : (at your option) any later version.
15 :
16 : This program is distributed in the hope that it will be useful,
17 : but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : GNU General Public License for more details.
20 :
21 : You should have received a copy of the GNU General Public License
22 : along with this program. If not, see <http://www.gnu.org/licenses/>.
23 : */
24 :
25 : #include "config.h"
26 :
27 : #include "util/sss_format.h"
28 : #include "providers/proxy/proxy.h"
29 :
30 : static int client_registration(struct sbus_request *dbus_req, void *data);
31 :
32 : static struct data_provider_iface proxy_methods = {
33 : { &data_provider_iface_meta, 0 },
34 : .RegisterService = client_registration,
35 : .pamHandler = NULL,
36 : .sudoHandler = NULL,
37 : .autofsHandler = NULL,
38 : .hostHandler = NULL,
39 : .getDomains = NULL,
40 : .getAccountInfo = NULL,
41 : };
42 :
43 0 : static void proxy_shutdown(struct be_req *req)
44 : {
45 : /* TODO: Clean up any internal data */
46 0 : be_req_terminate(req, DP_ERR_OK, EOK, NULL);
47 0 : }
48 :
49 0 : static void proxy_auth_shutdown(struct be_req *req)
50 : {
51 0 : struct be_ctx *be_ctx = be_req_get_be_ctx(req);
52 0 : talloc_free(be_ctx->bet_info[BET_AUTH].pvt_bet_data);
53 0 : be_req_terminate(req, DP_ERR_OK, EOK, NULL);
54 0 : }
55 :
56 : struct bet_ops proxy_id_ops = {
57 : .handler = proxy_get_account_info,
58 : .finalize = proxy_shutdown,
59 : .check_online = NULL
60 : };
61 :
62 : struct bet_ops proxy_auth_ops = {
63 : .handler = proxy_pam_handler,
64 : .finalize = proxy_auth_shutdown
65 : };
66 :
67 : struct bet_ops proxy_access_ops = {
68 : .handler = proxy_pam_handler,
69 : .finalize = proxy_auth_shutdown
70 : };
71 :
72 : struct bet_ops proxy_chpass_ops = {
73 : .handler = proxy_pam_handler,
74 : .finalize = proxy_auth_shutdown
75 : };
76 :
77 0 : static void *proxy_dlsym(void *handle, const char *functemp, char *libname)
78 : {
79 : char *funcname;
80 : void *funcptr;
81 :
82 0 : funcname = talloc_asprintf(NULL, functemp, libname);
83 0 : if (funcname == NULL) return NULL;
84 :
85 0 : funcptr = dlsym(handle, funcname);
86 0 : talloc_free(funcname);
87 :
88 0 : return funcptr;
89 : }
90 :
91 0 : int sssm_proxy_id_init(struct be_ctx *bectx,
92 : struct bet_ops **ops, void **pvt_data)
93 : {
94 : struct proxy_id_ctx *ctx;
95 : char *libname;
96 : char *libpath;
97 : int ret;
98 :
99 0 : ctx = talloc_zero(bectx, struct proxy_id_ctx);
100 0 : if (!ctx) {
101 0 : return ENOMEM;
102 : }
103 0 : ctx->be = bectx;
104 :
105 0 : ret = confdb_get_string(bectx->cdb, ctx, bectx->conf_path,
106 : CONFDB_PROXY_LIBNAME, NULL, &libname);
107 0 : if (ret != EOK) goto done;
108 0 : if (libname == NULL) {
109 0 : ret = ENOENT;
110 0 : goto done;
111 : }
112 :
113 0 : ret = confdb_get_bool(bectx->cdb, bectx->conf_path,
114 : CONFDB_PROXY_FAST_ALIAS, false, &ctx->fast_alias);
115 0 : if (ret != EOK) goto done;
116 :
117 0 : libpath = talloc_asprintf(ctx, "libnss_%s.so.2", libname);
118 0 : if (!libpath) {
119 0 : ret = ENOMEM;
120 0 : goto done;
121 : }
122 :
123 0 : ctx->handle = dlopen(libpath, RTLD_NOW);
124 0 : if (!ctx->handle) {
125 0 : DEBUG(SSSDBG_FATAL_FAILURE,
126 : "Unable to load %s module with path, error: %s\n",
127 : libpath, dlerror());
128 0 : ret = ELIBACC;
129 0 : goto done;
130 : }
131 :
132 0 : ctx->ops.getpwnam_r = proxy_dlsym(ctx->handle, "_nss_%s_getpwnam_r",
133 : libname);
134 0 : if (!ctx->ops.getpwnam_r) {
135 0 : DEBUG(SSSDBG_FATAL_FAILURE,
136 : "Failed to load NSS fns, error: %s\n", dlerror());
137 0 : ret = ELIBBAD;
138 0 : goto done;
139 : }
140 :
141 0 : ctx->ops.getpwuid_r = proxy_dlsym(ctx->handle, "_nss_%s_getpwuid_r",
142 : libname);
143 0 : if (!ctx->ops.getpwuid_r) {
144 0 : DEBUG(SSSDBG_FATAL_FAILURE,
145 : "Failed to load NSS fns, error: %s\n", dlerror());
146 0 : ret = ELIBBAD;
147 0 : goto done;
148 : }
149 :
150 0 : ctx->ops.setpwent = proxy_dlsym(ctx->handle, "_nss_%s_setpwent", libname);
151 0 : if (!ctx->ops.setpwent) {
152 0 : DEBUG(SSSDBG_FATAL_FAILURE,
153 : "Failed to load NSS fns, error: %s\n", dlerror());
154 0 : ret = ELIBBAD;
155 0 : goto done;
156 : }
157 :
158 0 : ctx->ops.getpwent_r = proxy_dlsym(ctx->handle, "_nss_%s_getpwent_r",
159 : libname);
160 0 : if (!ctx->ops.getpwent_r) {
161 0 : DEBUG(SSSDBG_FATAL_FAILURE,
162 : "Failed to load NSS fns, error: %s\n", dlerror());
163 0 : ret = ELIBBAD;
164 0 : goto done;
165 : }
166 :
167 0 : ctx->ops.endpwent = proxy_dlsym(ctx->handle, "_nss_%s_endpwent", libname);
168 0 : if (!ctx->ops.endpwent) {
169 0 : DEBUG(SSSDBG_FATAL_FAILURE,
170 : "Failed to load NSS fns, error: %s\n", dlerror());
171 0 : ret = ELIBBAD;
172 0 : goto done;
173 : }
174 :
175 0 : ctx->ops.getgrnam_r = proxy_dlsym(ctx->handle, "_nss_%s_getgrnam_r",
176 : libname);
177 0 : if (!ctx->ops.getgrnam_r) {
178 0 : DEBUG(SSSDBG_FATAL_FAILURE,
179 : "Failed to load NSS fns, error: %s\n", dlerror());
180 0 : ret = ELIBBAD;
181 0 : goto done;
182 : }
183 :
184 0 : ctx->ops.getgrgid_r = proxy_dlsym(ctx->handle, "_nss_%s_getgrgid_r",
185 : libname);
186 0 : if (!ctx->ops.getgrgid_r) {
187 0 : DEBUG(SSSDBG_FATAL_FAILURE,
188 : "Failed to load NSS fns, error: %s\n", dlerror());
189 0 : ret = ELIBBAD;
190 0 : goto done;
191 : }
192 :
193 0 : ctx->ops.setgrent = proxy_dlsym(ctx->handle, "_nss_%s_setgrent", libname);
194 0 : if (!ctx->ops.setgrent) {
195 0 : DEBUG(SSSDBG_FATAL_FAILURE,
196 : "Failed to load NSS fns, error: %s\n", dlerror());
197 0 : ret = ELIBBAD;
198 0 : goto done;
199 : }
200 :
201 0 : ctx->ops.getgrent_r = proxy_dlsym(ctx->handle, "_nss_%s_getgrent_r",
202 : libname);
203 0 : if (!ctx->ops.getgrent_r) {
204 0 : DEBUG(SSSDBG_FATAL_FAILURE,
205 : "Failed to load NSS fns, error: %s\n", dlerror());
206 0 : ret = ELIBBAD;
207 0 : goto done;
208 : }
209 :
210 0 : ctx->ops.endgrent = proxy_dlsym(ctx->handle, "_nss_%s_endgrent", libname);
211 0 : if (!ctx->ops.endgrent) {
212 0 : DEBUG(SSSDBG_FATAL_FAILURE,
213 : "Failed to load NSS fns, error: %s\n", dlerror());
214 0 : ret = ELIBBAD;
215 0 : goto done;
216 : }
217 :
218 0 : ctx->ops.initgroups_dyn = proxy_dlsym(ctx->handle, "_nss_%s_initgroups_dyn",
219 : libname);
220 0 : if (!ctx->ops.initgroups_dyn) {
221 0 : DEBUG(SSSDBG_CRIT_FAILURE, "The '%s' library does not provides the "
222 : "_nss_XXX_initgroups_dyn function!\n"
223 : "initgroups will be slow as it will require "
224 : "full groups enumeration!\n", libname);
225 : }
226 :
227 0 : ctx->ops.setnetgrent = proxy_dlsym(ctx->handle, "_nss_%s_setnetgrent",
228 : libname);
229 0 : if (!ctx->ops.setnetgrent) {
230 0 : DEBUG(SSSDBG_FATAL_FAILURE,
231 : "Failed to load _nss_%s_setnetgrent, error: %s. "
232 : "The library does not support netgroups.\n", libname,
233 : dlerror());
234 : }
235 :
236 0 : ctx->ops.getnetgrent_r = proxy_dlsym(ctx->handle, "_nss_%s_getnetgrent_r",
237 : libname);
238 0 : if (!ctx->ops.getgrent_r) {
239 0 : DEBUG(SSSDBG_FATAL_FAILURE,
240 : "Failed to load _nss_%s_getnetgrent_r, error: %s. "
241 : "The library does not support netgroups.\n", libname,
242 : dlerror());
243 : }
244 :
245 0 : ctx->ops.endnetgrent = proxy_dlsym(ctx->handle, "_nss_%s_endnetgrent",
246 : libname);
247 0 : if (!ctx->ops.endnetgrent) {
248 0 : DEBUG(SSSDBG_FATAL_FAILURE,
249 : "Failed to load _nss_%s_endnetgrent, error: %s. "
250 : "The library does not support netgroups.\n", libname,
251 : dlerror());
252 : }
253 :
254 0 : ctx->ops.getservbyname_r = proxy_dlsym(ctx->handle,
255 : "_nss_%s_getservbyname_r",
256 : libname);
257 0 : if (!ctx->ops.getservbyname_r) {
258 0 : DEBUG(SSSDBG_MINOR_FAILURE,
259 : "Failed to load _nss_%s_getservbyname_r, error: %s. "
260 : "The library does not support services.\n",
261 : libname,
262 : dlerror());
263 : }
264 :
265 0 : ctx->ops.getservbyport_r = proxy_dlsym(ctx->handle,
266 : "_nss_%s_getservbyport_r",
267 : libname);
268 0 : if (!ctx->ops.getservbyport_r) {
269 0 : DEBUG(SSSDBG_MINOR_FAILURE,
270 : "Failed to load _nss_%s_getservbyport_r, error: %s. "
271 : "The library does not support services.\n",
272 : libname,
273 : dlerror());
274 : }
275 :
276 0 : ctx->ops.setservent = proxy_dlsym(ctx->handle,
277 : "_nss_%s_setservent",
278 : libname);
279 0 : if (!ctx->ops.setservent) {
280 0 : DEBUG(SSSDBG_MINOR_FAILURE,
281 : "Failed to load _nss_%s_setservent, error: %s. "
282 : "The library does not support services.\n",
283 : libname,
284 : dlerror());
285 : }
286 :
287 0 : ctx->ops.getservent_r = proxy_dlsym(ctx->handle,
288 : "_nss_%s_getservent_r",
289 : libname);
290 0 : if (!ctx->ops.getservent_r) {
291 0 : DEBUG(SSSDBG_MINOR_FAILURE,
292 : "Failed to load _nss_%s_getservent_r, error: %s. "
293 : "The library does not support services.\n",
294 : libname,
295 : dlerror());
296 : }
297 :
298 0 : ctx->ops.endservent = proxy_dlsym(ctx->handle,
299 : "_nss_%s_endservent",
300 : libname);
301 0 : if (!ctx->ops.endservent) {
302 0 : DEBUG(SSSDBG_MINOR_FAILURE,
303 : "Failed to load _nss_%s_endservent, error: %s. "
304 : "The library does not support services.\n",
305 : libname,
306 : dlerror());
307 : }
308 :
309 0 : *ops = &proxy_id_ops;
310 0 : *pvt_data = ctx;
311 0 : ret = EOK;
312 :
313 : done:
314 0 : if (ret != EOK) {
315 0 : talloc_free(ctx);
316 : }
317 0 : return ret;
318 : }
319 :
320 : struct proxy_client {
321 : struct proxy_auth_ctx *proxy_auth_ctx;
322 : struct sbus_connection *conn;
323 : struct tevent_timer *timeout;
324 : bool initialized;
325 : };
326 :
327 : static void init_timeout(struct tevent_context *ev,
328 : struct tevent_timer *te,
329 : struct timeval t, void *ptr);
330 0 : static int proxy_client_init(struct sbus_connection *conn, void *data)
331 : {
332 : struct proxy_auth_ctx *proxy_auth_ctx;
333 : struct proxy_client *proxy_cli;
334 : struct timeval tv;
335 :
336 0 : proxy_auth_ctx = talloc_get_type(data, struct proxy_auth_ctx);
337 :
338 : /* hang off this memory to the connection so that when the connection
339 : * is freed we can potentially call a destructor */
340 :
341 0 : proxy_cli = talloc_zero(conn, struct proxy_client);
342 0 : if (!proxy_cli) {
343 0 : DEBUG(SSSDBG_FATAL_FAILURE,"Out of memory?!\n");
344 0 : talloc_zfree(conn);
345 0 : return ENOMEM;
346 : }
347 0 : proxy_cli->proxy_auth_ctx = proxy_auth_ctx;
348 0 : proxy_cli->conn = conn;
349 0 : proxy_cli->initialized = false;
350 :
351 : /* 5 seconds should be plenty */
352 0 : tv = tevent_timeval_current_ofs(5, 0);
353 :
354 0 : proxy_cli->timeout = tevent_add_timer(proxy_auth_ctx->be->ev, proxy_cli,
355 : tv, init_timeout, proxy_cli);
356 0 : if (!proxy_cli->timeout) {
357 0 : DEBUG(SSSDBG_FATAL_FAILURE,"Out of memory?!\n");
358 0 : talloc_zfree(conn);
359 0 : return ENOMEM;
360 : }
361 0 : DEBUG(SSSDBG_CONF_SETTINGS,
362 : "Set-up proxy client ID timeout [%p]\n", proxy_cli->timeout);
363 :
364 0 : return sbus_conn_register_iface(conn, &proxy_methods.vtable,
365 : DP_PATH, proxy_cli);
366 : }
367 :
368 0 : static void init_timeout(struct tevent_context *ev,
369 : struct tevent_timer *te,
370 : struct timeval t, void *ptr)
371 : {
372 : struct proxy_client *proxy_cli;
373 :
374 0 : DEBUG(SSSDBG_OP_FAILURE,
375 : "Client timed out before Identification [%p]!\n", te);
376 :
377 0 : proxy_cli = talloc_get_type(ptr, struct proxy_client);
378 :
379 0 : sbus_disconnect(proxy_cli->conn);
380 0 : talloc_zfree(proxy_cli);
381 :
382 : /* If we time out here, we will also time out to
383 : * pc_init_timeout(), so we'll finish the request
384 : * there.
385 : */
386 0 : }
387 :
388 0 : static int client_registration(struct sbus_request *dbus_req, void *data)
389 : {
390 0 : dbus_uint16_t version = DATA_PROVIDER_VERSION;
391 : struct sbus_connection *conn;
392 : struct proxy_client *proxy_cli;
393 : dbus_uint16_t cli_ver;
394 : uint32_t cli_id;
395 : int hret;
396 : hash_key_t key;
397 : hash_value_t value;
398 : struct tevent_req *req;
399 : struct proxy_child_ctx *child_ctx;
400 : struct pc_init_ctx *init_ctx;
401 : int ret;
402 :
403 0 : conn = dbus_req->conn;
404 0 : proxy_cli = talloc_get_type(data, struct proxy_client);
405 0 : if (!proxy_cli) {
406 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Connection holds no valid init data\n");
407 0 : return EINVAL;
408 : }
409 :
410 : /* First thing, cancel the timeout */
411 0 : DEBUG(SSSDBG_CONF_SETTINGS,
412 : "Cancel proxy client ID timeout [%p]\n", proxy_cli->timeout);
413 0 : talloc_zfree(proxy_cli->timeout);
414 :
415 0 : if (!sbus_request_parse_or_finish(dbus_req,
416 : DBUS_TYPE_UINT16, &cli_ver,
417 : DBUS_TYPE_UINT32, &cli_id,
418 : DBUS_TYPE_INVALID)) {
419 0 : sbus_disconnect(conn);
420 0 : return EOK; /* handled */
421 : }
422 :
423 0 : DEBUG(SSSDBG_FUNC_DATA, "Proxy client [%"PRIu32"] connected\n", cli_id);
424 :
425 : /* Check the hash table */
426 0 : key.type = HASH_KEY_ULONG;
427 0 : key.ul = cli_id;
428 0 : if (!hash_has_key(proxy_cli->proxy_auth_ctx->request_table, &key)) {
429 0 : DEBUG(SSSDBG_CRIT_FAILURE,
430 : "Unknown child ID. Killing the connection\n");
431 0 : sbus_disconnect(proxy_cli->conn);
432 0 : return EIO;
433 : }
434 :
435 : /* reply that all is ok */
436 0 : ret = sbus_request_return_and_finish(dbus_req,
437 : DBUS_TYPE_UINT16, &version,
438 : DBUS_TYPE_INVALID);
439 0 : if (ret != EOK) {
440 0 : sbus_disconnect(conn);
441 0 : return ret;
442 : }
443 :
444 0 : hret = hash_lookup(proxy_cli->proxy_auth_ctx->request_table, &key, &value);
445 0 : if (hret != HASH_SUCCESS) {
446 0 : DEBUG(SSSDBG_CRIT_FAILURE,
447 : "Hash error [%d][%s]\n", hret, hash_error_string(hret));
448 0 : sbus_disconnect(conn);
449 : }
450 :
451 : /* Signal that the child is up and ready to receive the request */
452 0 : req = talloc_get_type(value.ptr, struct tevent_req);
453 0 : child_ctx = tevent_req_data(req, struct proxy_child_ctx);
454 :
455 0 : if (!child_ctx->running) {
456 : /* This should hopefully be impossible, but protect
457 : * against it anyway. If we're not marked running, then
458 : * the init_req will be NULL below and things will
459 : * break.
460 : */
461 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Client connection from a request "
462 : "that's not marked as running\n");
463 0 : return EIO;
464 : }
465 :
466 0 : init_ctx = tevent_req_data(child_ctx->init_req, struct pc_init_ctx);
467 0 : init_ctx->conn = conn;
468 0 : tevent_req_done(child_ctx->init_req);
469 0 : child_ctx->init_req = NULL;
470 :
471 0 : return EOK;
472 : }
473 :
474 0 : int sssm_proxy_auth_init(struct be_ctx *bectx,
475 : struct bet_ops **ops, void **pvt_data)
476 : {
477 : struct proxy_auth_ctx *ctx;
478 : int ret;
479 : int hret;
480 : char *sbus_address;
481 :
482 : /* If we're already set up, just return that */
483 0 : if(bectx->bet_info[BET_AUTH].mod_name &&
484 0 : strcmp("proxy", bectx->bet_info[BET_AUTH].mod_name) == 0) {
485 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
486 : "Re-using proxy_auth_ctx for this provider\n");
487 0 : *ops = bectx->bet_info[BET_AUTH].bet_ops;
488 0 : *pvt_data = bectx->bet_info[BET_AUTH].pvt_bet_data;
489 0 : return EOK;
490 : }
491 :
492 0 : ctx = talloc_zero(bectx, struct proxy_auth_ctx);
493 0 : if (!ctx) {
494 0 : return ENOMEM;
495 : }
496 0 : ctx->be = bectx;
497 0 : ctx->timeout_ms = SSS_CLI_SOCKET_TIMEOUT/4;
498 0 : ctx->next_id = 1;
499 :
500 0 : ret = confdb_get_string(bectx->cdb, ctx, bectx->conf_path,
501 : CONFDB_PROXY_PAM_TARGET, NULL,
502 : &ctx->pam_target);
503 0 : if (ret != EOK) goto done;
504 0 : if (!ctx->pam_target) {
505 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Missing option proxy_pam_target.\n");
506 0 : ret = EINVAL;
507 0 : goto done;
508 : }
509 :
510 0 : sbus_address = talloc_asprintf(ctx, "unix:path=%s/%s_%s", PIPE_PATH,
511 0 : PROXY_CHILD_PIPE, bectx->domain->name);
512 0 : if (sbus_address == NULL) {
513 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n");
514 0 : ret = ENOMEM;
515 0 : goto done;
516 : }
517 :
518 0 : ret = sbus_new_server(ctx, bectx->ev, sbus_address, 0, bectx->gid,
519 : false, &ctx->sbus_srv, proxy_client_init, ctx);
520 0 : if (ret != EOK) {
521 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Could not set up sbus server.\n");
522 0 : goto done;
523 : }
524 :
525 : /* Set up request hash table */
526 : /* FIXME: get max_children from configuration file */
527 0 : ctx->max_children = 10;
528 :
529 0 : hret = hash_create(ctx->max_children * 2, &ctx->request_table,
530 : NULL, NULL);
531 0 : if (hret != HASH_SUCCESS) {
532 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Could not initialize request table\n");
533 0 : ret = EIO;
534 0 : goto done;
535 : }
536 :
537 0 : *ops = &proxy_auth_ops;
538 0 : *pvt_data = ctx;
539 :
540 : done:
541 0 : if (ret != EOK) {
542 0 : talloc_free(ctx);
543 : }
544 0 : return ret;
545 : }
546 :
547 0 : int sssm_proxy_access_init(struct be_ctx *bectx,
548 : struct bet_ops **ops, void **pvt_data)
549 : {
550 : int ret;
551 0 : ret = sssm_proxy_auth_init(bectx, ops, pvt_data);
552 0 : *ops = &proxy_access_ops;
553 0 : return ret;
554 : }
555 :
556 0 : int sssm_proxy_chpass_init(struct be_ctx *bectx,
557 : struct bet_ops **ops, void **pvt_data)
558 : {
559 : int ret;
560 0 : ret = sssm_proxy_auth_init(bectx, ops, pvt_data);
561 0 : *ops = &proxy_chpass_ops;
562 0 : return ret;
563 : }
|