Revert "libwbclient4: Remove unused composite-based functions"
[metze/samba/wip.git] / source4 / libcli / wbclient / wbclient.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Winbind client library.
5
6    Copyright (C) 2008 Kai Blin  <kai@samba.org>
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include <tevent.h>
24 #include "lib/util/tevent_unix.h"
25 #include "libcli/wbclient/wbclient.h"
26 #include "nsswitch/wb_reqtrans.h"
27 #include "system/network.h"
28 #include "libcli/util/error.h"
29 #include "libcli/security/dom_sid.h"
30
31 /**
32  * Initialize the wbclient context, talloc_free() when done.
33  *
34  * \param mem_ctx talloc context to allocate memory from
35  * \param msg_ctx message context to use
36  * \param
37  */
38 struct wbc_context *wbc_init(TALLOC_CTX *mem_ctx,
39                              struct imessaging_context *msg_ctx,
40                              struct tevent_context *event_ctx)
41 {
42         struct wbc_context *ctx;
43
44         ctx = talloc(mem_ctx, struct wbc_context);
45         if (ctx == NULL) return NULL;
46
47         ctx->event_ctx = event_ctx;
48
49         ctx->irpc_handle = irpc_binding_handle_by_name(ctx, msg_ctx,
50                                                        "winbind_server",
51                                                        &ndr_table_winbind);
52         if (ctx->irpc_handle == NULL) {
53                 talloc_free(ctx);
54                 return NULL;
55         }
56
57         return ctx;
58 }
59
60 struct wbc_idmap_state {
61         struct composite_context *ctx;
62         struct winbind_get_idmap *req;
63         struct id_map *ids;
64 };
65
66 static void sids_to_xids_recv_ids(struct tevent_req *subreq);
67
68 struct composite_context *wbc_sids_to_xids_send(struct wbc_context *wbc_ctx,
69                                                 TALLOC_CTX *mem_ctx,
70                                                 uint32_t count,
71                                                 struct id_map *ids)
72 {
73         struct composite_context *ctx;
74         struct wbc_idmap_state *state;
75         struct tevent_req *subreq;
76
77         DEBUG(5, ("wbc_sids_to_xids called\n"));
78
79         ctx = composite_create(mem_ctx, wbc_ctx->event_ctx);
80         if (ctx == NULL) return NULL;
81
82         state = talloc(ctx, struct wbc_idmap_state);
83         if (composite_nomem(state, ctx)) return ctx;
84         ctx->private_data = state;
85
86         state->req = talloc(state, struct winbind_get_idmap);
87         if (composite_nomem(state->req, ctx)) return ctx;
88
89         state->req->in.count = count;
90         state->req->in.level = WINBIND_IDMAP_LEVEL_SIDS_TO_XIDS;
91         state->req->in.ids = ids;
92         state->ctx = ctx;
93
94         subreq = dcerpc_winbind_get_idmap_r_send(state,
95                                                  wbc_ctx->event_ctx,
96                                                  wbc_ctx->irpc_handle,
97                                                  state->req);
98         if (composite_nomem(subreq, ctx)) return ctx;
99
100         tevent_req_set_callback(subreq, sids_to_xids_recv_ids, state);
101
102         return ctx;
103 }
104
105 static void sids_to_xids_recv_ids(struct tevent_req *subreq)
106 {
107         struct wbc_idmap_state *state =
108                 tevent_req_callback_data(subreq,
109                 struct wbc_idmap_state);
110
111         state->ctx->status = dcerpc_winbind_get_idmap_r_recv(subreq, state);
112         TALLOC_FREE(subreq);
113         if (!composite_is_ok(state->ctx)) return;
114
115         state->ids = state->req->out.ids;
116         composite_done(state->ctx);
117 }
118
119 NTSTATUS wbc_sids_to_xids_recv(struct composite_context *ctx,
120                                struct id_map **ids)
121 {
122         NTSTATUS status = composite_wait(ctx);
123                 DEBUG(5, ("wbc_sids_to_xids_recv called\n"));
124         if (NT_STATUS_IS_OK(status)) {
125                 struct wbc_idmap_state *state = talloc_get_type_abort(
126                                                         ctx->private_data,
127                                                         struct wbc_idmap_state);
128                 *ids = state->ids;
129         }
130
131         return status;
132 }
133
134 static void xids_to_sids_recv_ids(struct tevent_req *subreq);
135
136 struct composite_context *wbc_xids_to_sids_send(struct wbc_context *wbc_ctx,
137                                                 TALLOC_CTX *mem_ctx,
138                                                 uint32_t count,
139                                                 struct id_map *ids)
140 {
141         struct composite_context *ctx;
142         struct wbc_idmap_state *state;
143         struct tevent_req *subreq;
144
145         DEBUG(5, ("wbc_xids_to_sids called\n"));
146
147         ctx = composite_create(mem_ctx, wbc_ctx->event_ctx);
148         if (ctx == NULL) return NULL;
149
150         state = talloc(ctx, struct wbc_idmap_state);
151         if (composite_nomem(state, ctx)) return ctx;
152         ctx->private_data = state;
153
154         state->req = talloc(state, struct winbind_get_idmap);
155         if (composite_nomem(state->req, ctx)) return ctx;
156
157         state->req->in.count = count;
158         state->req->in.level = WINBIND_IDMAP_LEVEL_XIDS_TO_SIDS;
159         state->req->in.ids = ids;
160         state->ctx = ctx;
161
162         subreq = dcerpc_winbind_get_idmap_r_send(state,
163                                                  wbc_ctx->event_ctx,
164                                                  wbc_ctx->irpc_handle,
165                                                  state->req);
166         if (composite_nomem(subreq, ctx)) return ctx;
167
168         tevent_req_set_callback(subreq, xids_to_sids_recv_ids, state);
169
170         return ctx;
171 }
172
173 static void xids_to_sids_recv_ids(struct tevent_req *subreq)
174 {
175         struct wbc_idmap_state *state =
176                 tevent_req_callback_data(subreq,
177                 struct wbc_idmap_state);
178
179         state->ctx->status = dcerpc_winbind_get_idmap_r_recv(subreq, state);
180         TALLOC_FREE(subreq);
181         if (!composite_is_ok(state->ctx)) return;
182
183         state->ids = state->req->out.ids;
184         composite_done(state->ctx);
185 }
186
187 NTSTATUS wbc_xids_to_sids_recv(struct composite_context *ctx,
188                                struct id_map **ids)
189 {
190         NTSTATUS status = composite_wait(ctx);
191                 DEBUG(5, ("wbc_xids_to_sids_recv called\n"));
192         if (NT_STATUS_IS_OK(status)) {
193                 struct wbc_idmap_state *state = talloc_get_type_abort(
194                                                         ctx->private_data,
195                                                         struct wbc_idmap_state);
196                 *ids = state->ids;
197         }
198
199         return status;
200 }
201
202 static int wb_simple_trans(struct tevent_context *ev, int fd,
203                            struct winbindd_request *wb_req,
204                            TALLOC_CTX *mem_ctx,
205                            struct winbindd_response **resp, int *err)
206 {
207         struct tevent_req *req;
208         bool polled;
209         int ret;
210
211         req = wb_simple_trans_send(ev, ev, NULL, fd, wb_req);
212         if (req == NULL) {
213                 *err = ENOMEM;
214                 return -1;
215         }
216
217         polled = tevent_req_poll(req, ev);
218         if (!polled) {
219                 *err = errno;
220                 DEBUG(10, ("tevent_req_poll returned %s\n",
221                            strerror(*err)));
222                 return -1;
223         }
224
225         ret = wb_simple_trans_recv(req, mem_ctx, resp, err);
226         TALLOC_FREE(req);
227         return ret;
228 }
229
230 static const char *winbindd_socket_dir(void)
231 {
232 #ifdef SOCKET_WRAPPER
233         const char *env_dir;
234
235         env_dir = getenv(WINBINDD_SOCKET_DIR_ENVVAR);
236         if (env_dir) {
237                 return env_dir;
238         }
239 #endif
240
241         return WINBINDD_SOCKET_DIR;
242 }
243
244 static int winbindd_pipe_sock(void)
245 {
246         struct sockaddr_un sunaddr = {};
247         int ret, fd;
248         char *path;
249
250         ret = asprintf(&path, "%s/%s", winbindd_socket_dir(),
251                        WINBINDD_SOCKET_NAME);
252         if (ret == -1) {
253                 errno = ENOMEM;
254                 return -1;
255         }
256         sunaddr.sun_family = AF_UNIX;
257         strlcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path));
258         free(path);
259
260         fd = socket(AF_UNIX, SOCK_STREAM, 0);
261         if (fd == -1) {
262                 return -1;
263         }
264
265         ret = connect(fd, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
266         if (ret == -1) {
267                 int err = errno;
268                 close(fd);
269                 errno = err;
270                 return -1;
271         }
272
273         return fd;
274 }
275
276 NTSTATUS wbc_sids_to_xids(struct tevent_context *ev, struct id_map *ids,
277                           uint32_t count)
278 {
279         TALLOC_CTX *mem_ctx;
280         struct winbindd_request req = {};
281         struct winbindd_response *resp;
282         uint32_t i;
283         int fd, ret, err;
284         char *sids, *p;
285         size_t sidslen;
286
287         fd = winbindd_pipe_sock();
288         if (fd == -1) {
289                 return map_nt_error_from_unix_common(errno);
290         }
291
292         mem_ctx = talloc_new(NULL);
293         if (mem_ctx == NULL) {
294                 close(fd);
295                 return NT_STATUS_NO_MEMORY;
296         }
297
298         sidslen = count * (DOM_SID_STR_BUFLEN + 1);
299
300         sids = talloc_array(mem_ctx, char, sidslen);
301         if (sids == NULL) {
302                 close(fd);
303                 TALLOC_FREE(mem_ctx);
304                 return NT_STATUS_NO_MEMORY;
305         }
306
307         p = sids;
308         for (i=0; i<count; i++) {
309                 p += dom_sid_string_buf(ids[i].sid, p, sidslen - (p - sids));
310                 *p++ = '\n';
311         }
312         *p++ = '\0';
313
314         DEBUG(10, ("sids=\n%s", sids));
315
316         req.length = sizeof(struct winbindd_request);
317         req.cmd = WINBINDD_SIDS_TO_XIDS;
318         req.pid = getpid();
319         req.extra_data.data = sids;
320         req.extra_len = sidslen;
321
322         ret = wb_simple_trans(ev, fd, &req, mem_ctx, &resp, &err);
323         if (ret == -1) {
324                 return map_nt_error_from_unix_common(err);
325         }
326
327         close(fd);
328
329         p = resp->extra_data.data;
330
331         for (i=0; i<count; i++) {
332                 struct unixid *id = &ids[i].xid;
333                 char *q;
334
335                 switch (p[0]) {
336                 case 'U':
337                         id->type = ID_TYPE_UID;
338                         id->id = strtoul(p+1, &q, 10);
339                         break;
340                 case 'G':
341                         id->type = ID_TYPE_GID;
342                         id->id = strtoul(p+1, &q, 10);
343                         break;
344                 case 'B':
345                         id->type = ID_TYPE_BOTH;
346                         id->id = strtoul(p+1, &q, 10);
347                         break;
348                 default:
349                         id->type = ID_TYPE_NOT_SPECIFIED;
350                         id->id = UINT32_MAX;
351                         q = strchr(p, '\n');
352                         break;
353                 };
354                 ids[i].status = ID_MAPPED;
355
356                 if (q == NULL || q[0] != '\n') {
357                         TALLOC_FREE(mem_ctx);
358                         return NT_STATUS_INTERNAL_ERROR;
359                 }
360                 p = q+1;
361         }
362
363         return NT_STATUS_OK;
364 }
365
366 struct wbc_id_to_sid_state {
367         struct winbindd_request wbreq;
368         struct dom_sid sid;
369 };
370
371 static void wbc_id_to_sid_done(struct tevent_req *subreq);
372
373 static struct tevent_req *wbc_id_to_sid_send(TALLOC_CTX *mem_ctx,
374                                              struct tevent_context *ev,
375                                              int fd, const struct unixid *id)
376 {
377         struct tevent_req *req, *subreq;
378         struct wbc_id_to_sid_state *state;
379
380         req = tevent_req_create(mem_ctx, &state, struct wbc_id_to_sid_state);
381         if (req == NULL) {
382                 return NULL;
383         }
384
385         switch(id->type) {
386         case ID_TYPE_UID:
387                 state->wbreq.cmd = WINBINDD_UID_TO_SID;
388                 state->wbreq.data.uid = id->id;
389                 break;
390         case ID_TYPE_GID:
391                 state->wbreq.cmd = WINBINDD_GID_TO_SID;
392                 state->wbreq.data.gid = id->id;
393                 break;
394         default:
395                 tevent_req_error(req, ENOENT);
396                 return tevent_req_post(req, ev);
397         }
398
399         subreq = wb_simple_trans_send(state, ev, NULL, fd, &state->wbreq);
400         if (tevent_req_nomem(subreq, req)) {
401                 return tevent_req_post(req, ev);
402         }
403         tevent_req_set_callback(subreq, wbc_id_to_sid_done, req);
404         return req;
405 }
406
407 static void wbc_id_to_sid_done(struct tevent_req *subreq)
408 {
409         struct tevent_req *req = tevent_req_callback_data(
410                 subreq, struct tevent_req);
411         struct wbc_id_to_sid_state *state = tevent_req_data(
412                 req, struct wbc_id_to_sid_state);
413         struct winbindd_response *wbresp;
414         int ret, err;
415
416         ret = wb_simple_trans_recv(subreq, state, &wbresp, &err);
417         TALLOC_FREE(subreq);
418         if (ret == -1) {
419                 tevent_req_error(req, err);
420                 return;
421         }
422         if ((wbresp->result != WINBINDD_OK) ||
423             !dom_sid_parse(wbresp->data.sid.sid, &state->sid)) {
424                 tevent_req_error(req, ENOENT);
425                 return;
426         }
427         tevent_req_done(req);
428 }
429
430 static int wbc_id_to_sid_recv(struct tevent_req *req, struct dom_sid *sid)
431 {
432         struct wbc_id_to_sid_state *state = tevent_req_data(
433                 req, struct wbc_id_to_sid_state);
434         int err;
435
436         if (tevent_req_is_unix_error(req, &err)) {
437                 return err;
438         }
439         sid_copy(sid, &state->sid);
440         return 0;
441 }
442
443 struct wbc_ids_to_sids_state {
444         struct tevent_context *ev;
445         int fd;
446         struct id_map *ids;
447         uint32_t count;
448         uint32_t idx;
449 };
450
451 static void wbc_ids_to_sids_done(struct tevent_req *subreq);
452
453 static struct tevent_req *wbc_ids_to_sids_send(
454         TALLOC_CTX *mem_ctx, struct tevent_context *ev,
455         int fd, struct id_map *ids, uint32_t count)
456 {
457         struct tevent_req *req, *subreq;
458         struct wbc_ids_to_sids_state *state;
459
460         req = tevent_req_create(mem_ctx, &state,
461                                 struct wbc_ids_to_sids_state);
462         if (req == NULL) {
463                 return NULL;
464         }
465         state->ev = ev;
466         state->fd = fd;
467         state->ids = ids;
468         state->count = count;
469
470         if (count == 0) {
471                 tevent_req_done(req);
472                 return tevent_req_post(req, ev);
473         }
474
475         subreq = wbc_id_to_sid_send(state, state->ev, state->fd,
476                                     &state->ids[state->idx].xid);
477         if (tevent_req_nomem(subreq, req)) {
478                 return tevent_req_post(req, ev);
479         }
480         tevent_req_set_callback(subreq, wbc_ids_to_sids_done, req);
481         return req;
482 }
483
484 static void wbc_ids_to_sids_done(struct tevent_req *subreq)
485 {
486         struct tevent_req *req = tevent_req_callback_data(
487                 subreq, struct tevent_req);
488         struct wbc_ids_to_sids_state *state = tevent_req_data(
489                 req, struct wbc_ids_to_sids_state);
490         struct id_map *id;
491         struct dom_sid sid;
492         int ret;
493
494         ret = wbc_id_to_sid_recv(subreq, &sid);
495         TALLOC_FREE(subreq);
496
497         id = &state->ids[state->idx];
498         if (ret == 0) {
499                 id->status = ID_MAPPED;
500                 id->sid = dom_sid_dup(state->ids, &sid);
501                 if (id->sid == NULL) {
502                         tevent_req_error(req, ENOMEM);
503                         return;
504                 }
505         } else {
506                 id->status = ID_UNMAPPED;
507                 id->sid = NULL;
508         }
509
510         state->idx += 1;
511         if (state->idx == state->count) {
512                 tevent_req_done(req);
513                 return;
514         }
515
516         subreq = wbc_id_to_sid_send(state, state->ev, state->fd,
517                                     &state->ids[state->idx].xid);
518         if (tevent_req_nomem(subreq, req)) {
519                 return;
520         }
521         tevent_req_set_callback(subreq, wbc_ids_to_sids_done, req);
522 }
523
524 static int wbc_ids_to_sids_recv(struct tevent_req *req)
525 {
526         int err;
527         if (tevent_req_is_unix_error(req, &err)) {
528                 return err;
529         }
530         return 0;
531 }
532
533 NTSTATUS wbc_xids_to_sids(struct tevent_context *ev, struct id_map *ids,
534                           uint32_t count)
535 {
536         struct tevent_req *req;
537         NTSTATUS status;
538         bool polled;
539         int ret, fd;
540
541         DEBUG(5, ("wbc_xids_to_sids called: %u ids\n", (unsigned)count));
542
543         fd = winbindd_pipe_sock();
544         if (fd == -1) {
545                 status = map_nt_error_from_unix_common(errno);
546                 DEBUG(10, ("winbindd_pipe_sock returned %s\n",
547                            strerror(errno)));
548                 return status;
549         }
550
551         req = wbc_ids_to_sids_send(ev, ev, fd, ids, count);
552         if (req == NULL) {
553                 status = NT_STATUS_NO_MEMORY;
554                 goto done;
555         }
556
557         polled = tevent_req_poll(req, ev);
558         if (!polled) {
559                 status = map_nt_error_from_unix_common(errno);
560                 DEBUG(10, ("tevent_req_poll returned %s\n",
561                            strerror(errno)));
562                 goto done;
563         }
564
565         ret = wbc_ids_to_sids_recv(req);
566         TALLOC_FREE(req);
567         if (ret != 0) {
568                 status = map_nt_error_from_unix_common(ret);
569                 DEBUG(10, ("tevent_req_poll returned %s\n",
570                            strerror(ret)));
571         } else {
572                 status = NT_STATUS_OK;
573         }
574
575 done:
576         close(fd);
577         return status;
578 }