Fix headers, ldb_includes.h is a private header,
[Samba/bjacke.git] / source3 / lib / wbclient.c
blob4d3a6095301dba783ef07c25d9c9091346337c08
1 /*
2 Unix SMB/CIFS implementation.
3 Infrastructure for async winbind requests
4 Copyright (C) Volker Lendecke 2008
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "wbc_async.h"
23 static int make_nonstd_fd(int fd)
25 int i;
26 int sys_errno = 0;
27 int fds[3];
28 int num_fds = 0;
30 if (fd == -1) {
31 return -1;
33 while (fd < 3) {
34 fds[num_fds++] = fd;
35 fd = dup(fd);
36 if (fd == -1) {
37 sys_errno = errno;
38 break;
41 for (i=0; i<num_fds; i++) {
42 close(fds[i]);
44 if (fd == -1) {
45 errno = sys_errno;
47 return fd;
50 /****************************************************************************
51 Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
52 else
53 if SYSV use O_NDELAY
54 if BSD use FNDELAY
55 Set close on exec also.
56 ****************************************************************************/
58 static int make_safe_fd(int fd)
60 int result, flags;
61 int new_fd = make_nonstd_fd(fd);
63 if (new_fd == -1) {
64 goto fail;
67 /* Socket should be nonblocking. */
69 #ifdef O_NONBLOCK
70 #define FLAG_TO_SET O_NONBLOCK
71 #else
72 #ifdef SYSV
73 #define FLAG_TO_SET O_NDELAY
74 #else /* BSD */
75 #define FLAG_TO_SET FNDELAY
76 #endif
77 #endif
79 if ((flags = fcntl(new_fd, F_GETFL)) == -1) {
80 goto fail;
83 flags |= FLAG_TO_SET;
84 if (fcntl(new_fd, F_SETFL, flags) == -1) {
85 goto fail;
88 #undef FLAG_TO_SET
90 /* Socket should be closed on exec() */
91 #ifdef FD_CLOEXEC
92 result = flags = fcntl(new_fd, F_GETFD, 0);
93 if (flags >= 0) {
94 flags |= FD_CLOEXEC;
95 result = fcntl( new_fd, F_SETFD, flags );
97 if (result < 0) {
98 goto fail;
100 #endif
101 return new_fd;
103 fail:
104 if (new_fd != -1) {
105 int sys_errno = errno;
106 close(new_fd);
107 errno = sys_errno;
109 return -1;
112 static bool winbind_closed_fd(int fd)
114 struct timeval tv;
115 fd_set r_fds;
117 if (fd == -1) {
118 return true;
121 FD_ZERO(&r_fds);
122 FD_SET(fd, &r_fds);
123 ZERO_STRUCT(tv);
125 if ((select(fd+1, &r_fds, NULL, NULL, &tv) == -1)
126 || FD_ISSET(fd, &r_fds)) {
127 return true;
130 return false;
133 struct wb_context *wb_context_init(TALLOC_CTX *mem_ctx)
135 struct wb_context *result;
137 result = talloc(mem_ctx, struct wb_context);
138 if (result == NULL) {
139 return NULL;
141 result->queue = async_req_queue_init(result);
142 if (result->queue == NULL) {
143 TALLOC_FREE(result);
144 return NULL;
146 result->fd = -1;
147 return result;
150 static struct async_req *wb_connect_send(TALLOC_CTX *mem_ctx,
151 struct tevent_context *ev,
152 struct wb_context *wb_ctx,
153 const char *dir)
155 struct async_req *req;
156 struct sockaddr_un sunaddr;
157 struct stat st;
158 char *path = NULL;
159 wbcErr wbc_err;
161 if (wb_ctx->fd != -1) {
162 close(wb_ctx->fd);
163 wb_ctx->fd = -1;
166 /* Check permissions on unix socket directory */
168 if (lstat(dir, &st) == -1) {
169 wbc_err = WBC_ERR_WINBIND_NOT_AVAILABLE;
170 goto post_status;
173 if (!S_ISDIR(st.st_mode) ||
174 (st.st_uid != 0 && st.st_uid != geteuid())) {
175 wbc_err = WBC_ERR_WINBIND_NOT_AVAILABLE;
176 goto post_status;
179 /* Connect to socket */
181 path = talloc_asprintf(talloc_tos(), "%s/%s", dir,
182 WINBINDD_SOCKET_NAME);
183 if (path == NULL) {
184 goto nomem;
187 sunaddr.sun_family = AF_UNIX;
188 strlcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path));
189 TALLOC_FREE(path);
191 /* If socket file doesn't exist, don't bother trying to connect
192 with retry. This is an attempt to make the system usable when
193 the winbindd daemon is not running. */
195 if ((lstat(sunaddr.sun_path, &st) == -1)
196 || !S_ISSOCK(st.st_mode)
197 || (st.st_uid != 0 && st.st_uid != geteuid())) {
198 wbc_err = WBC_ERR_WINBIND_NOT_AVAILABLE;
199 goto post_status;
202 wb_ctx->fd = make_safe_fd(socket(AF_UNIX, SOCK_STREAM, 0));
203 if (wb_ctx->fd == -1) {
204 wbc_err = map_wbc_err_from_errno(errno);
205 goto post_status;
208 req = async_connect_send(mem_ctx, ev, wb_ctx->fd,
209 (struct sockaddr *)&sunaddr,
210 sizeof(sunaddr));
211 if (req == NULL) {
212 goto nomem;
214 if (!async_req_set_timeout(req, ev, timeval_set(30, 0))) {
215 TALLOC_FREE(req);
216 goto nomem;
219 return req;
221 nomem:
222 wbc_err = WBC_ERR_NO_MEMORY;
223 post_status:
224 req = async_req_new(mem_ctx);
225 if (req == NULL) {
226 return NULL;
228 if (async_post_error(req, ev, wbc_err)) {
229 return req;
231 TALLOC_FREE(req);
232 return NULL;
235 static wbcErr wb_connect_recv(struct async_req *req)
237 return async_req_simple_recv_wbcerr(req);
240 static struct winbindd_request *winbindd_request_copy(
241 TALLOC_CTX *mem_ctx,
242 const struct winbindd_request *req)
244 struct winbindd_request *result;
246 result = (struct winbindd_request *)TALLOC_MEMDUP(
247 mem_ctx, req, sizeof(struct winbindd_request));
248 if (result == NULL) {
249 return NULL;
252 if (result->extra_len == 0) {
253 return result;
256 result->extra_data.data = (char *)TALLOC_MEMDUP(
257 result, result->extra_data.data, result->extra_len);
258 if (result->extra_data.data == NULL) {
259 TALLOC_FREE(result);
260 return NULL;
262 return result;
265 struct wb_int_trans_state {
266 struct tevent_context *ev;
267 int fd;
268 struct winbindd_request *wb_req;
269 struct winbindd_response *wb_resp;
272 static void wb_int_trans_write_done(struct async_req *subreq);
273 static void wb_int_trans_read_done(struct async_req *subreq);
275 static struct async_req *wb_int_trans_send(TALLOC_CTX *mem_ctx,
276 struct tevent_context *ev, int fd,
277 struct winbindd_request *wb_req)
279 struct async_req *result;
280 struct async_req *subreq;
281 struct wb_int_trans_state *state;
283 if (!async_req_setup(mem_ctx, &result, &state,
284 struct wb_int_trans_state)) {
285 return NULL;
288 if (winbind_closed_fd(fd)) {
289 if (!async_post_error(result, ev,
290 WBC_ERR_WINBIND_NOT_AVAILABLE)) {
291 goto fail;
293 return result;
296 state->ev = ev;
297 state->fd = fd;
298 state->wb_req = wb_req;
300 state->wb_req->length = sizeof(struct winbindd_request);
301 state->wb_req->pid = getpid();
303 subreq = wb_req_write_send(state, state->ev, state->fd, state->wb_req);
304 if (subreq == NULL) {
305 goto fail;
307 subreq->async.fn = wb_int_trans_write_done;
308 subreq->async.priv = result;
310 return result;
312 fail:
313 TALLOC_FREE(result);
314 return NULL;
317 static void wb_int_trans_write_done(struct async_req *subreq)
319 struct async_req *req = talloc_get_type_abort(
320 subreq->async.priv, struct async_req);
321 struct wb_int_trans_state *state = talloc_get_type_abort(
322 req->private_data, struct wb_int_trans_state);
323 wbcErr wbc_err;
325 wbc_err = wb_req_write_recv(subreq);
326 TALLOC_FREE(subreq);
327 if (!WBC_ERROR_IS_OK(wbc_err)) {
328 async_req_error(req, wbc_err);
329 return;
332 subreq = wb_resp_read_send(state, state->ev, state->fd);
333 if (subreq == NULL) {
334 async_req_error(req, WBC_ERR_NO_MEMORY);
336 subreq->async.fn = wb_int_trans_read_done;
337 subreq->async.priv = req;
340 static void wb_int_trans_read_done(struct async_req *subreq)
342 struct async_req *req = talloc_get_type_abort(
343 subreq->async.priv, struct async_req);
344 struct wb_int_trans_state *state = talloc_get_type_abort(
345 req->private_data, struct wb_int_trans_state);
346 wbcErr wbc_err;
348 wbc_err = wb_resp_read_recv(subreq, state, &state->wb_resp);
349 TALLOC_FREE(subreq);
350 if (!WBC_ERROR_IS_OK(wbc_err)) {
351 async_req_error(req, wbc_err);
352 return;
355 async_req_done(req);
358 static wbcErr wb_int_trans_recv(struct async_req *req,
359 TALLOC_CTX *mem_ctx,
360 struct winbindd_response **presponse)
362 struct wb_int_trans_state *state = talloc_get_type_abort(
363 req->private_data, struct wb_int_trans_state);
364 wbcErr wbc_err;
366 if (async_req_is_wbcerr(req, &wbc_err)) {
367 return wbc_err;
370 *presponse = talloc_move(mem_ctx, &state->wb_resp);
371 return WBC_ERR_SUCCESS;
374 static const char *winbindd_socket_dir(void)
376 #ifdef SOCKET_WRAPPER
377 const char *env_dir;
379 env_dir = getenv(WINBINDD_SOCKET_DIR_ENVVAR);
380 if (env_dir) {
381 return env_dir;
383 #endif
385 return WINBINDD_SOCKET_DIR;
388 struct wb_open_pipe_state {
389 struct wb_context *wb_ctx;
390 struct tevent_context *ev;
391 bool need_priv;
392 struct winbindd_request wb_req;
395 static void wb_open_pipe_connect_nonpriv_done(struct async_req *subreq);
396 static void wb_open_pipe_ping_done(struct async_req *subreq);
397 static void wb_open_pipe_getpriv_done(struct async_req *subreq);
398 static void wb_open_pipe_connect_priv_done(struct async_req *subreq);
400 static struct async_req *wb_open_pipe_send(TALLOC_CTX *mem_ctx,
401 struct tevent_context *ev,
402 struct wb_context *wb_ctx,
403 bool need_priv)
405 struct async_req *result;
406 struct async_req *subreq;
407 struct wb_open_pipe_state *state;
409 if (!async_req_setup(mem_ctx, &result, &state,
410 struct wb_open_pipe_state)) {
411 return NULL;
413 state->wb_ctx = wb_ctx;
414 state->ev = ev;
415 state->need_priv = need_priv;
417 if (wb_ctx->fd != -1) {
418 close(wb_ctx->fd);
419 wb_ctx->fd = -1;
422 subreq = wb_connect_send(state, ev, wb_ctx, winbindd_socket_dir());
423 if (subreq == NULL) {
424 goto fail;
427 subreq->async.fn = wb_open_pipe_connect_nonpriv_done;
428 subreq->async.priv = result;
429 return result;
431 fail:
432 TALLOC_FREE(result);
433 return NULL;
436 static void wb_open_pipe_connect_nonpriv_done(struct async_req *subreq)
438 struct async_req *req = talloc_get_type_abort(
439 subreq->async.priv, struct async_req);
440 struct wb_open_pipe_state *state = talloc_get_type_abort(
441 req->private_data, struct wb_open_pipe_state);
442 wbcErr wbc_err;
444 wbc_err = wb_connect_recv(subreq);
445 TALLOC_FREE(subreq);
446 if (!WBC_ERROR_IS_OK(wbc_err)) {
447 state->wb_ctx->is_priv = true;
448 async_req_error(req, wbc_err);
449 return;
452 ZERO_STRUCT(state->wb_req);
453 state->wb_req.cmd = WINBINDD_INTERFACE_VERSION;
455 subreq = wb_int_trans_send(state, state->ev, state->wb_ctx->fd,
456 &state->wb_req);
457 if (async_req_nomem(subreq, req)) {
458 return;
461 subreq->async.fn = wb_open_pipe_ping_done;
462 subreq->async.priv = req;
465 static void wb_open_pipe_ping_done(struct async_req *subreq)
467 struct async_req *req = talloc_get_type_abort(
468 subreq->async.priv, struct async_req);
469 struct wb_open_pipe_state *state = talloc_get_type_abort(
470 req->private_data, struct wb_open_pipe_state);
471 struct winbindd_response *wb_resp;
472 wbcErr wbc_err;
474 wbc_err = wb_int_trans_recv(subreq, state, &wb_resp);
475 TALLOC_FREE(subreq);
476 if (!WBC_ERROR_IS_OK(wbc_err)) {
477 async_req_error(req, wbc_err);
478 return;
481 if (!state->need_priv) {
482 async_req_done(req);
483 return;
486 state->wb_req.cmd = WINBINDD_PRIV_PIPE_DIR;
488 subreq = wb_int_trans_send(state, state->ev, state->wb_ctx->fd,
489 &state->wb_req);
490 if (async_req_nomem(subreq, req)) {
491 return;
494 subreq->async.fn = wb_open_pipe_getpriv_done;
495 subreq->async.priv = req;
498 static void wb_open_pipe_getpriv_done(struct async_req *subreq)
500 struct async_req *req = talloc_get_type_abort(
501 subreq->async.priv, struct async_req);
502 struct wb_open_pipe_state *state = talloc_get_type_abort(
503 req->private_data, struct wb_open_pipe_state);
504 struct winbindd_response *wb_resp = NULL;
505 wbcErr wbc_err;
507 wbc_err = wb_int_trans_recv(subreq, state, &wb_resp);
508 TALLOC_FREE(subreq);
509 if (!WBC_ERROR_IS_OK(wbc_err)) {
510 async_req_error(req, wbc_err);
511 return;
514 close(state->wb_ctx->fd);
515 state->wb_ctx->fd = -1;
517 subreq = wb_connect_send(state, state->ev, state->wb_ctx,
518 (char *)wb_resp->extra_data.data);
519 TALLOC_FREE(wb_resp);
520 if (async_req_nomem(subreq, req)) {
521 return;
524 subreq->async.fn = wb_open_pipe_connect_priv_done;
525 subreq->async.priv = req;
528 static void wb_open_pipe_connect_priv_done(struct async_req *subreq)
530 struct async_req *req = talloc_get_type_abort(
531 subreq->async.priv, struct async_req);
532 struct wb_open_pipe_state *state = talloc_get_type_abort(
533 req->private_data, struct wb_open_pipe_state);
534 wbcErr wbc_err;
536 wbc_err = wb_connect_recv(subreq);
537 TALLOC_FREE(subreq);
538 if (!WBC_ERROR_IS_OK(wbc_err)) {
539 async_req_error(req, wbc_err);
540 return;
542 state->wb_ctx->is_priv = true;
543 async_req_done(req);
546 static wbcErr wb_open_pipe_recv(struct async_req *req)
548 return async_req_simple_recv_wbcerr(req);
551 struct wb_trans_state {
552 struct wb_trans_state *prev, *next;
553 struct wb_context *wb_ctx;
554 struct tevent_context *ev;
555 struct winbindd_request *wb_req;
556 struct winbindd_response *wb_resp;
557 int num_retries;
558 bool need_priv;
561 static void wb_trans_connect_done(struct async_req *subreq);
562 static void wb_trans_done(struct async_req *subreq);
563 static void wb_trans_retry_wait_done(struct async_req *subreq);
565 static void wb_trigger_trans(struct async_req *req)
567 struct wb_trans_state *state = talloc_get_type_abort(
568 req->private_data, struct wb_trans_state);
569 struct async_req *subreq;
571 if ((state->wb_ctx->fd == -1)
572 || (state->need_priv && !state->wb_ctx->is_priv)) {
574 subreq = wb_open_pipe_send(state, state->ev, state->wb_ctx,
575 state->need_priv);
576 if (async_req_nomem(subreq, req)) {
577 return;
579 subreq->async.fn = wb_trans_connect_done;
580 subreq->async.priv = req;
581 return;
584 subreq = wb_int_trans_send(state, state->ev, state->wb_ctx->fd,
585 state->wb_req);
586 if (async_req_nomem(subreq, req)) {
587 return;
589 subreq->async.fn = wb_trans_done;
590 subreq->async.priv = req;
593 struct async_req *wb_trans_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
594 struct wb_context *wb_ctx, bool need_priv,
595 const struct winbindd_request *wb_req)
597 struct async_req *result;
598 struct wb_trans_state *state;
600 if (!async_req_setup(mem_ctx, &result, &state,
601 struct wb_trans_state)) {
602 return NULL;
604 state->wb_ctx = wb_ctx;
605 state->ev = ev;
606 state->wb_req = winbindd_request_copy(state, wb_req);
607 if (state->wb_req == NULL) {
608 goto fail;
610 state->num_retries = 10;
611 state->need_priv = need_priv;
613 if (!async_req_enqueue(wb_ctx->queue, ev, result, wb_trigger_trans)) {
614 goto fail;
616 return result;
618 fail:
619 TALLOC_FREE(result);
620 return NULL;
623 static bool wb_trans_retry(struct async_req *req,
624 struct wb_trans_state *state,
625 wbcErr wbc_err)
627 struct async_req *subreq;
629 if (WBC_ERROR_IS_OK(wbc_err)) {
630 return false;
633 if (wbc_err == WBC_ERR_WINBIND_NOT_AVAILABLE) {
635 * Winbind not around or we can't connect to the pipe. Fail
636 * immediately.
638 async_req_error(req, wbc_err);
639 return true;
642 state->num_retries -= 1;
643 if (state->num_retries == 0) {
644 async_req_error(req, wbc_err);
645 return true;
649 * The transfer as such failed, retry after one second
652 if (state->wb_ctx->fd != -1) {
653 close(state->wb_ctx->fd);
654 state->wb_ctx->fd = -1;
657 subreq = async_wait_send(state, state->ev, timeval_set(1, 0));
658 if (async_req_nomem(subreq, req)) {
659 return true;
662 subreq->async.fn = wb_trans_retry_wait_done;
663 subreq->async.priv = req;
664 return true;
667 static void wb_trans_retry_wait_done(struct async_req *subreq)
669 struct async_req *req = talloc_get_type_abort(
670 subreq->async.priv, struct async_req);
671 struct wb_trans_state *state = talloc_get_type_abort(
672 req->private_data, struct wb_trans_state);
673 bool ret;
675 ret = async_wait_recv(subreq);
676 TALLOC_FREE(subreq);
677 if (ret) {
678 async_req_error(req, WBC_ERR_UNKNOWN_FAILURE);
679 return;
682 subreq = wb_open_pipe_send(state, state->ev, state->wb_ctx,
683 state->need_priv);
684 if (async_req_nomem(subreq, req)) {
685 return;
687 subreq->async.fn = wb_trans_connect_done;
688 subreq->async.priv = req;
691 static void wb_trans_connect_done(struct async_req *subreq)
693 struct async_req *req = talloc_get_type_abort(
694 subreq->async.priv, struct async_req);
695 struct wb_trans_state *state = talloc_get_type_abort(
696 req->private_data, struct wb_trans_state);
697 wbcErr wbc_err;
699 wbc_err = wb_open_pipe_recv(subreq);
700 TALLOC_FREE(subreq);
702 if (wb_trans_retry(req, state, wbc_err)) {
703 return;
706 subreq = wb_int_trans_send(state, state->ev, state->wb_ctx->fd,
707 state->wb_req);
708 if (async_req_nomem(subreq, req)) {
709 return;
712 subreq->async.fn = wb_trans_done;
713 subreq->async.priv = req;
716 static void wb_trans_done(struct async_req *subreq)
718 struct async_req *req = talloc_get_type_abort(
719 subreq->async.priv, struct async_req);
720 struct wb_trans_state *state = talloc_get_type_abort(
721 req->private_data, struct wb_trans_state);
722 wbcErr wbc_err;
724 wbc_err = wb_int_trans_recv(subreq, state, &state->wb_resp);
725 TALLOC_FREE(subreq);
727 if (wb_trans_retry(req, state, wbc_err)) {
728 return;
731 async_req_done(req);
734 wbcErr wb_trans_recv(struct async_req *req, TALLOC_CTX *mem_ctx,
735 struct winbindd_response **presponse)
737 struct wb_trans_state *state = talloc_get_type_abort(
738 req->private_data, struct wb_trans_state);
739 wbcErr wbc_err;
741 if (async_req_is_wbcerr(req, &wbc_err)) {
742 return wbc_err;
745 *presponse = talloc_move(mem_ctx, &state->wb_resp);
746 return WBC_ERR_SUCCESS;