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