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  	}