libwbclient4: Add wbc_sids_to_xids
[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 "libcli/wbclient/wbclient.h"
25 #include "nsswitch/wb_reqtrans.h"
26 #include "system/network.h"
27 #include "libcli/util/error.h"
28 #include "libcli/security/dom_sid.h"
29
30 /**
31  * Initialize the wbclient context, talloc_free() when done.
32  *
33  * \param mem_ctx talloc context to allocate memory from
34  * \param msg_ctx message context to use
35  * \param
36  */
37 struct wbc_context *wbc_init(TALLOC_CTX *mem_ctx,
38                              struct imessaging_context *msg_ctx,
39                              struct tevent_context *event_ctx)
40 {
41         struct wbc_context *ctx;
42
43         ctx = talloc(mem_ctx, struct wbc_context);
44         if (ctx == NULL) return NULL;
45
46         ctx->event_ctx = event_ctx;
47
48         ctx->irpc_handle = irpc_binding_handle_by_name(ctx, msg_ctx,
49                                                        "winbind_server",
50                                                        &ndr_table_winbind);
51         if (ctx->irpc_handle == NULL) {
52                 talloc_free(ctx);
53                 return NULL;
54         }
55
56         return ctx;
57 }
58
59 struct wbc_idmap_state {
60         struct composite_context *ctx;
61         struct winbind_get_idmap *req;
62         struct id_map *ids;
63 };
64
65 static void sids_to_xids_recv_ids(struct tevent_req *subreq);
66
67 struct composite_context *wbc_sids_to_xids_send(struct wbc_context *wbc_ctx,
68                                                 TALLOC_CTX *mem_ctx,
69                                                 uint32_t count,
70                                                 struct id_map *ids)
71 {
72         struct composite_context *ctx;
73         struct wbc_idmap_state *state;
74         struct tevent_req *subreq;
75
76         DEBUG(5, ("wbc_sids_to_xids called\n"));
77
78         ctx = composite_create(mem_ctx, wbc_ctx->event_ctx);
79         if (ctx == NULL) return NULL;
80
81         state = talloc(ctx, struct wbc_idmap_state);
82         if (composite_nomem(state, ctx)) return ctx;
83         ctx->private_data = state;
84
85         state->req = talloc(state, struct winbind_get_idmap);
86         if (composite_nomem(state->req, ctx)) return ctx;
87
88         state->req->in.count = count;
89         state->req->in.level = WINBIND_IDMAP_LEVEL_SIDS_TO_XIDS;
90         state->req->in.ids = ids;
91         state->ctx = ctx;
92
93         subreq = dcerpc_winbind_get_idmap_r_send(state,
94                                                  wbc_ctx->event_ctx,
95                                                  wbc_ctx->irpc_handle,
96                                                  state->req);
97         if (composite_nomem(subreq, ctx)) return ctx;
98
99         tevent_req_set_callback(subreq, sids_to_xids_recv_ids, state);
100
101         return ctx;
102 }
103
104 static void sids_to_xids_recv_ids(struct tevent_req *subreq)
105 {
106         struct wbc_idmap_state *state =
107                 tevent_req_callback_data(subreq,
108                 struct wbc_idmap_state);
109
110         state->ctx->status = dcerpc_winbind_get_idmap_r_recv(subreq, state);
111         TALLOC_FREE(subreq);
112         if (!composite_is_ok(state->ctx)) return;
113
114         state->ids = state->req->out.ids;
115         composite_done(state->ctx);
116 }
117
118 NTSTATUS wbc_sids_to_xids_recv(struct composite_context *ctx,
119                                struct id_map **ids)
120 {
121         NTSTATUS status = composite_wait(ctx);
122                 DEBUG(5, ("wbc_sids_to_xids_recv called\n"));
123         if (NT_STATUS_IS_OK(status)) {
124                 struct wbc_idmap_state *state = talloc_get_type_abort(
125                                                         ctx->private_data,
126                                                         struct wbc_idmap_state);
127                 *ids = state->ids;
128         }
129
130         return status;
131 }
132
133 static void xids_to_sids_recv_ids(struct tevent_req *subreq);
134
135 struct composite_context *wbc_xids_to_sids_send(struct wbc_context *wbc_ctx,
136                                                 TALLOC_CTX *mem_ctx,
137                                                 uint32_t count,
138                                                 struct id_map *ids)
139 {
140         struct composite_context *ctx;
141         struct wbc_idmap_state *state;
142         struct tevent_req *subreq;
143
144         DEBUG(5, ("wbc_xids_to_sids called\n"));
145
146         ctx = composite_create(mem_ctx, wbc_ctx->event_ctx);
147         if (ctx == NULL) return NULL;
148
149         state = talloc(ctx, struct wbc_idmap_state);
150         if (composite_nomem(state, ctx)) return ctx;
151         ctx->private_data = state;
152
153         state->req = talloc(state, struct winbind_get_idmap);
154         if (composite_nomem(state->req, ctx)) return ctx;
155
156         state->req->in.count = count;
157         state->req->in.level = WINBIND_IDMAP_LEVEL_XIDS_TO_SIDS;
158         state->req->in.ids = ids;
159         state->ctx = ctx;
160
161         subreq = dcerpc_winbind_get_idmap_r_send(state,
162                                                  wbc_ctx->event_ctx,
163                                                  wbc_ctx->irpc_handle,
164                                                  state->req);
165         if (composite_nomem(subreq, ctx)) return ctx;
166
167         tevent_req_set_callback(subreq, xids_to_sids_recv_ids, state);
168
169         return ctx;
170 }
171
172 static void xids_to_sids_recv_ids(struct tevent_req *subreq)
173 {
174         struct wbc_idmap_state *state =
175                 tevent_req_callback_data(subreq,
176                 struct wbc_idmap_state);
177
178         state->ctx->status = dcerpc_winbind_get_idmap_r_recv(subreq, state);
179         TALLOC_FREE(subreq);
180         if (!composite_is_ok(state->ctx)) return;
181
182         state->ids = state->req->out.ids;
183         composite_done(state->ctx);
184 }
185
186 NTSTATUS wbc_xids_to_sids_recv(struct composite_context *ctx,
187                                struct id_map **ids)
188 {
189         NTSTATUS status = composite_wait(ctx);
190                 DEBUG(5, ("wbc_xids_to_sids_recv called\n"));
191         if (NT_STATUS_IS_OK(status)) {
192                 struct wbc_idmap_state *state = talloc_get_type_abort(
193                                                         ctx->private_data,
194                                                         struct wbc_idmap_state);
195                 *ids = state->ids;
196         }
197
198         return status;
199 }
200
201 static int wb_simple_trans(struct tevent_context *ev, int fd,
202                            struct winbindd_request *wb_req,
203                            TALLOC_CTX *mem_ctx,
204                            struct winbindd_response **resp, int *err)
205 {
206         struct tevent_req *req;
207         bool polled;
208         int ret;
209
210         req = wb_simple_trans_send(ev, ev, NULL, fd, wb_req);
211         if (req == NULL) {
212                 *err = ENOMEM;
213                 return -1;
214         }
215
216         polled = tevent_req_poll(req, ev);
217         if (!polled) {
218                 *err = errno;
219                 DEBUG(10, ("tevent_req_poll returned %s\n",
220                            strerror(*err)));
221                 return -1;
222         }
223
224         ret = wb_simple_trans_recv(req, mem_ctx, resp, err);
225         TALLOC_FREE(req);
226         return ret;
227 }
228
229 static const char *winbindd_socket_dir(void)
230 {
231 #ifdef SOCKET_WRAPPER
232         const char *env_dir;
233
234         env_dir = getenv(WINBINDD_SOCKET_DIR_ENVVAR);
235         if (env_dir) {
236                 return env_dir;
237         }
238 #endif
239
240         return WINBINDD_SOCKET_DIR;
241 }
242
243 static int winbindd_pipe_sock(void)
244 {
245         struct sockaddr_un sunaddr = {};
246         int ret, fd;
247         char *path;
248
249         ret = asprintf(&path, "%s/%s", winbindd_socket_dir(),
250                        WINBINDD_SOCKET_NAME);
251         if (ret == -1) {
252                 errno = ENOMEM;
253                 return -1;
254         }
255         sunaddr.sun_family = AF_UNIX;
256         strlcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path));
257         free(path);
258
259         fd = socket(AF_UNIX, SOCK_STREAM, 0);
260         if (fd == -1) {
261                 return -1;
262         }
263
264         ret = connect(fd, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
265         if (ret == -1) {
266                 int err = errno;
267                 close(fd);
268                 errno = err;
269                 return -1;
270         }
271
272         return fd;
273 }
274
275 NTSTATUS wbc_sids_to_xids(struct tevent_context *ev, struct id_map *ids,
276                           uint32_t count)
277 {
278         TALLOC_CTX *mem_ctx;
279         struct winbindd_request req = {};
280         struct winbindd_response *resp;
281         uint32_t i;
282         int fd, ret, err;
283         char *sids, *p;
284         size_t sidslen;
285
286         fd = winbindd_pipe_sock();
287         if (fd == -1) {
288                 return map_nt_error_from_unix_common(errno);
289         }
290
291         mem_ctx = talloc_new(NULL);
292         if (mem_ctx == NULL) {
293                 close(fd);
294                 return NT_STATUS_NO_MEMORY;
295         }
296
297         sidslen = count * (DOM_SID_STR_BUFLEN + 1);
298
299         sids = talloc_array(mem_ctx, char, sidslen);
300         if (sids == NULL) {
301                 close(fd);
302                 TALLOC_FREE(mem_ctx);
303                 return NT_STATUS_NO_MEMORY;
304         }
305
306         p = sids;
307         for (i=0; i<count; i++) {
308                 p += dom_sid_string_buf(ids[i].sid, p, sidslen - (p - sids));
309                 *p++ = '\n';
310         }
311         *p++ = '\0';
312
313         DEBUG(10, ("sids=\n%s", sids));
314
315         req.length = sizeof(struct winbindd_request);
316         req.cmd = WINBINDD_SIDS_TO_XIDS;
317         req.pid = getpid();
318         req.extra_data.data = sids;
319         req.extra_len = sidslen;
320
321         ret = wb_simple_trans(ev, fd, &req, mem_ctx, &resp, &err);
322         if (ret == -1) {
323                 return map_nt_error_from_unix_common(err);
324         }
325
326         close(fd);
327
328         p = resp->extra_data.data;
329
330         for (i=0; i<count; i++) {
331                 struct unixid *id = &ids[i].xid;
332                 char *q;
333
334                 switch (p[0]) {
335                 case 'U':
336                         id->type = ID_TYPE_UID;
337                         id->id = strtoul(p+1, &q, 10);
338                         break;
339                 case 'G':
340                         id->type = ID_TYPE_GID;
341                         id->id = strtoul(p+1, &q, 10);
342                         break;
343                 case 'B':
344                         id->type = ID_TYPE_BOTH;
345                         id->id = strtoul(p+1, &q, 10);
346                         break;
347                 default:
348                         id->type = ID_TYPE_NOT_SPECIFIED;
349                         id->id = UINT32_MAX;
350                         q = strchr(p, '\n');
351                         break;
352                 };
353                 ids[i].status = ID_MAPPED;
354
355                 if (q == NULL || q[0] != '\n') {
356                         TALLOC_FREE(mem_ctx);
357                         return NT_STATUS_INTERNAL_ERROR;
358                 }
359                 p = q+1;
360         }
361
362         return NT_STATUS_OK;
363 }