Line data Source code
1 : /*
2 : SSSD
3 :
4 : Common Responder methods
5 :
6 : Copyright (C) Simo Sorce <ssorce@redhat.com> 2008
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include "config.h"
23 :
24 : #include <stdio.h>
25 : #include <sys/types.h>
26 : #include <sys/stat.h>
27 : #include <sys/socket.h>
28 : #include <sys/un.h>
29 : #include <string.h>
30 : #include <sys/time.h>
31 : #include <errno.h>
32 : #include <popt.h>
33 : #include <dbus/dbus.h>
34 :
35 : #include "util/util.h"
36 : #include "util/strtonum.h"
37 : #include "db/sysdb.h"
38 : #include "confdb/confdb.h"
39 : #include "sbus/sssd_dbus.h"
40 : #include "responder/common/responder.h"
41 : #include "responder/common/responder_packet.h"
42 : #include "providers/data_provider.h"
43 : #include "monitor/monitor_interfaces.h"
44 : #include "sbus/sbus_client.h"
45 :
46 2 : static errno_t set_close_on_exec(int fd)
47 : {
48 : int v;
49 : int ferr;
50 : errno_t error;
51 :
52 : /* Get the current flags for this file descriptor */
53 2 : v = fcntl(fd, F_GETFD, 0);
54 :
55 2 : errno = 0;
56 : /* Set the close-on-exec flags on this fd */
57 2 : ferr = fcntl(fd, F_SETFD, v | FD_CLOEXEC);
58 2 : if (ferr < 0) {
59 0 : error = errno;
60 0 : DEBUG(SSSDBG_FATAL_FAILURE,
61 : "Unable to set fd close-on-exec: [%d][%s]\n",
62 : error, strerror(error));
63 0 : return error;
64 : }
65 2 : return EOK;
66 : }
67 :
68 0 : static int client_destructor(struct cli_ctx *ctx)
69 : {
70 : errno_t ret;
71 :
72 0 : if ((ctx->cfd > 0) && close(ctx->cfd) < 0) {
73 0 : ret = errno;
74 0 : DEBUG(SSSDBG_CRIT_FAILURE,
75 : "Failed to close fd [%d]: [%s]\n",
76 : ctx->cfd, strerror(ret));
77 : }
78 :
79 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
80 : "Terminated client [%p][%d]\n",
81 : ctx, ctx->cfd);
82 0 : return 0;
83 : }
84 :
85 0 : static errno_t get_client_cred(struct cli_ctx *cctx)
86 : {
87 0 : cctx->client_euid = -1;
88 0 : cctx->client_egid = -1;
89 0 : cctx->client_pid = -1;
90 :
91 : #ifdef HAVE_UCRED
92 : int ret;
93 : struct ucred client_cred;
94 0 : socklen_t client_cred_len = sizeof(client_cred);
95 :
96 0 : ret = getsockopt(cctx->cfd, SOL_SOCKET, SO_PEERCRED, &client_cred,
97 : &client_cred_len);
98 0 : if (ret != EOK) {
99 0 : ret = errno;
100 0 : DEBUG(SSSDBG_CRIT_FAILURE,
101 : "getsock failed [%d][%s].\n", ret, strerror(ret));
102 0 : return ret;
103 : }
104 0 : if (client_cred_len != sizeof(struct ucred)) {
105 0 : DEBUG(SSSDBG_CRIT_FAILURE,
106 : "getsockopt returned unexpected message size.\n");
107 0 : return ENOMSG;
108 : }
109 :
110 0 : cctx->client_euid = client_cred.uid;
111 0 : cctx->client_egid = client_cred.gid;
112 0 : cctx->client_pid = client_cred.pid;
113 :
114 0 : DEBUG(SSSDBG_TRACE_ALL, "Client creds: euid[%d] egid[%d] pid[%d].\n",
115 : cctx->client_euid, cctx->client_egid, cctx->client_pid);
116 : #endif
117 :
118 0 : return EOK;
119 : }
120 :
121 8 : errno_t check_allowed_uids(uid_t uid, size_t allowed_uids_count,
122 : uid_t *allowed_uids)
123 : {
124 : size_t c;
125 :
126 8 : if (allowed_uids == NULL) {
127 1 : return EINVAL;
128 : }
129 :
130 14 : for (c = 0; c < allowed_uids_count; c++) {
131 12 : if (uid == allowed_uids[c]) {
132 5 : return EOK;
133 : }
134 : }
135 :
136 2 : return EACCES;
137 : }
138 :
139 15 : errno_t csv_string_to_uid_array(TALLOC_CTX *mem_ctx, const char *csv_string,
140 : bool allow_sss_loop,
141 : size_t *_uid_count, uid_t **_uids)
142 : {
143 : int ret;
144 : size_t c;
145 15 : char **list = NULL;
146 : int list_size;
147 15 : uid_t *uids = NULL;
148 : char *endptr;
149 :
150 15 : ret = split_on_separator(mem_ctx, csv_string, ',', true, false,
151 : &list, &list_size);
152 15 : if (ret != EOK) {
153 2 : DEBUG(SSSDBG_OP_FAILURE, "split_on_separator failed [%d][%s].\n",
154 : ret, strerror(ret));
155 2 : goto done;
156 : }
157 :
158 13 : uids = talloc_array(mem_ctx, uint32_t, list_size);
159 13 : if (uids == NULL) {
160 0 : DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n");
161 0 : ret = ENOMEM;
162 0 : goto done;
163 : }
164 :
165 13 : if (allow_sss_loop) {
166 12 : ret = unsetenv("_SSS_LOOPS");
167 12 : if (ret != EOK) {
168 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to unset _SSS_LOOPS, getpwnam "
169 : "might not find sssd users.\n");
170 : }
171 : }
172 :
173 45 : for (c = 0; c < list_size; c++) {
174 37 : errno = 0;
175 37 : if (*list[c] == '\0') {
176 1 : DEBUG(SSSDBG_OP_FAILURE, "Empty list item.\n");
177 1 : ret = EINVAL;
178 1 : goto done;
179 : }
180 :
181 36 : uids[c] = strtouint32(list[c], &endptr, 10);
182 36 : if (errno != 0 || *endptr != '\0') {
183 7 : ret = errno;
184 7 : if (ret == ERANGE) {
185 2 : DEBUG(SSSDBG_OP_FAILURE, "List item [%s] is out of range.\n",
186 : list[c]);
187 2 : goto done;
188 : }
189 :
190 5 : ret = sss_user_by_name_or_uid(list[c], &uids[c], NULL);
191 5 : if (ret != EOK) {
192 2 : DEBUG(SSSDBG_OP_FAILURE, "List item [%s] is neither a valid "
193 : "UID nor a user name which could be "
194 : "resolved by getpwnam().\n", list[c]);
195 2 : sss_log(SSS_LOG_WARNING, "List item [%s] is neither a valid "
196 : "UID nor a user name which could be "
197 2 : "resolved by getpwnam().\n", list[c]);
198 2 : goto done;
199 : }
200 : }
201 : }
202 :
203 8 : *_uid_count = list_size;
204 8 : *_uids = uids;
205 :
206 8 : ret = EOK;
207 :
208 : done:
209 15 : if(setenv("_SSS_LOOPS", "NO", 0) != 0) {
210 0 : DEBUG(SSSDBG_OP_FAILURE, "Failed to set _SSS_LOOPS.\n");
211 : }
212 15 : talloc_free(list);
213 15 : if (ret != EOK) {
214 7 : talloc_free(uids);
215 : }
216 :
217 15 : return ret;
218 : }
219 :
220 :
221 0 : static void client_send(struct cli_ctx *cctx)
222 : {
223 : int ret;
224 :
225 0 : ret = sss_packet_send(cctx->creq->out, cctx->cfd);
226 0 : if (ret == EAGAIN) {
227 : /* not all data was sent, loop again */
228 0 : return;
229 : }
230 0 : if (ret != EOK) {
231 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Failed to send data, aborting client!\n");
232 0 : talloc_free(cctx);
233 0 : return;
234 : }
235 :
236 : /* ok all sent */
237 0 : TEVENT_FD_NOT_WRITEABLE(cctx->cfde);
238 0 : TEVENT_FD_READABLE(cctx->cfde);
239 0 : talloc_free(cctx->creq);
240 0 : cctx->creq = NULL;
241 0 : return;
242 : }
243 :
244 0 : static int client_cmd_execute(struct cli_ctx *cctx, struct sss_cmd_table *sss_cmds)
245 : {
246 : enum sss_cli_command cmd;
247 :
248 0 : cmd = sss_packet_get_cmd(cctx->creq->in);
249 0 : return sss_cmd_execute(cctx, cmd, sss_cmds);
250 : }
251 :
252 0 : static void client_recv(struct cli_ctx *cctx)
253 : {
254 : int ret;
255 :
256 0 : if (!cctx->creq) {
257 0 : cctx->creq = talloc_zero(cctx, struct cli_request);
258 0 : if (!cctx->creq) {
259 0 : DEBUG(SSSDBG_FATAL_FAILURE,
260 : "Failed to alloc request, aborting client!\n");
261 0 : talloc_free(cctx);
262 0 : return;
263 : }
264 : }
265 :
266 0 : if (!cctx->creq->in) {
267 0 : ret = sss_packet_new(cctx->creq, SSS_PACKET_MAX_RECV_SIZE,
268 0 : 0, &cctx->creq->in);
269 0 : if (ret != EOK) {
270 0 : DEBUG(SSSDBG_FATAL_FAILURE,
271 : "Failed to alloc request, aborting client!\n");
272 0 : talloc_free(cctx);
273 0 : return;
274 : }
275 : }
276 :
277 0 : ret = sss_packet_recv(cctx->creq->in, cctx->cfd);
278 0 : switch (ret) {
279 : case EOK:
280 : /* do not read anymore */
281 0 : TEVENT_FD_NOT_READABLE(cctx->cfde);
282 : /* execute command */
283 0 : ret = client_cmd_execute(cctx, cctx->rctx->sss_cmds);
284 0 : if (ret != EOK) {
285 0 : DEBUG(SSSDBG_FATAL_FAILURE,
286 : "Failed to execute request, aborting client!\n");
287 0 : talloc_free(cctx);
288 : }
289 : /* past this point cctx can be freed at any time by callbacks
290 : * in case of error, do not use it */
291 0 : return;
292 :
293 : case EAGAIN:
294 : /* need to read still some data, loop again */
295 0 : break;
296 :
297 : case EINVAL:
298 0 : DEBUG(SSSDBG_TRACE_FUNC,
299 : "Invalid data from client, closing connection!\n");
300 0 : talloc_free(cctx);
301 0 : break;
302 :
303 : case ENODATA:
304 0 : DEBUG(SSSDBG_FUNC_DATA, "Client disconnected!\n");
305 0 : talloc_free(cctx);
306 0 : break;
307 :
308 : default:
309 0 : DEBUG(SSSDBG_TRACE_FUNC, "Failed to read request, aborting client!\n");
310 0 : talloc_free(cctx);
311 : }
312 :
313 0 : return;
314 : }
315 :
316 : static errno_t reset_idle_timer(struct cli_ctx *cctx);
317 :
318 0 : static void client_fd_handler(struct tevent_context *ev,
319 : struct tevent_fd *fde,
320 : uint16_t flags, void *ptr)
321 : {
322 : errno_t ret;
323 0 : struct cli_ctx *cctx = talloc_get_type(ptr, struct cli_ctx);
324 :
325 : /* Always reset the idle timer on any activity */
326 0 : ret = reset_idle_timer(cctx);
327 0 : if (ret != EOK) {
328 0 : DEBUG(SSSDBG_CRIT_FAILURE,
329 : "Could not create idle timer for client. "
330 : "This connection may not auto-terminate\n");
331 : /* Non-fatal, continue */
332 : }
333 :
334 0 : if (flags & TEVENT_FD_READ) {
335 0 : client_recv(cctx);
336 0 : return;
337 : }
338 0 : if (flags & TEVENT_FD_WRITE) {
339 0 : client_send(cctx);
340 0 : return;
341 : }
342 : }
343 :
344 : struct accept_fd_ctx {
345 : struct resp_ctx *rctx;
346 : bool is_private;
347 : };
348 :
349 : static void idle_handler(struct tevent_context *ev,
350 : struct tevent_timer *te,
351 : struct timeval current_time,
352 : void *data);
353 :
354 0 : static void accept_fd_handler(struct tevent_context *ev,
355 : struct tevent_fd *fde,
356 : uint16_t flags, void *ptr)
357 : {
358 : /* accept and attach new event handler */
359 0 : struct accept_fd_ctx *accept_ctx =
360 : talloc_get_type(ptr, struct accept_fd_ctx);
361 0 : struct resp_ctx *rctx = accept_ctx->rctx;
362 : struct cli_ctx *cctx;
363 : socklen_t len;
364 : struct stat stat_buf;
365 : int ret;
366 0 : int fd = accept_ctx->is_private ? rctx->priv_lfd : rctx->lfd;
367 : int client_fd;
368 :
369 0 : if (accept_ctx->is_private) {
370 0 : ret = stat(rctx->priv_sock_name, &stat_buf);
371 0 : if (ret == -1) {
372 0 : DEBUG(SSSDBG_CRIT_FAILURE,
373 : "stat on privileged pipe failed: [%d][%s].\n", errno,
374 : strerror(errno));
375 0 : return;
376 : }
377 :
378 0 : if ( ! (stat_buf.st_uid == 0 && stat_buf.st_gid == 0 &&
379 0 : (stat_buf.st_mode&(S_IFSOCK|S_IRUSR|S_IWUSR)) == stat_buf.st_mode)) {
380 0 : DEBUG(SSSDBG_CRIT_FAILURE,
381 : "privileged pipe has an illegal status.\n");
382 : /* TODO: what is the best response to this condition? Terminate? */
383 0 : return;
384 : }
385 : }
386 :
387 0 : cctx = talloc_zero(rctx, struct cli_ctx);
388 0 : if (!cctx) {
389 : struct sockaddr_un addr;
390 0 : DEBUG(SSSDBG_FATAL_FAILURE,
391 : "Out of memory trying to setup client context%s!\n",
392 : accept_ctx->is_private ? " on privileged pipe": "");
393 : /* accept and close to signal the client we have a problem */
394 0 : memset(&addr, 0, sizeof(addr));
395 0 : len = sizeof(addr);
396 0 : client_fd = accept(fd, (struct sockaddr *)&addr, &len);
397 0 : if (client_fd == -1) {
398 0 : return;
399 : }
400 0 : close(client_fd);
401 0 : return;
402 : }
403 :
404 0 : len = sizeof(cctx->addr);
405 0 : cctx->cfd = accept(fd, (struct sockaddr *)&cctx->addr, &len);
406 0 : if (cctx->cfd == -1) {
407 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Accept failed [%s]\n", strerror(errno));
408 0 : talloc_free(cctx);
409 0 : return;
410 : }
411 :
412 0 : cctx->priv = accept_ctx->is_private;
413 :
414 0 : ret = get_client_cred(cctx);
415 0 : if (ret != EOK) {
416 0 : DEBUG(SSSDBG_OP_FAILURE, "get_client_cred failed, "
417 : "client cred may not be available.\n");
418 : }
419 :
420 0 : if (rctx->allowed_uids_count != 0) {
421 0 : if (cctx->client_euid == -1) {
422 0 : DEBUG(SSSDBG_CRIT_FAILURE, "allowed_uids configured, " \
423 : "but platform does not support " \
424 : "reading peer credential from the " \
425 : "socket. Access denied.\n");
426 0 : close(cctx->cfd);
427 0 : talloc_free(cctx);
428 0 : return;
429 : }
430 :
431 0 : ret = check_allowed_uids(cctx->client_euid, rctx->allowed_uids_count,
432 : rctx->allowed_uids);
433 0 : if (ret != EOK) {
434 0 : if (ret == EACCES) {
435 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Access denied for uid [%d].\n",
436 : cctx->client_euid);
437 : } else {
438 0 : DEBUG(SSSDBG_OP_FAILURE, "check_allowed_uids failed.\n");
439 : }
440 0 : close(cctx->cfd);
441 0 : talloc_free(cctx);
442 0 : return;
443 : }
444 : }
445 :
446 0 : cctx->cfde = tevent_add_fd(ev, cctx, cctx->cfd,
447 : TEVENT_FD_READ, client_fd_handler, cctx);
448 0 : if (!cctx->cfde) {
449 0 : close(cctx->cfd);
450 0 : talloc_free(cctx);
451 0 : DEBUG(SSSDBG_OP_FAILURE,
452 : "Failed to queue client handler%s\n",
453 : accept_ctx->is_private ? " on privileged pipe" : "");
454 0 : return;
455 : }
456 :
457 0 : cctx->ev = ev;
458 0 : cctx->rctx = rctx;
459 :
460 0 : talloc_set_destructor(cctx, client_destructor);
461 :
462 : /* Set up the idle timer */
463 0 : ret = reset_idle_timer(cctx);
464 0 : if (ret != EOK) {
465 0 : DEBUG(SSSDBG_CRIT_FAILURE,
466 : "Could not create idle timer for client. "
467 : "This connection may not auto-terminate\n");
468 : /* Non-fatal, continue */
469 : }
470 :
471 0 : DEBUG(SSSDBG_TRACE_FUNC,
472 : "Client connected%s!\n",
473 : accept_ctx->is_private ? " to privileged pipe" : "");
474 :
475 0 : return;
476 : }
477 :
478 0 : static errno_t reset_idle_timer(struct cli_ctx *cctx)
479 : {
480 0 : struct timeval tv =
481 0 : tevent_timeval_current_ofs(cctx->rctx->client_idle_timeout, 0);
482 :
483 0 : talloc_zfree(cctx->idle);
484 :
485 0 : cctx->idle = tevent_add_timer(cctx->ev, cctx, tv, idle_handler, cctx);
486 0 : if (!cctx->idle) return ENOMEM;
487 :
488 0 : DEBUG(SSSDBG_TRACE_ALL,
489 : "Idle timer re-set for client [%p][%d]\n",
490 : cctx, cctx->cfd);
491 :
492 0 : return EOK;
493 : }
494 :
495 0 : static void idle_handler(struct tevent_context *ev,
496 : struct tevent_timer *te,
497 : struct timeval current_time,
498 : void *data)
499 : {
500 : /* This connection is idle. Terminate it */
501 0 : struct cli_ctx *cctx =
502 : talloc_get_type(data, struct cli_ctx);
503 :
504 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
505 : "Terminating idle client [%p][%d]\n",
506 : cctx, cctx->cfd);
507 :
508 : /* The cli_ctx destructor will handle the rest */
509 0 : talloc_free(cctx);
510 0 : }
511 :
512 0 : static int sss_dp_init(struct resp_ctx *rctx,
513 : struct sbus_vtable *dp_intf,
514 : const char *cli_name,
515 : struct sss_domain_info *domain)
516 : {
517 : struct be_conn *be_conn;
518 : int ret;
519 :
520 0 : be_conn = talloc_zero(rctx, struct be_conn);
521 0 : if (!be_conn) return ENOMEM;
522 :
523 0 : be_conn->cli_name = cli_name;
524 0 : be_conn->domain = domain;
525 0 : be_conn->rctx = rctx;
526 :
527 : /* Set up SBUS connection to the monitor */
528 0 : ret = dp_get_sbus_address(be_conn, &be_conn->sbus_address, domain->name);
529 0 : if (ret != EOK) {
530 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Could not locate DP address.\n");
531 0 : return ret;
532 : }
533 0 : ret = sbus_client_init(rctx, rctx->ev,
534 0 : be_conn->sbus_address,
535 : &be_conn->conn);
536 0 : if (ret != EOK) {
537 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Failed to connect to monitor services.\n");
538 0 : return ret;
539 : }
540 :
541 0 : ret = sbus_conn_register_iface(be_conn->conn, dp_intf, DP_PATH, rctx);
542 0 : if (ret != EOK) {
543 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Failed to export data provider.\n");
544 0 : return ret;
545 : }
546 :
547 0 : DLIST_ADD_END(rctx->be_conns, be_conn, struct be_conn *);
548 :
549 : /* Identify ourselves to the DP */
550 0 : ret = dp_common_send_id(be_conn->conn,
551 : DATA_PROVIDER_VERSION,
552 : cli_name);
553 0 : if (ret != EOK) {
554 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Failed to identify to the DP!\n");
555 0 : return ret;
556 : }
557 :
558 0 : return EOK;
559 : }
560 :
561 2 : int create_pipe_fd(const char *sock_name, int *_fd, mode_t umaskval)
562 : {
563 : struct sockaddr_un addr;
564 : mode_t orig_umaskval;
565 : errno_t ret;
566 : int fd;
567 :
568 2 : fd = socket(AF_UNIX, SOCK_STREAM, 0);
569 2 : if (fd == -1) {
570 0 : return EIO;
571 : }
572 :
573 2 : orig_umaskval = umask(umaskval);
574 :
575 2 : ret = sss_fd_nonblocking(fd);
576 2 : if (ret != EOK) {
577 0 : goto done;
578 : }
579 :
580 2 : ret = set_close_on_exec(fd);
581 2 : if (ret != EOK) {
582 0 : goto done;
583 : }
584 :
585 2 : memset(&addr, 0, sizeof(addr));
586 2 : addr.sun_family = AF_UNIX;
587 2 : strncpy(addr.sun_path, sock_name, sizeof(addr.sun_path) - 1);
588 2 : addr.sun_path[sizeof(addr.sun_path) - 1] = '\0';
589 :
590 : /* make sure we have no old sockets around */
591 2 : ret = unlink(sock_name);
592 2 : if (ret != 0 && errno != ENOENT) {
593 0 : ret = errno;
594 0 : DEBUG(SSSDBG_MINOR_FAILURE,
595 : "Cannot remove old socket (errno=%d), bind might fail!\n", ret);
596 : }
597 :
598 2 : if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
599 0 : DEBUG(SSSDBG_FATAL_FAILURE,
600 : "Unable to bind on socket '%s'\n", sock_name);
601 0 : ret = EIO;
602 0 : goto done;
603 : }
604 2 : if (listen(fd, 10) == -1) {
605 0 : DEBUG(SSSDBG_FATAL_FAILURE,
606 : "Unable to listen on socket '%s'\n", sock_name);
607 0 : ret = EIO;
608 0 : goto done;
609 : }
610 :
611 2 : ret = EOK;
612 :
613 : done:
614 : /* restore previous umask value */
615 2 : umask(orig_umaskval);
616 2 : if (ret == EOK) {
617 2 : *_fd = fd;
618 : } else {
619 0 : close(fd);
620 : }
621 2 : return ret;
622 : }
623 :
624 : /* create a unix socket and listen to it */
625 0 : static int set_unix_socket(struct resp_ctx *rctx)
626 : {
627 : errno_t ret;
628 : struct accept_fd_ctx *accept_ctx;
629 :
630 : /* for future use */
631 : #if 0
632 : char *default_pipe;
633 : int ret;
634 :
635 : default_pipe = talloc_asprintf(rctx, "%s/%s", PIPE_PATH,
636 : rctx->sss_pipe_name);
637 : if (!default_pipe) {
638 : return ENOMEM;
639 : }
640 :
641 : ret = confdb_get_string(rctx->cdb, rctx,
642 : rctx->confdb_socket_path, "unixSocket",
643 : default_pipe, &rctx->sock_name);
644 : if (ret != EOK) {
645 : talloc_free(default_pipe);
646 : return ret;
647 : }
648 : talloc_free(default_pipe);
649 :
650 : default_pipe = talloc_asprintf(rctx, "%s/private/%s", PIPE_PATH,
651 : rctx->sss_pipe_name);
652 : if (!default_pipe) {
653 : return ENOMEM;
654 : }
655 :
656 : ret = confdb_get_string(rctx->cdb, rctx,
657 : rctx->confdb_socket_path, "privUnixSocket",
658 : default_pipe, &rctx->priv_sock_name);
659 : if (ret != EOK) {
660 : talloc_free(default_pipe);
661 : return ret;
662 : }
663 : talloc_free(default_pipe);
664 : #endif
665 :
666 0 : if (rctx->sock_name != NULL ) {
667 : /* Set the umask so that permissions are set right on the socket.
668 : * It must be readable and writable by anybody on the system. */
669 0 : if (rctx->lfd == -1) {
670 0 : ret = create_pipe_fd(rctx->sock_name, &rctx->lfd, SCKT_RSP_UMASK);
671 0 : if (ret != EOK) {
672 0 : return ret;
673 : }
674 : }
675 :
676 0 : accept_ctx = talloc_zero(rctx, struct accept_fd_ctx);
677 0 : if(!accept_ctx) goto failed;
678 0 : accept_ctx->rctx = rctx;
679 0 : accept_ctx->is_private = false;
680 :
681 0 : rctx->lfde = tevent_add_fd(rctx->ev, rctx, rctx->lfd,
682 : TEVENT_FD_READ, accept_fd_handler,
683 : accept_ctx);
684 0 : if (!rctx->lfde) {
685 0 : DEBUG(SSSDBG_FATAL_FAILURE, "Failed to queue handler on pipe\n");
686 0 : goto failed;
687 : }
688 : }
689 :
690 0 : if (rctx->priv_sock_name != NULL ) {
691 : /* create privileged pipe */
692 0 : if (rctx->priv_lfd == -1) {
693 0 : ret = create_pipe_fd(rctx->priv_sock_name, &rctx->priv_lfd,
694 : DFL_RSP_UMASK);
695 0 : if (ret != EOK) {
696 0 : goto failed;
697 : }
698 : }
699 :
700 0 : accept_ctx = talloc_zero(rctx, struct accept_fd_ctx);
701 0 : if(!accept_ctx) goto failed;
702 0 : accept_ctx->rctx = rctx;
703 0 : accept_ctx->is_private = true;
704 :
705 0 : rctx->priv_lfde = tevent_add_fd(rctx->ev, rctx, rctx->priv_lfd,
706 : TEVENT_FD_READ, accept_fd_handler,
707 : accept_ctx);
708 0 : if (!rctx->priv_lfde) {
709 0 : DEBUG(SSSDBG_FATAL_FAILURE,
710 : "Failed to queue handler on privileged pipe\n");
711 0 : goto failed;
712 : }
713 : }
714 :
715 0 : return EOK;
716 :
717 : failed:
718 0 : close(rctx->lfd);
719 0 : close(rctx->priv_lfd);
720 0 : return EIO;
721 : }
722 :
723 0 : static int sss_responder_ctx_destructor(void *ptr)
724 : {
725 0 : struct resp_ctx *rctx = talloc_get_type(ptr, struct resp_ctx);
726 :
727 : /* mark that we are shutting down the responder, so it is propagated
728 : * into underlying contexts that are freed right before rctx */
729 0 : DEBUG(SSSDBG_TRACE_FUNC, "Responder is being shut down\n");
730 0 : rctx->shutting_down = true;
731 :
732 0 : return 0;
733 : }
734 :
735 0 : int sss_process_init(TALLOC_CTX *mem_ctx,
736 : struct tevent_context *ev,
737 : struct confdb_ctx *cdb,
738 : struct sss_cmd_table sss_cmds[],
739 : const char *sss_pipe_name,
740 : int pipe_fd,
741 : const char *sss_priv_pipe_name,
742 : int priv_pipe_fd,
743 : const char *confdb_service_path,
744 : const char *svc_name,
745 : uint16_t svc_version,
746 : struct mon_cli_iface *monitor_intf,
747 : const char *cli_name,
748 : struct sbus_vtable *dp_intf,
749 : struct resp_ctx **responder_ctx)
750 : {
751 : struct resp_ctx *rctx;
752 : struct sss_domain_info *dom;
753 : int ret;
754 0 : char *tmp = NULL;
755 :
756 0 : rctx = talloc_zero(mem_ctx, struct resp_ctx);
757 0 : if (!rctx) {
758 0 : DEBUG(SSSDBG_FATAL_FAILURE, "fatal error initializing resp_ctx\n");
759 0 : return ENOMEM;
760 : }
761 0 : rctx->ev = ev;
762 0 : rctx->cdb = cdb;
763 0 : rctx->sss_cmds = sss_cmds;
764 0 : rctx->sock_name = sss_pipe_name;
765 0 : rctx->priv_sock_name = sss_priv_pipe_name;
766 0 : rctx->lfd = pipe_fd;
767 0 : rctx->priv_lfd = priv_pipe_fd;
768 0 : rctx->confdb_service_path = confdb_service_path;
769 0 : rctx->shutting_down = false;
770 :
771 0 : talloc_set_destructor((TALLOC_CTX*)rctx, sss_responder_ctx_destructor);
772 :
773 0 : ret = confdb_get_int(rctx->cdb, rctx->confdb_service_path,
774 : CONFDB_RESPONDER_CLI_IDLE_TIMEOUT,
775 : CONFDB_RESPONDER_CLI_IDLE_DEFAULT_TIMEOUT,
776 : &rctx->client_idle_timeout);
777 0 : if (ret != EOK) {
778 0 : DEBUG(SSSDBG_OP_FAILURE,
779 : "Cannot get the client idle timeout [%d]: %s\n",
780 : ret, strerror(ret));
781 0 : goto fail;
782 : }
783 :
784 : /* Ensure that the client timeout is at least ten seconds */
785 0 : if (rctx->client_idle_timeout < 10) {
786 0 : rctx->client_idle_timeout = 10;
787 : }
788 :
789 0 : ret = confdb_get_int(rctx->cdb, rctx->confdb_service_path,
790 : CONFDB_RESPONDER_GET_DOMAINS_TIMEOUT,
791 : GET_DOMAINS_DEFAULT_TIMEOUT, &rctx->domains_timeout);
792 0 : if (ret != EOK) {
793 0 : DEBUG(SSSDBG_OP_FAILURE,
794 : "Cannnot get the default domain timeout [%d]: %s\n",
795 : ret, strerror(ret));
796 0 : goto fail;
797 : }
798 :
799 0 : if (rctx->domains_timeout < 0) {
800 0 : DEBUG(SSSDBG_CONF_SETTINGS, "timeout can't be set to negative value, setting default\n");
801 0 : rctx->domains_timeout = GET_DOMAINS_DEFAULT_TIMEOUT;
802 : }
803 :
804 0 : ret = confdb_get_domains(rctx->cdb, &rctx->domains);
805 0 : if (ret != EOK) {
806 0 : DEBUG(SSSDBG_FATAL_FAILURE, "fatal error setting up domain map\n");
807 0 : goto fail;
808 : }
809 :
810 0 : ret = confdb_get_string(rctx->cdb, rctx, CONFDB_MONITOR_CONF_ENTRY,
811 : CONFDB_MONITOR_DEFAULT_DOMAIN, NULL,
812 : &rctx->default_domain);
813 0 : if (ret != EOK) {
814 0 : DEBUG(SSSDBG_OP_FAILURE,
815 : "Cannnot get the default domain [%d]: %s\n",
816 : ret, strerror(ret));
817 0 : goto fail;
818 : }
819 :
820 0 : ret = confdb_get_string(rctx->cdb, rctx, CONFDB_MONITOR_CONF_ENTRY,
821 : CONFDB_MONITOR_OVERRIDE_SPACE, NULL,
822 : &tmp);
823 0 : if (ret != EOK) {
824 0 : DEBUG(SSSDBG_OP_FAILURE,
825 : "Cannnot get the space substitution character [%d]: %s\n",
826 : ret, strerror(ret));
827 0 : goto fail;
828 : }
829 :
830 0 : if (tmp != NULL) {
831 0 : if (strlen(tmp) > 1) {
832 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Option %s is longer than 1 character "
833 : "only the first character %c will be used\n",
834 : CONFDB_MONITOR_OVERRIDE_SPACE, tmp[0]);
835 : }
836 :
837 0 : rctx->override_space = tmp[0];
838 : }
839 :
840 0 : ret = sss_monitor_init(rctx, rctx->ev, monitor_intf,
841 : svc_name, svc_version, rctx,
842 : &rctx->mon_conn);
843 0 : if (ret != EOK) {
844 0 : DEBUG(SSSDBG_FATAL_FAILURE, "fatal error setting up message bus\n");
845 0 : goto fail;
846 : }
847 :
848 0 : for (dom = rctx->domains; dom; dom = get_next_domain(dom, false)) {
849 0 : ret = sss_names_init(rctx->cdb, rctx->cdb, dom->name, &dom->names);
850 0 : if (ret != EOK) {
851 0 : DEBUG(SSSDBG_FATAL_FAILURE,
852 : "fatal error initializing regex data for domain: %s\n",
853 : dom->name);
854 0 : goto fail;
855 : }
856 :
857 : /* skip local domain, it doesn't have a backend */
858 0 : if (strcasecmp(dom->provider, "local") == 0) {
859 0 : continue;
860 : }
861 :
862 0 : ret = sss_dp_init(rctx, dp_intf, cli_name, dom);
863 0 : if (ret != EOK) {
864 0 : DEBUG(SSSDBG_FATAL_FAILURE,
865 : "fatal error setting up backend connector\n");
866 0 : goto fail;
867 : }
868 : }
869 :
870 0 : ret = sysdb_init(rctx, rctx->domains, false);
871 0 : if (ret != EOK) {
872 0 : SYSDB_VERSION_ERROR_DAEMON(ret);
873 0 : DEBUG(SSSDBG_FATAL_FAILURE, "fatal error initializing resp_ctx\n");
874 0 : goto fail;
875 : }
876 :
877 : /* after all initializations we are ready to listen on our socket */
878 0 : ret = set_unix_socket(rctx);
879 0 : if (ret != EOK) {
880 0 : DEBUG(SSSDBG_FATAL_FAILURE, "fatal error initializing socket\n");
881 0 : goto fail;
882 : }
883 :
884 : /* Create DP request table */
885 0 : ret = sss_hash_create(rctx, 30, &rctx->dp_request_table);
886 0 : if (ret != EOK) {
887 0 : DEBUG(SSSDBG_FATAL_FAILURE,
888 : "Could not create hash table for the request queue\n");
889 0 : goto fail;
890 : }
891 :
892 0 : DEBUG(SSSDBG_TRACE_FUNC, "Responder Initialization complete\n");
893 :
894 0 : *responder_ctx = rctx;
895 0 : return EOK;
896 :
897 : fail:
898 0 : talloc_free(rctx);
899 0 : return ret;
900 : }
901 :
902 0 : int sss_dp_get_domain_conn(struct resp_ctx *rctx, const char *domain,
903 : struct be_conn **_conn)
904 : {
905 : struct be_conn *iter;
906 :
907 0 : if (!rctx->be_conns) return ENOENT;
908 :
909 0 : for (iter = rctx->be_conns; iter; iter = iter->next) {
910 0 : if (strcasecmp(domain, iter->domain->name) == 0) break;
911 : }
912 :
913 0 : if (!iter) return ENOENT;
914 :
915 0 : *_conn = iter;
916 :
917 0 : return EOK;
918 : }
919 :
920 : struct sss_domain_info *
921 55 : responder_get_domain(struct resp_ctx *rctx, const char *name)
922 : {
923 : struct sss_domain_info *dom;
924 55 : struct sss_domain_info *ret_dom = NULL;
925 :
926 77 : for (dom = rctx->domains; dom; dom = get_next_domain(dom, true)) {
927 71 : if (sss_domain_get_state(dom) == DOM_DISABLED) {
928 0 : continue;
929 : }
930 :
931 93 : if (strcasecmp(dom->name, name) == 0 ||
932 22 : (dom->flat_name != NULL &&
933 0 : strcasecmp(dom->flat_name, name) == 0)) {
934 49 : ret_dom = dom;
935 49 : break;
936 : }
937 : }
938 :
939 55 : if (!ret_dom) {
940 6 : DEBUG(SSSDBG_OP_FAILURE, "Unknown domain [%s]\n", name);
941 : }
942 :
943 55 : return ret_dom;
944 : }
945 :
946 4 : errno_t responder_get_domain_by_id(struct resp_ctx *rctx, const char *id,
947 : struct sss_domain_info **_ret_dom)
948 : {
949 : struct sss_domain_info *dom;
950 4 : struct sss_domain_info *ret_dom = NULL;
951 : size_t id_len;
952 : size_t dom_id_len;
953 : int ret;
954 :
955 4 : if (id == NULL || _ret_dom == NULL) {
956 0 : return EINVAL;
957 : }
958 :
959 4 : id_len = strlen(id);
960 :
961 4 : for (dom = rctx->domains; dom; dom = get_next_domain(dom, true)) {
962 8 : if (sss_domain_get_state(dom) == DOM_DISABLED ||
963 4 : dom->domain_id == NULL) {
964 0 : continue;
965 : }
966 :
967 4 : dom_id_len = strlen(dom->domain_id);
968 8 : if ((id_len >= dom_id_len) &&
969 4 : strncasecmp(dom->domain_id, id, dom_id_len) == 0) {
970 4 : if (IS_SUBDOMAIN(dom) &&
971 0 : ((time(NULL) - dom->parent->subdomains_last_checked.tv_sec) >
972 0 : rctx->domains_timeout)) {
973 0 : DEBUG(SSSDBG_TRACE_FUNC, "Domain entry with id [%s] " \
974 : "is expired.\n", id);
975 0 : ret = EAGAIN;
976 0 : goto done;
977 : }
978 4 : ret_dom = dom;
979 4 : break;
980 : }
981 : }
982 :
983 4 : if (ret_dom == NULL) {
984 0 : DEBUG(SSSDBG_OP_FAILURE, "Unknown domain id [%s], checking for "
985 : "possible subdomains!\n", id);
986 0 : ret = ENOENT;
987 : } else {
988 4 : *_ret_dom = ret_dom;
989 4 : ret = EOK;
990 : }
991 :
992 : done:
993 4 : return ret;
994 : }
995 :
996 0 : int responder_logrotate(struct sbus_request *dbus_req, void *data)
997 : {
998 : errno_t ret;
999 0 : struct resp_ctx *rctx = talloc_get_type(data, struct resp_ctx);
1000 :
1001 0 : ret = server_common_rotate_logs(rctx->cdb, rctx->confdb_service_path);
1002 0 : if (ret != EOK) return ret;
1003 :
1004 0 : return sbus_request_return_and_finish(dbus_req, DBUS_TYPE_INVALID);
1005 : }
1006 :
1007 0 : void responder_set_fd_limit(rlim_t fd_limit)
1008 : {
1009 : struct rlimit current_limit, new_limit;
1010 : int limret;
1011 :
1012 : /* First, let's see if we have permission to just set
1013 : * the value as-is.
1014 : */
1015 0 : new_limit.rlim_cur = fd_limit;
1016 0 : new_limit.rlim_max = fd_limit;
1017 0 : limret = setrlimit(RLIMIT_NOFILE, &new_limit);
1018 0 : if (limret == 0) {
1019 0 : DEBUG(SSSDBG_CONF_SETTINGS,
1020 : "Maximum file descriptors set to [%"SPRIrlim"]\n",
1021 : new_limit.rlim_cur);
1022 0 : return;
1023 : }
1024 :
1025 : /* We couldn't set the soft and hard limits to this
1026 : * value. Let's see how high we CAN set it.
1027 : */
1028 :
1029 : /* Determine the maximum hard limit */
1030 0 : limret = getrlimit(RLIMIT_NOFILE, ¤t_limit);
1031 0 : if (limret == 0) {
1032 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
1033 : "Current fd limit: [%"SPRIrlim"]\n",
1034 : current_limit.rlim_cur);
1035 : /* Choose the lesser of the requested and the hard limit */
1036 0 : if (current_limit.rlim_max < fd_limit) {
1037 0 : new_limit.rlim_cur = current_limit.rlim_max;
1038 : } else {
1039 0 : new_limit.rlim_cur = fd_limit;
1040 : }
1041 0 : new_limit.rlim_max = current_limit.rlim_max;
1042 :
1043 0 : limret = setrlimit(RLIMIT_NOFILE, &new_limit);
1044 0 : if (limret == 0) {
1045 0 : DEBUG(SSSDBG_CONF_SETTINGS,
1046 : "Maximum file descriptors set to [%"SPRIrlim"]\n",
1047 : new_limit.rlim_cur);
1048 : } else {
1049 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1050 : "Could not set new fd limits. Proceeding with "
1051 : "[%"SPRIrlim"]\n", current_limit.rlim_cur);
1052 : }
1053 : } else {
1054 0 : DEBUG(SSSDBG_CRIT_FAILURE,
1055 : "Could not determine fd limits. "
1056 : "Proceeding with system values\n");
1057 : }
1058 : }
|