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