Merge branch 'master' of ssh://git.samba.org/data/git/samba
[samba.git] / source3 / lib / wbclient.c
1 /*
2    Unix SMB/CIFS implementation.
3    Infrastructure for async winbind requests
4    Copyright (C) Volker Lendecke 2008
5
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.
10
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.
15
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/>.
18 */
19
20 #include "includes.h"
21 #include "winbindd/winbindd.h"
22 #include "winbindd/winbindd_proto.h"
23
24 static int make_nonstd_fd(int fd)
25 {
26         int i;
27         int sys_errno = 0;
28         int fds[3];
29         int num_fds = 0;
30
31         if (fd == -1) {
32                 return -1;
33         }
34         while (fd < 3) {
35                 fds[num_fds++] = fd;
36                 fd = dup(fd);
37                 if (fd == -1) {
38                         sys_errno = errno;
39                         break;
40                 }
41         }
42         for (i=0; i<num_fds; i++) {
43                 close(fds[i]);
44         }
45         if (fd == -1) {
46                 errno = sys_errno;
47         }
48         return fd;
49 }
50
51 /****************************************************************************
52  Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
53  else
54  if SYSV use O_NDELAY
55  if BSD use FNDELAY
56  Set close on exec also.
57 ****************************************************************************/
58
59 static int make_safe_fd(int fd)
60 {
61         int result, flags;
62         int new_fd = make_nonstd_fd(fd);
63
64         if (new_fd == -1) {
65                 goto fail;
66         }
67
68         /* Socket should be nonblocking. */
69
70 #ifdef O_NONBLOCK
71 #define FLAG_TO_SET O_NONBLOCK
72 #else
73 #ifdef SYSV
74 #define FLAG_TO_SET O_NDELAY
75 #else /* BSD */
76 #define FLAG_TO_SET FNDELAY
77 #endif
78 #endif
79
80         if ((flags = fcntl(new_fd, F_GETFL)) == -1) {
81                 goto fail;
82         }
83
84         flags |= FLAG_TO_SET;
85         if (fcntl(new_fd, F_SETFL, flags) == -1) {
86                 goto fail;
87         }
88
89 #undef FLAG_TO_SET
90
91         /* Socket should be closed on exec() */
92 #ifdef FD_CLOEXEC
93         result = flags = fcntl(new_fd, F_GETFD, 0);
94         if (flags >= 0) {
95                 flags |= FD_CLOEXEC;
96                 result = fcntl( new_fd, F_SETFD, flags );
97         }
98         if (result < 0) {
99                 goto fail;
100         }
101 #endif
102         return new_fd;
103
104  fail:
105         if (new_fd != -1) {
106                 int sys_errno = errno;
107                 close(new_fd);
108                 errno = sys_errno;
109         }
110         return -1;
111 }
112
113 static bool winbind_closed_fd(int fd)
114 {
115         struct timeval tv;
116         fd_set r_fds;
117
118         if (fd == -1) {
119                 return true;
120         }
121
122         FD_ZERO(&r_fds);
123         FD_SET(fd, &r_fds);
124         ZERO_STRUCT(tv);
125
126         if ((select(fd+1, &r_fds, NULL, NULL, &tv) == -1)
127             || FD_ISSET(fd, &r_fds)) {
128                 return true;
129         }
130
131         return false;
132 }
133
134 struct wb_context {
135         struct async_req_queue *queue;
136         int fd;
137         bool is_priv;
138 };
139
140 struct wb_context *wb_context_init(TALLOC_CTX *mem_ctx)
141 {
142         struct wb_context *result;
143
144         result = talloc(mem_ctx, struct wb_context);
145         if (result == NULL) {
146                 return NULL;
147         }
148         result->queue = async_req_queue_init(result);
149         if (result->queue == NULL) {
150                 TALLOC_FREE(result);
151                 return NULL;
152         }
153         result->fd = -1;
154         return result;
155 }
156
157 static struct async_req *wb_connect_send(TALLOC_CTX *mem_ctx,
158                                          struct event_context *ev,
159                                          struct wb_context *wb_ctx,
160                                          const char *dir)
161 {
162         struct async_req *req;
163         struct sockaddr_un sunaddr;
164         struct stat st;
165         char *path = NULL;
166         NTSTATUS status;
167
168         if (wb_ctx->fd != -1) {
169                 close(wb_ctx->fd);
170                 wb_ctx->fd = -1;
171         }
172
173         /* Check permissions on unix socket directory */
174
175         if (lstat(dir, &st) == -1) {
176                 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
177                 goto post_status;
178         }
179
180         if (!S_ISDIR(st.st_mode) ||
181             (st.st_uid != 0 && st.st_uid != geteuid())) {
182                 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
183                 goto post_status;
184         }
185
186         /* Connect to socket */
187
188         path = talloc_asprintf(talloc_tos(), "%s/%s", dir,
189                                WINBINDD_SOCKET_NAME);
190         if (path == NULL) {
191                 goto nomem;
192         }
193
194         sunaddr.sun_family = AF_UNIX;
195         strlcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path));
196         TALLOC_FREE(path);
197
198         /* If socket file doesn't exist, don't bother trying to connect
199            with retry.  This is an attempt to make the system usable when
200            the winbindd daemon is not running. */
201
202         if ((lstat(sunaddr.sun_path, &st) == -1)
203             || !S_ISSOCK(st.st_mode)
204             || (st.st_uid != 0 && st.st_uid != geteuid())) {
205                 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
206                 goto post_status;
207         }
208
209         wb_ctx->fd = make_safe_fd(socket(AF_UNIX, SOCK_STREAM, 0));
210         if (wb_ctx->fd == -1) {
211                 status = map_nt_error_from_unix(errno);
212                 goto post_status;
213         }
214
215         req = async_connect_send(mem_ctx, ev, wb_ctx->fd,
216                                  (struct sockaddr *)&sunaddr,
217                                  sizeof(sunaddr));
218         if (req == NULL) {
219                 goto nomem;
220         }
221         if (!async_req_set_timeout(req, ev, timeval_set(30, 0))) {
222                 TALLOC_FREE(req);
223                 goto nomem;
224         }
225
226         return req;
227
228  nomem:
229         status = NT_STATUS_NO_MEMORY;
230  post_status:
231         req = async_req_new(mem_ctx);
232         if (req == NULL) {
233                 return NULL;
234         }
235         if (async_post_status(req, ev, status)) {
236                 return req;
237         }
238         TALLOC_FREE(req);
239         return NULL;
240 }
241
242 static NTSTATUS wb_connect_recv(struct async_req *req)
243 {
244         int dummy;
245
246         return async_connect_recv(req, &dummy);
247 }
248
249 static struct winbindd_request *winbindd_request_copy(
250         TALLOC_CTX *mem_ctx,
251         const struct winbindd_request *req)
252 {
253         struct winbindd_request *result;
254
255         result = (struct winbindd_request *)TALLOC_MEMDUP(
256                 mem_ctx, req, sizeof(struct winbindd_request));
257         if (result == NULL) {
258                 return NULL;
259         }
260
261         if (result->extra_len == 0) {
262                 return result;
263         }
264
265         result->extra_data.data = (char *)TALLOC_MEMDUP(
266                 result, result->extra_data.data, result->extra_len);
267         if (result->extra_data.data == NULL) {
268                 TALLOC_FREE(result);
269                 return NULL;
270         }
271         return result;
272 }
273
274 struct wb_int_trans_state {
275         struct event_context *ev;
276         int fd;
277         struct winbindd_request *wb_req;
278         struct winbindd_response *wb_resp;
279 };
280
281 static void wb_int_trans_write_done(struct async_req *subreq);
282 static void wb_int_trans_read_done(struct async_req *subreq);
283
284 static struct async_req *wb_int_trans_send(TALLOC_CTX *mem_ctx,
285                                            struct event_context *ev, int fd,
286                                            struct winbindd_request *wb_req)
287 {
288         struct async_req *result;
289         struct async_req *subreq;
290         struct wb_int_trans_state *state;
291
292         result = async_req_new(mem_ctx);
293         if (result == NULL) {
294                 return NULL;
295         }
296         state = talloc(result, struct wb_int_trans_state);
297         if (state == NULL) {
298                 goto fail;
299         }
300         result->private_data = state;
301
302         if (winbind_closed_fd(fd)) {
303                 if (!async_post_status(result, ev,
304                                        NT_STATUS_PIPE_DISCONNECTED)) {
305                         goto fail;
306                 }
307                 return result;
308         }
309
310         state->ev = ev;
311         state->fd = fd;
312         state->wb_req = wb_req;
313
314         state->wb_req->length = sizeof(struct winbindd_request);
315         state->wb_req->pid = getpid();
316
317         subreq = wb_req_write_send(state, state->ev, state->fd, state->wb_req);
318         if (subreq == NULL) {
319                 goto fail;
320         }
321         subreq->async.fn = wb_int_trans_write_done;
322         subreq->async.priv = result;
323
324         return result;
325
326  fail:
327         TALLOC_FREE(result);
328         return NULL;
329 }
330
331 static void wb_int_trans_write_done(struct async_req *subreq)
332 {
333         struct async_req *req = talloc_get_type_abort(
334                 subreq->async.priv, struct async_req);
335         struct wb_int_trans_state *state = talloc_get_type_abort(
336                 req->private_data, struct wb_int_trans_state);
337         NTSTATUS status;
338
339         status = wb_req_write_recv(subreq);
340         TALLOC_FREE(subreq);
341         if (!NT_STATUS_IS_OK(status)) {
342                 async_req_error(req, status);
343                 return;
344         }
345
346         subreq = wb_resp_read_send(state, state->ev, state->fd);
347         if (subreq == NULL) {
348                 async_req_error(req, NT_STATUS_NO_MEMORY);
349         }
350         subreq->async.fn = wb_int_trans_read_done;
351         subreq->async.priv = req;
352 }
353
354 static void wb_int_trans_read_done(struct async_req *subreq)
355 {
356         struct async_req *req = talloc_get_type_abort(
357                 subreq->async.priv, struct async_req);
358         struct wb_int_trans_state *state = talloc_get_type_abort(
359                 req->private_data, struct wb_int_trans_state);
360         NTSTATUS status;
361
362         status = wb_resp_read_recv(subreq, state, &state->wb_resp);
363         TALLOC_FREE(subreq);
364         if (!NT_STATUS_IS_OK(status)) {
365                 async_req_error(req, status);
366                 return;
367         }
368
369         async_req_done(req);
370 }
371
372 static NTSTATUS wb_int_trans_recv(struct async_req *req,
373                                   TALLOC_CTX *mem_ctx,
374                                   struct winbindd_response **presponse)
375 {
376         struct wb_int_trans_state *state = talloc_get_type_abort(
377                 req->private_data, struct wb_int_trans_state);
378         NTSTATUS status;
379
380         if (async_req_is_error(req, &status)) {
381                 return status;
382         }
383
384         *presponse = talloc_move(mem_ctx, &state->wb_resp);
385         return NT_STATUS_OK;
386 }
387
388 static const char *winbindd_socket_dir(void)
389 {
390 #ifdef SOCKET_WRAPPER
391         const char *env_dir;
392
393         env_dir = getenv(WINBINDD_SOCKET_DIR_ENVVAR);
394         if (env_dir) {
395                 return env_dir;
396         }
397 #endif
398
399         return WINBINDD_SOCKET_DIR;
400 }
401
402 struct wb_open_pipe_state {
403         struct wb_context *wb_ctx;
404         struct event_context *ev;
405         bool need_priv;
406         struct winbindd_request wb_req;
407 };
408
409 static void wb_open_pipe_connect_nonpriv_done(struct async_req *subreq);
410 static void wb_open_pipe_ping_done(struct async_req *subreq);
411 static void wb_open_pipe_getpriv_done(struct async_req *subreq);
412 static void wb_open_pipe_connect_priv_done(struct async_req *subreq);
413
414 static struct async_req *wb_open_pipe_send(TALLOC_CTX *mem_ctx,
415                                            struct event_context *ev,
416                                            struct wb_context *wb_ctx,
417                                            bool need_priv)
418 {
419         struct async_req *result;
420         struct async_req *subreq;
421         struct wb_open_pipe_state *state;
422
423         result = async_req_new(mem_ctx);
424         if (result == NULL) {
425                 return NULL;
426         }
427         state = talloc(result, struct wb_open_pipe_state);
428         if (state == NULL) {
429                 goto fail;
430         }
431         result->private_data = state;
432
433         state->wb_ctx = wb_ctx;
434         state->ev = ev;
435         state->need_priv = need_priv;
436
437         if (wb_ctx->fd != -1) {
438                 close(wb_ctx->fd);
439                 wb_ctx->fd = -1;
440         }
441
442         subreq = wb_connect_send(state, ev, wb_ctx, winbindd_socket_dir());
443         if (subreq == NULL) {
444                 goto fail;
445         }
446
447         subreq->async.fn = wb_open_pipe_connect_nonpriv_done;
448         subreq->async.priv = result;
449         return result;
450
451  fail:
452         TALLOC_FREE(result);
453         return NULL;
454 }
455
456 static void wb_open_pipe_connect_nonpriv_done(struct async_req *subreq)
457 {
458         struct async_req *req = talloc_get_type_abort(
459                 subreq->async.priv, struct async_req);
460         struct wb_open_pipe_state *state = talloc_get_type_abort(
461                 req->private_data, struct wb_open_pipe_state);
462         NTSTATUS status;
463
464         status = wb_connect_recv(subreq);
465         TALLOC_FREE(subreq);
466         if (!NT_STATUS_IS_OK(status)) {
467                 state->wb_ctx->is_priv = true;
468                 async_req_error(req, status);
469                 return;
470         }
471
472         ZERO_STRUCT(state->wb_req);
473         state->wb_req.cmd = WINBINDD_INTERFACE_VERSION;
474
475         subreq = wb_int_trans_send(state, state->ev, state->wb_ctx->fd,
476                                    &state->wb_req);
477         if (async_req_nomem(subreq, req)) {
478                 return;
479         }
480
481         subreq->async.fn = wb_open_pipe_ping_done;
482         subreq->async.priv = req;
483 }
484
485 static void wb_open_pipe_ping_done(struct async_req *subreq)
486 {
487         struct async_req *req = talloc_get_type_abort(
488                 subreq->async.priv, struct async_req);
489         struct wb_open_pipe_state *state = talloc_get_type_abort(
490                 req->private_data, struct wb_open_pipe_state);
491         struct winbindd_response *wb_resp;
492         NTSTATUS status;
493
494         status = wb_int_trans_recv(subreq, state, &wb_resp);
495         TALLOC_FREE(subreq);
496         if (!NT_STATUS_IS_OK(status)) {
497                 async_req_error(req, status);
498                 return;
499         }
500
501         if (!state->need_priv) {
502                 async_req_done(req);
503                 return;
504         }
505
506         state->wb_req.cmd = WINBINDD_PRIV_PIPE_DIR;
507
508         subreq = wb_int_trans_send(state, state->ev, state->wb_ctx->fd,
509                                    &state->wb_req);
510         if (async_req_nomem(subreq, req)) {
511                 return;
512         }
513
514         subreq->async.fn = wb_open_pipe_getpriv_done;
515         subreq->async.priv = req;
516 }
517
518 static void wb_open_pipe_getpriv_done(struct async_req *subreq)
519 {
520         struct async_req *req = talloc_get_type_abort(
521                 subreq->async.priv, struct async_req);
522         struct wb_open_pipe_state *state = talloc_get_type_abort(
523                 req->private_data, struct wb_open_pipe_state);
524         struct winbindd_response *wb_resp = NULL;
525         NTSTATUS status;
526
527         status = wb_int_trans_recv(subreq, state, &wb_resp);
528         TALLOC_FREE(subreq);
529         if (!NT_STATUS_IS_OK(status)) {
530                 async_req_error(req, status);
531                 return;
532         }
533
534         close(state->wb_ctx->fd);
535         state->wb_ctx->fd = -1;
536
537         subreq = wb_connect_send(state, state->ev, state->wb_ctx,
538                                  (char *)wb_resp->extra_data.data);
539         TALLOC_FREE(wb_resp);
540         if (async_req_nomem(subreq, req)) {
541                 return;
542         }
543
544         subreq->async.fn = wb_open_pipe_connect_priv_done;
545         subreq->async.priv = req;
546 }
547
548 static void wb_open_pipe_connect_priv_done(struct async_req *subreq)
549 {
550         struct async_req *req = talloc_get_type_abort(
551                 subreq->async.priv, struct async_req);
552         struct wb_open_pipe_state *state = talloc_get_type_abort(
553                 req->private_data, struct wb_open_pipe_state);
554         NTSTATUS status;
555
556         status = wb_connect_recv(subreq);
557         TALLOC_FREE(subreq);
558         if (!NT_STATUS_IS_OK(status)) {
559                 async_req_error(req, status);
560                 return;
561         }
562         state->wb_ctx->is_priv = true;
563         async_req_done(req);
564 }
565
566 static NTSTATUS wb_open_pipe_recv(struct async_req *req)
567 {
568         return async_req_simple_recv(req);
569 }
570
571 struct wb_trans_state {
572         struct wb_trans_state *prev, *next;
573         struct wb_context *wb_ctx;
574         struct event_context *ev;
575         struct winbindd_request *wb_req;
576         struct winbindd_response *wb_resp;
577         int num_retries;
578         bool need_priv;
579 };
580
581 static void wb_trans_connect_done(struct async_req *subreq);
582 static void wb_trans_done(struct async_req *subreq);
583 static void wb_trans_retry_wait_done(struct async_req *subreq);
584
585 static void wb_trigger_trans(struct async_req *req)
586 {
587         struct wb_trans_state *state = talloc_get_type_abort(
588                 req->private_data, struct wb_trans_state);
589         struct async_req *subreq;
590
591         if ((state->wb_ctx->fd == -1)
592             || (state->need_priv && !state->wb_ctx->is_priv)) {
593
594                 subreq = wb_open_pipe_send(state, state->ev, state->wb_ctx,
595                                            state->need_priv);
596                 if (async_req_nomem(subreq, req)) {
597                         return;
598                 }
599                 subreq->async.fn = wb_trans_connect_done;
600                 subreq->async.priv = req;
601                 return;
602         }
603
604         subreq = wb_int_trans_send(state, state->ev, state->wb_ctx->fd,
605                                    state->wb_req);
606         if (async_req_nomem(subreq, req)) {
607                 return;
608         }
609         subreq->async.fn = wb_trans_done;
610         subreq->async.priv = req;
611 }
612
613 struct async_req *wb_trans_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
614                                 struct wb_context *wb_ctx, bool need_priv,
615                                 const struct winbindd_request *wb_req)
616 {
617         struct async_req *result;
618         struct wb_trans_state *state;
619
620         result = async_req_new(mem_ctx);
621         if (result == NULL) {
622                 return NULL;
623         }
624         state = talloc(result, struct wb_trans_state);
625         if (state == NULL) {
626                 goto fail;
627         }
628         result->private_data = state;
629
630         state->wb_ctx = wb_ctx;
631         state->ev = ev;
632         state->wb_req = winbindd_request_copy(state, wb_req);
633         if (state->wb_req == NULL) {
634                 goto fail;
635         }
636         state->num_retries = 10;
637         state->need_priv = need_priv;
638
639         if (!async_req_enqueue(wb_ctx->queue, ev, result, wb_trigger_trans)) {
640                 goto fail;
641         }
642         return result;
643
644  fail:
645         TALLOC_FREE(result);
646         return NULL;
647 }
648
649 static bool wb_trans_retry(struct async_req *req,
650                            struct wb_trans_state *state,
651                            NTSTATUS status)
652 {
653         struct async_req *subreq;
654
655         if (NT_STATUS_IS_OK(status)) {
656                 return false;
657         }
658
659         if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)
660             || NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
661                 /*
662                  * Winbind not around or we can't connect to the pipe. Fail
663                  * immediately.
664                  */
665                 async_req_error(req, status);
666                 return true;
667         }
668
669         state->num_retries -= 1;
670         if (state->num_retries == 0) {
671                 async_req_error(req, status);
672                 return true;
673         }
674
675         /*
676          * The transfer as such failed, retry after one second
677          */
678
679         if (state->wb_ctx->fd != -1) {
680                 close(state->wb_ctx->fd);
681                 state->wb_ctx->fd = -1;
682         }
683
684         subreq = async_wait_send(state, state->ev, timeval_set(1, 0));
685         if (async_req_nomem(subreq, req)) {
686                 return true;
687         }
688
689         subreq->async.fn = wb_trans_retry_wait_done;
690         subreq->async.priv = req;
691         return true;
692 }
693
694 static void wb_trans_retry_wait_done(struct async_req *subreq)
695 {
696         struct async_req *req = talloc_get_type_abort(
697                 subreq->async.priv, struct async_req);
698         struct wb_trans_state *state = talloc_get_type_abort(
699                 req->private_data, struct wb_trans_state);
700         NTSTATUS status;
701
702         status = async_wait_recv(subreq);
703         TALLOC_FREE(subreq);
704         if (!NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
705                 async_req_error(req, status);
706                 return;
707         }
708
709         subreq = wb_open_pipe_send(state, state->ev, state->wb_ctx,
710                                    state->need_priv);
711         if (async_req_nomem(subreq, req)) {
712                 return;
713         }
714         subreq->async.fn = wb_trans_connect_done;
715         subreq->async.priv = req;
716 }
717
718 static void wb_trans_connect_done(struct async_req *subreq)
719 {
720         struct async_req *req = talloc_get_type_abort(
721                 subreq->async.priv, struct async_req);
722         struct wb_trans_state *state = talloc_get_type_abort(
723                 req->private_data, struct wb_trans_state);
724         NTSTATUS status;
725
726         status = wb_open_pipe_recv(subreq);
727         TALLOC_FREE(subreq);
728
729         if (wb_trans_retry(req, state, status)) {
730                 return;
731         }
732
733         subreq = wb_int_trans_send(state, state->ev, state->wb_ctx->fd,
734                                    state->wb_req);
735         if (async_req_nomem(subreq, req)) {
736                 return;
737         }
738
739         subreq->async.fn = wb_trans_done;
740         subreq->async.priv = req;
741 }
742
743 static void wb_trans_done(struct async_req *subreq)
744 {
745         struct async_req *req = talloc_get_type_abort(
746                 subreq->async.priv, struct async_req);
747         struct wb_trans_state *state = talloc_get_type_abort(
748                 req->private_data, struct wb_trans_state);
749         NTSTATUS status;
750
751         status = wb_int_trans_recv(subreq, state, &state->wb_resp);
752         TALLOC_FREE(subreq);
753
754         if (wb_trans_retry(req, state, status)) {
755                 return;
756         }
757
758         async_req_done(req);
759 }
760
761 NTSTATUS wb_trans_recv(struct async_req *req, TALLOC_CTX *mem_ctx,
762                        struct winbindd_response **presponse)
763 {
764         struct wb_trans_state *state = talloc_get_type_abort(
765                 req->private_data, struct wb_trans_state);
766         NTSTATUS status;
767
768         if (async_req_is_error(req, &status)) {
769                 return status;
770         }
771
772         *presponse = talloc_move(mem_ctx, &state->wb_resp);
773         return NT_STATUS_OK;
774 }