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