Line data Source code
1 : /*
2 : SSSD
3 :
4 : LDAP Backend Module -- child helpers
5 :
6 : Authors:
7 : Jakub Hrozek <jhrozek@redhat.com>
8 :
9 : Copyright (C) 2009 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 <sys/types.h>
26 : #include <sys/wait.h>
27 : #include <pwd.h>
28 : #include <unistd.h>
29 : #include <fcntl.h>
30 :
31 : #include "util/util.h"
32 : #include "util/sss_krb5.h"
33 : #include "providers/ldap/ldap_common.h"
34 : #include "providers/ldap/sdap_async_private.h"
35 : #include "util/child_common.h"
36 :
37 : #ifndef SSSD_LIBEXEC_PATH
38 : #error "SSSD_LIBEXEC_PATH not defined"
39 : #else
40 : #define LDAP_CHILD SSSD_LIBEXEC_PATH"/ldap_child"
41 : #endif
42 :
43 : #ifndef LDAP_CHILD_USER
44 : #define LDAP_CHILD_USER "nobody"
45 : #endif
46 :
47 : struct sdap_child {
48 : /* child info */
49 : pid_t pid;
50 : struct child_io_fds *io;
51 : };
52 :
53 0 : static void sdap_close_fd(int *fd)
54 : {
55 : int ret;
56 :
57 0 : if (*fd == -1) {
58 0 : DEBUG(SSSDBG_TRACE_FUNC, "fd already closed\n");
59 0 : return;
60 : }
61 :
62 0 : ret = close(*fd);
63 0 : if (ret) {
64 0 : ret = errno;
65 0 : DEBUG(SSSDBG_OP_FAILURE, "Closing fd %d, return error %d (%s)\n",
66 : *fd, ret, strerror(ret));
67 : }
68 :
69 0 : *fd = -1;
70 : }
71 :
72 0 : static errno_t sdap_fork_child(struct tevent_context *ev,
73 : struct sdap_child *child)
74 : {
75 0 : int pipefd_to_child[2] = PIPE_INIT;
76 0 : int pipefd_from_child[2] = PIPE_INIT;
77 : pid_t pid;
78 : errno_t ret;
79 :
80 0 : ret = pipe(pipefd_from_child);
81 0 : if (ret == -1) {
82 0 : ret = errno;
83 0 : DEBUG(SSSDBG_CRIT_FAILURE,
84 : "pipe failed [%d][%s].\n", ret, strerror(ret));
85 0 : goto fail;
86 : }
87 0 : ret = pipe(pipefd_to_child);
88 0 : if (ret == -1) {
89 0 : ret = errno;
90 0 : DEBUG(SSSDBG_CRIT_FAILURE,
91 : "pipe failed [%d][%s].\n", ret, strerror(ret));
92 0 : goto fail;
93 : }
94 :
95 0 : pid = fork();
96 :
97 0 : if (pid == 0) { /* child */
98 0 : exec_child(child,
99 : pipefd_to_child, pipefd_from_child,
100 : LDAP_CHILD, ldap_child_debug_fd);
101 :
102 : /* We should never get here */
103 0 : DEBUG(SSSDBG_CRIT_FAILURE, "BUG: Could not exec LDAP child\n");
104 0 : } else if (pid > 0) { /* parent */
105 0 : child->pid = pid;
106 0 : child->io->read_from_child_fd = pipefd_from_child[0];
107 0 : PIPE_FD_CLOSE(pipefd_from_child[1]);
108 0 : child->io->write_to_child_fd = pipefd_to_child[1];
109 0 : PIPE_FD_CLOSE(pipefd_to_child[0]);
110 0 : sss_fd_nonblocking(child->io->read_from_child_fd);
111 0 : sss_fd_nonblocking(child->io->write_to_child_fd);
112 :
113 0 : ret = child_handler_setup(ev, pid, NULL, NULL, NULL);
114 0 : if (ret != EOK) {
115 0 : goto fail;
116 : }
117 :
118 : } else { /* error */
119 0 : ret = errno;
120 0 : DEBUG(SSSDBG_CRIT_FAILURE,
121 : "fork failed [%d][%s].\n", ret, strerror(ret));
122 0 : goto fail;
123 : }
124 :
125 0 : return EOK;
126 :
127 : fail:
128 0 : PIPE_CLOSE(pipefd_from_child);
129 0 : PIPE_CLOSE(pipefd_to_child);
130 0 : return ret;
131 : }
132 :
133 0 : static errno_t create_tgt_req_send_buffer(TALLOC_CTX *mem_ctx,
134 : const char *realm_str,
135 : const char *princ_str,
136 : const char *keytab_name,
137 : int32_t lifetime,
138 : struct io_buffer **io_buf)
139 : {
140 : struct io_buffer *buf;
141 : size_t rp;
142 :
143 0 : buf = talloc(mem_ctx, struct io_buffer);
144 0 : if (buf == NULL) {
145 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n");
146 0 : return ENOMEM;
147 : }
148 :
149 0 : buf->size = 6 * sizeof(uint32_t);
150 0 : if (realm_str) {
151 0 : buf->size += strlen(realm_str);
152 : }
153 0 : if (princ_str) {
154 0 : buf->size += strlen(princ_str);
155 : }
156 0 : if (keytab_name) {
157 0 : buf->size += strlen(keytab_name);
158 : }
159 :
160 0 : DEBUG(SSSDBG_TRACE_FUNC, "buffer size: %zu\n", buf->size);
161 :
162 0 : buf->data = talloc_size(buf, buf->size);
163 0 : if (buf->data == NULL) {
164 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_size failed.\n");
165 0 : talloc_free(buf);
166 0 : return ENOMEM;
167 : }
168 :
169 0 : rp = 0;
170 :
171 : /* realm */
172 0 : if (realm_str) {
173 0 : SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(realm_str), &rp);
174 0 : safealign_memcpy(&buf->data[rp], realm_str, strlen(realm_str), &rp);
175 : } else {
176 0 : SAFEALIGN_SET_UINT32(&buf->data[rp], 0, &rp);
177 : }
178 :
179 : /* principal */
180 0 : if (princ_str) {
181 0 : SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(princ_str), &rp);
182 0 : safealign_memcpy(&buf->data[rp], princ_str, strlen(princ_str), &rp);
183 : } else {
184 0 : SAFEALIGN_SET_UINT32(&buf->data[rp], 0, &rp);
185 : }
186 :
187 : /* keytab */
188 0 : if (keytab_name) {
189 0 : SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(keytab_name), &rp);
190 0 : safealign_memcpy(&buf->data[rp], keytab_name, strlen(keytab_name), &rp);
191 : } else {
192 0 : SAFEALIGN_SET_UINT32(&buf->data[rp], 0, &rp);
193 : }
194 :
195 : /* lifetime */
196 0 : SAFEALIGN_SET_UINT32(&buf->data[rp], lifetime, &rp);
197 :
198 : /* UID and GID to drop privileges to, if needed. The ldap_child process runs as
199 : * setuid if the back end runs unprivileged as it needs to access the keytab
200 : */
201 0 : SAFEALIGN_SET_UINT32(&buf->data[rp], geteuid(), &rp);
202 0 : SAFEALIGN_SET_UINT32(&buf->data[rp], getegid(), &rp);
203 :
204 0 : *io_buf = buf;
205 0 : return EOK;
206 : }
207 :
208 0 : static int parse_child_response(TALLOC_CTX *mem_ctx,
209 : uint8_t *buf, ssize_t size,
210 : int *result, krb5_error_code *kerr,
211 : char **ccache, time_t *expire_time_out)
212 : {
213 0 : size_t p = 0;
214 : uint32_t len;
215 : uint32_t res;
216 : char *ccn;
217 : time_t expire_time;
218 : krb5_error_code krberr;
219 :
220 : /* operation result code */
221 0 : SAFEALIGN_COPY_UINT32_CHECK(&res, buf + p, size, &p);
222 :
223 : /* krb5 error code */
224 0 : safealign_memcpy(&krberr, buf+p, sizeof(krberr), &p);
225 :
226 : /* ccache name size */
227 0 : SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p);
228 :
229 0 : if (len > size - p) return EINVAL;
230 :
231 0 : ccn = talloc_size(mem_ctx, sizeof(char) * (len + 1));
232 0 : if (ccn == NULL) {
233 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_size failed.\n");
234 0 : return ENOMEM;
235 : }
236 0 : safealign_memcpy(ccn, buf+p, sizeof(char) * len, &p);
237 0 : ccn[len] = '\0';
238 :
239 0 : if (p + sizeof(time_t) > size) {
240 0 : talloc_free(ccn);
241 0 : return EINVAL;
242 : }
243 0 : safealign_memcpy(&expire_time, buf+p, sizeof(time_t), &p);
244 :
245 0 : *result = res;
246 0 : *ccache = ccn;
247 0 : *expire_time_out = expire_time;
248 0 : *kerr = krberr;
249 0 : return EOK;
250 : }
251 :
252 : /* ==The-public-async-interface============================================*/
253 :
254 : struct sdap_get_tgt_state {
255 : struct tevent_context *ev;
256 : struct sdap_child *child;
257 : ssize_t len;
258 : uint8_t *buf;
259 : };
260 :
261 : static errno_t set_tgt_child_timeout(struct tevent_req *req,
262 : struct tevent_context *ev,
263 : int timeout);
264 : static void sdap_get_tgt_step(struct tevent_req *subreq);
265 : static void sdap_get_tgt_done(struct tevent_req *subreq);
266 :
267 0 : struct tevent_req *sdap_get_tgt_send(TALLOC_CTX *mem_ctx,
268 : struct tevent_context *ev,
269 : const char *realm_str,
270 : const char *princ_str,
271 : const char *keytab_name,
272 : int32_t lifetime,
273 : int timeout)
274 : {
275 : struct tevent_req *req, *subreq;
276 : struct sdap_get_tgt_state *state;
277 : struct io_buffer *buf;
278 : int ret;
279 :
280 0 : req = tevent_req_create(mem_ctx, &state, struct sdap_get_tgt_state);
281 0 : if (!req) {
282 0 : return NULL;
283 : }
284 :
285 0 : state->ev = ev;
286 :
287 0 : state->child = talloc_zero(state, struct sdap_child);
288 0 : if (!state->child) {
289 0 : ret = ENOMEM;
290 0 : goto fail;
291 : }
292 :
293 0 : state->child->io = talloc(state, struct child_io_fds);
294 0 : if (state->child->io == NULL) {
295 0 : ret = ENOMEM;
296 0 : goto fail;
297 : }
298 0 : state->child->io->read_from_child_fd = -1;
299 0 : state->child->io->write_to_child_fd = -1;
300 0 : talloc_set_destructor((TALLOC_CTX *) state->child->io, child_io_destructor);
301 :
302 : /* prepare the data to pass to child */
303 0 : ret = create_tgt_req_send_buffer(state,
304 : realm_str, princ_str, keytab_name, lifetime,
305 : &buf);
306 0 : if (ret != EOK) {
307 0 : DEBUG(SSSDBG_CRIT_FAILURE, "create_tgt_req_send_buffer failed.\n");
308 0 : goto fail;
309 : }
310 :
311 0 : ret = sdap_fork_child(state->ev, state->child);
312 0 : if (ret != EOK) {
313 0 : DEBUG(SSSDBG_CRIT_FAILURE, "sdap_fork_child failed.\n");
314 0 : goto fail;
315 : }
316 :
317 0 : ret = set_tgt_child_timeout(req, ev, timeout);
318 0 : if (ret != EOK) {
319 0 : DEBUG(SSSDBG_CRIT_FAILURE, "activate_child_timeout_handler failed.\n");
320 0 : goto fail;
321 : }
322 :
323 0 : subreq = write_pipe_send(state, ev, buf->data, buf->size,
324 0 : state->child->io->write_to_child_fd);
325 0 : if (!subreq) {
326 0 : ret = ENOMEM;
327 0 : goto fail;
328 : }
329 0 : tevent_req_set_callback(subreq, sdap_get_tgt_step, req);
330 :
331 0 : return req;
332 :
333 : fail:
334 0 : tevent_req_error(req, ret);
335 0 : tevent_req_post(req, ev);
336 0 : return req;
337 : }
338 :
339 0 : static void sdap_get_tgt_step(struct tevent_req *subreq)
340 : {
341 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
342 : struct tevent_req);
343 0 : struct sdap_get_tgt_state *state = tevent_req_data(req,
344 : struct sdap_get_tgt_state);
345 : int ret;
346 :
347 0 : ret = write_pipe_recv(subreq);
348 0 : talloc_zfree(subreq);
349 0 : if (ret != EOK) {
350 0 : tevent_req_error(req, ret);
351 0 : return;
352 : }
353 :
354 0 : sdap_close_fd(&state->child->io->write_to_child_fd);
355 :
356 0 : subreq = read_pipe_send(state, state->ev,
357 0 : state->child->io->read_from_child_fd);
358 0 : if (!subreq) {
359 0 : tevent_req_error(req, ENOMEM);
360 0 : return;
361 : }
362 0 : tevent_req_set_callback(subreq, sdap_get_tgt_done, req);
363 : }
364 :
365 0 : static void sdap_get_tgt_done(struct tevent_req *subreq)
366 : {
367 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
368 : struct tevent_req);
369 0 : struct sdap_get_tgt_state *state = tevent_req_data(req,
370 : struct sdap_get_tgt_state);
371 : int ret;
372 :
373 0 : ret = read_pipe_recv(subreq, state, &state->buf, &state->len);
374 0 : talloc_zfree(subreq);
375 0 : if (ret != EOK) {
376 0 : tevent_req_error(req, ret);
377 0 : return;
378 : }
379 :
380 0 : sdap_close_fd(&state->child->io->read_from_child_fd);
381 :
382 0 : tevent_req_done(req);
383 : }
384 :
385 0 : int sdap_get_tgt_recv(struct tevent_req *req,
386 : TALLOC_CTX *mem_ctx,
387 : int *result,
388 : krb5_error_code *kerr,
389 : char **ccname,
390 : time_t *expire_time_out)
391 : {
392 0 : struct sdap_get_tgt_state *state = tevent_req_data(req,
393 : struct sdap_get_tgt_state);
394 : char *ccn;
395 : time_t expire_time;
396 : int res;
397 : int ret;
398 : krb5_error_code krberr;
399 :
400 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
401 :
402 0 : ret = parse_child_response(mem_ctx, state->buf, state->len,
403 : &res, &krberr, &ccn, &expire_time);
404 0 : if (ret != EOK) {
405 0 : DEBUG(SSSDBG_CRIT_FAILURE,
406 : "Cannot parse child response: [%d][%s]\n", ret, strerror(ret));
407 0 : return ret;
408 : }
409 :
410 0 : DEBUG(SSSDBG_TRACE_FUNC,
411 : "Child responded: %d [%s], expired on [%ld]\n", res, ccn, (long)expire_time);
412 0 : *result = res;
413 0 : *kerr = krberr;
414 0 : *ccname = ccn;
415 0 : *expire_time_out = expire_time;
416 0 : return EOK;
417 : }
418 :
419 :
420 :
421 0 : static void get_tgt_timeout_handler(struct tevent_context *ev,
422 : struct tevent_timer *te,
423 : struct timeval tv, void *pvt)
424 : {
425 0 : struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
426 0 : struct sdap_get_tgt_state *state = tevent_req_data(req,
427 : struct sdap_get_tgt_state);
428 : int ret;
429 :
430 0 : DEBUG(SSSDBG_TRACE_ALL,
431 : "timeout for tgt child [%d] reached.\n", state->child->pid);
432 :
433 0 : ret = kill(state->child->pid, SIGKILL);
434 0 : if (ret == -1) {
435 0 : DEBUG(SSSDBG_CRIT_FAILURE,
436 : "kill failed [%d][%s].\n", errno, strerror(errno));
437 : }
438 :
439 0 : tevent_req_error(req, ETIMEDOUT);
440 0 : }
441 :
442 0 : static errno_t set_tgt_child_timeout(struct tevent_req *req,
443 : struct tevent_context *ev,
444 : int timeout)
445 : {
446 : struct tevent_timer *te;
447 : struct timeval tv;
448 :
449 0 : DEBUG(SSSDBG_TRACE_FUNC,
450 : "Setting %d seconds timeout for tgt child\n", timeout);
451 :
452 0 : tv = tevent_timeval_current_ofs(timeout, 0);
453 :
454 0 : te = tevent_add_timer(ev, req, tv, get_tgt_timeout_handler, req);
455 0 : if (te == NULL) {
456 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_add_timer failed.\n");
457 0 : return ENOMEM;
458 : }
459 :
460 0 : return EOK;
461 : }
462 :
463 :
464 :
465 : /* Setup child logging */
466 0 : int sdap_setup_child(void)
467 : {
468 0 : return child_debug_init(LDAP_CHILD_LOG_FILE, &ldap_child_debug_fd);
469 : }
|