2 Unix SMB/CIFS implementation.
4 Winbind client library.
6 Copyright (C) 2008 Kai Blin <kai@samba.org>
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.
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.
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/>.
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"
32 * Initialize the wbclient context, talloc_free() when done.
34 * \param mem_ctx talloc context to allocate memory from
35 * \param msg_ctx message context to use
38 struct wbc_context
*wbc_init(TALLOC_CTX
*mem_ctx
,
39 struct imessaging_context
*msg_ctx
,
40 struct tevent_context
*event_ctx
)
42 struct wbc_context
*ctx
;
44 ctx
= talloc(mem_ctx
, struct wbc_context
);
45 if (ctx
== NULL
) return NULL
;
47 ctx
->event_ctx
= event_ctx
;
49 ctx
->irpc_handle
= irpc_binding_handle_by_name(ctx
, msg_ctx
,
52 if (ctx
->irpc_handle
== NULL
) {
60 struct wbc_idmap_state
{
61 struct composite_context
*ctx
;
62 struct winbind_get_idmap
*req
;
66 static void sids_to_xids_recv_ids(struct tevent_req
*subreq
);
68 struct composite_context
*wbc_sids_to_xids_send(struct wbc_context
*wbc_ctx
,
73 struct composite_context
*ctx
;
74 struct wbc_idmap_state
*state
;
75 struct tevent_req
*subreq
;
77 DEBUG(5, ("wbc_sids_to_xids called\n"));
79 ctx
= composite_create(mem_ctx
, wbc_ctx
->event_ctx
);
80 if (ctx
== NULL
) return NULL
;
82 state
= talloc(ctx
, struct wbc_idmap_state
);
83 if (composite_nomem(state
, ctx
)) return ctx
;
84 ctx
->private_data
= state
;
86 state
->req
= talloc(state
, struct winbind_get_idmap
);
87 if (composite_nomem(state
->req
, ctx
)) return ctx
;
89 state
->req
->in
.count
= count
;
90 state
->req
->in
.level
= WINBIND_IDMAP_LEVEL_SIDS_TO_XIDS
;
91 state
->req
->in
.ids
= ids
;
94 subreq
= dcerpc_winbind_get_idmap_r_send(state
,
98 if (composite_nomem(subreq
, ctx
)) return ctx
;
100 tevent_req_set_callback(subreq
, sids_to_xids_recv_ids
, state
);
105 static void sids_to_xids_recv_ids(struct tevent_req
*subreq
)
107 struct wbc_idmap_state
*state
=
108 tevent_req_callback_data(subreq
,
109 struct wbc_idmap_state
);
111 state
->ctx
->status
= dcerpc_winbind_get_idmap_r_recv(subreq
, state
);
113 if (!composite_is_ok(state
->ctx
)) return;
115 state
->ids
= state
->req
->out
.ids
;
116 composite_done(state
->ctx
);
119 NTSTATUS
wbc_sids_to_xids_recv(struct composite_context
*ctx
,
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(
127 struct wbc_idmap_state
);
134 static void xids_to_sids_recv_ids(struct tevent_req
*subreq
);
136 struct composite_context
*wbc_xids_to_sids_send(struct wbc_context
*wbc_ctx
,
141 struct composite_context
*ctx
;
142 struct wbc_idmap_state
*state
;
143 struct tevent_req
*subreq
;
145 DEBUG(5, ("wbc_xids_to_sids called\n"));
147 ctx
= composite_create(mem_ctx
, wbc_ctx
->event_ctx
);
148 if (ctx
== NULL
) return NULL
;
150 state
= talloc(ctx
, struct wbc_idmap_state
);
151 if (composite_nomem(state
, ctx
)) return ctx
;
152 ctx
->private_data
= state
;
154 state
->req
= talloc(state
, struct winbind_get_idmap
);
155 if (composite_nomem(state
->req
, ctx
)) return ctx
;
157 state
->req
->in
.count
= count
;
158 state
->req
->in
.level
= WINBIND_IDMAP_LEVEL_XIDS_TO_SIDS
;
159 state
->req
->in
.ids
= ids
;
162 subreq
= dcerpc_winbind_get_idmap_r_send(state
,
164 wbc_ctx
->irpc_handle
,
166 if (composite_nomem(subreq
, ctx
)) return ctx
;
168 tevent_req_set_callback(subreq
, xids_to_sids_recv_ids
, state
);
173 static void xids_to_sids_recv_ids(struct tevent_req
*subreq
)
175 struct wbc_idmap_state
*state
=
176 tevent_req_callback_data(subreq
,
177 struct wbc_idmap_state
);
179 state
->ctx
->status
= dcerpc_winbind_get_idmap_r_recv(subreq
, state
);
181 if (!composite_is_ok(state
->ctx
)) return;
183 state
->ids
= state
->req
->out
.ids
;
184 composite_done(state
->ctx
);
187 NTSTATUS
wbc_xids_to_sids_recv(struct composite_context
*ctx
,
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(
195 struct wbc_idmap_state
);
202 static int wb_simple_trans(struct tevent_context
*ev
, int fd
,
203 struct winbindd_request
*wb_req
,
205 struct winbindd_response
**resp
, int *err
)
207 struct tevent_req
*req
;
211 req
= wb_simple_trans_send(ev
, ev
, NULL
, fd
, wb_req
);
217 polled
= tevent_req_poll(req
, ev
);
220 DEBUG(10, ("tevent_req_poll returned %s\n",
225 ret
= wb_simple_trans_recv(req
, mem_ctx
, resp
, err
);
230 static const char *winbindd_socket_dir(void)
232 #ifdef SOCKET_WRAPPER
235 env_dir
= getenv(WINBINDD_SOCKET_DIR_ENVVAR
);
241 return WINBINDD_SOCKET_DIR
;
244 static int winbindd_pipe_sock(void)
246 struct sockaddr_un sunaddr
= {};
250 ret
= asprintf(&path
, "%s/%s", winbindd_socket_dir(),
251 WINBINDD_SOCKET_NAME
);
256 sunaddr
.sun_family
= AF_UNIX
;
257 strlcpy(sunaddr
.sun_path
, path
, sizeof(sunaddr
.sun_path
));
260 fd
= socket(AF_UNIX
, SOCK_STREAM
, 0);
265 ret
= connect(fd
, (struct sockaddr
*)&sunaddr
, sizeof(sunaddr
));
276 NTSTATUS
wbc_sids_to_xids(struct tevent_context
*ev
, struct id_map
*ids
,
280 struct winbindd_request req
= {};
281 struct winbindd_response
*resp
;
287 fd
= winbindd_pipe_sock();
289 return map_nt_error_from_unix_common(errno
);
292 mem_ctx
= talloc_new(NULL
);
293 if (mem_ctx
== NULL
) {
295 return NT_STATUS_NO_MEMORY
;
298 sidslen
= count
* (DOM_SID_STR_BUFLEN
+ 1);
300 sids
= talloc_array(mem_ctx
, char, sidslen
);
303 TALLOC_FREE(mem_ctx
);
304 return NT_STATUS_NO_MEMORY
;
308 for (i
=0; i
<count
; i
++) {
309 p
+= dom_sid_string_buf(ids
[i
].sid
, p
, sidslen
- (p
- sids
));
314 DEBUG(10, ("sids=\n%s", sids
));
316 req
.length
= sizeof(struct winbindd_request
);
317 req
.cmd
= WINBINDD_SIDS_TO_XIDS
;
319 req
.extra_data
.data
= sids
;
320 req
.extra_len
= sidslen
;
322 ret
= wb_simple_trans(ev
, fd
, &req
, mem_ctx
, &resp
, &err
);
324 return map_nt_error_from_unix_common(err
);
329 p
= resp
->extra_data
.data
;
331 for (i
=0; i
<count
; i
++) {
332 struct unixid
*id
= &ids
[i
].xid
;
337 id
->type
= ID_TYPE_UID
;
338 id
->id
= strtoul(p
+1, &q
, 10);
341 id
->type
= ID_TYPE_GID
;
342 id
->id
= strtoul(p
+1, &q
, 10);
345 id
->type
= ID_TYPE_BOTH
;
346 id
->id
= strtoul(p
+1, &q
, 10);
349 id
->type
= ID_TYPE_NOT_SPECIFIED
;
354 ids
[i
].status
= ID_MAPPED
;
356 if (q
== NULL
|| q
[0] != '\n') {
357 TALLOC_FREE(mem_ctx
);
358 return NT_STATUS_INTERNAL_ERROR
;
366 struct wbc_id_to_sid_state
{
367 struct winbindd_request wbreq
;
371 static void wbc_id_to_sid_done(struct tevent_req
*subreq
);
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
)
377 struct tevent_req
*req
, *subreq
;
378 struct wbc_id_to_sid_state
*state
;
380 req
= tevent_req_create(mem_ctx
, &state
, struct wbc_id_to_sid_state
);
387 state
->wbreq
.cmd
= WINBINDD_UID_TO_SID
;
388 state
->wbreq
.data
.uid
= id
->id
;
391 state
->wbreq
.cmd
= WINBINDD_GID_TO_SID
;
392 state
->wbreq
.data
.gid
= id
->id
;
395 tevent_req_error(req
, ENOENT
);
396 return tevent_req_post(req
, ev
);
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
);
403 tevent_req_set_callback(subreq
, wbc_id_to_sid_done
, req
);
407 static void wbc_id_to_sid_done(struct tevent_req
*subreq
)
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
;
416 ret
= wb_simple_trans_recv(subreq
, state
, &wbresp
, &err
);
419 tevent_req_error(req
, err
);
422 if ((wbresp
->result
!= WINBINDD_OK
) ||
423 !dom_sid_parse(wbresp
->data
.sid
.sid
, &state
->sid
)) {
424 tevent_req_error(req
, ENOENT
);
427 tevent_req_done(req
);
430 static int wbc_id_to_sid_recv(struct tevent_req
*req
, struct dom_sid
*sid
)
432 struct wbc_id_to_sid_state
*state
= tevent_req_data(
433 req
, struct wbc_id_to_sid_state
);
436 if (tevent_req_is_unix_error(req
, &err
)) {
439 sid_copy(sid
, &state
->sid
);
443 struct wbc_ids_to_sids_state
{
444 struct tevent_context
*ev
;
451 static void wbc_ids_to_sids_done(struct tevent_req
*subreq
);
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
)
457 struct tevent_req
*req
, *subreq
;
458 struct wbc_ids_to_sids_state
*state
;
460 req
= tevent_req_create(mem_ctx
, &state
,
461 struct wbc_ids_to_sids_state
);
468 state
->count
= count
;
471 tevent_req_done(req
);
472 return tevent_req_post(req
, ev
);
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
);
480 tevent_req_set_callback(subreq
, wbc_ids_to_sids_done
, req
);
484 static void wbc_ids_to_sids_done(struct tevent_req
*subreq
)
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
);
494 ret
= wbc_id_to_sid_recv(subreq
, &sid
);
497 id
= &state
->ids
[state
->idx
];
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
);
506 id
->status
= ID_UNMAPPED
;
511 if (state
->idx
== state
->count
) {
512 tevent_req_done(req
);
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
)) {
521 tevent_req_set_callback(subreq
, wbc_ids_to_sids_done
, req
);
524 static int wbc_ids_to_sids_recv(struct tevent_req
*req
)
527 if (tevent_req_is_unix_error(req
, &err
)) {
533 NTSTATUS
wbc_xids_to_sids(struct tevent_context
*ev
, struct id_map
*ids
,
536 struct tevent_req
*req
;
541 DEBUG(5, ("wbc_xids_to_sids called: %u ids\n", (unsigned)count
));
543 fd
= winbindd_pipe_sock();
545 status
= map_nt_error_from_unix_common(errno
);
546 DEBUG(10, ("winbindd_pipe_sock returned %s\n",
551 req
= wbc_ids_to_sids_send(ev
, ev
, fd
, ids
, count
);
553 status
= NT_STATUS_NO_MEMORY
;
557 polled
= tevent_req_poll(req
, ev
);
559 status
= map_nt_error_from_unix_common(errno
);
560 DEBUG(10, ("tevent_req_poll returned %s\n",
565 ret
= wbc_ids_to_sids_recv(req
);
568 status
= map_nt_error_from_unix_common(ret
);
569 DEBUG(10, ("tevent_req_poll returned %s\n",
572 status
= NT_STATUS_OK
;