nss_wrapper: Fix some "discarding const" warnings
[Samba.git] / source4 / libcli / wbclient / wbclient.c
blobbb894356843115478f1865a5f15928899c096c76
1 /*
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/>.
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"
31 static int wb_simple_trans(struct tevent_context *ev, int fd,
32 struct winbindd_request *wb_req,
33 TALLOC_CTX *mem_ctx,
34 struct winbindd_response **resp, int *err)
36 struct tevent_req *req;
37 bool polled;
38 int ret;
40 req = wb_simple_trans_send(ev, ev, NULL, fd, wb_req);
41 if (req == NULL) {
42 *err = ENOMEM;
43 return -1;
46 polled = tevent_req_poll(req, ev);
47 if (!polled) {
48 *err = errno;
49 DEBUG(10, ("tevent_req_poll returned %s\n",
50 strerror(*err)));
51 return -1;
54 ret = wb_simple_trans_recv(req, mem_ctx, resp, err);
55 TALLOC_FREE(req);
56 return ret;
59 static const char *winbindd_socket_dir(void)
61 #ifdef SOCKET_WRAPPER
62 const char *env_dir;
64 env_dir = getenv("SELFTEST_WINBINDD_SOCKET_DIR");
65 if (env_dir) {
66 return env_dir;
68 #endif
70 return WINBINDD_SOCKET_DIR;
73 static int winbindd_pipe_sock(void)
75 struct sockaddr_un sunaddr = {};
76 int ret, fd;
77 char *path;
79 ret = asprintf(&path, "%s/%s", winbindd_socket_dir(),
80 WINBINDD_SOCKET_NAME);
81 if (ret == -1) {
82 errno = ENOMEM;
83 return -1;
85 sunaddr.sun_family = AF_UNIX;
86 strlcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path));
87 free(path);
89 fd = socket(AF_UNIX, SOCK_STREAM, 0);
90 if (fd == -1) {
91 return -1;
94 ret = connect(fd, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
95 if (ret == -1) {
96 int err = errno;
97 close(fd);
98 errno = err;
99 return -1;
102 return fd;
105 NTSTATUS wbc_sids_to_xids(struct tevent_context *ev, struct id_map *ids,
106 uint32_t count)
108 TALLOC_CTX *mem_ctx;
109 struct winbindd_request req = {};
110 struct winbindd_response *resp;
111 uint32_t i;
112 int fd, ret, err;
113 char *sids, *p;
114 size_t sidslen;
116 fd = winbindd_pipe_sock();
117 if (fd == -1) {
118 return map_nt_error_from_unix_common(errno);
121 mem_ctx = talloc_new(NULL);
122 if (mem_ctx == NULL) {
123 close(fd);
124 return NT_STATUS_NO_MEMORY;
127 sidslen = count * (DOM_SID_STR_BUFLEN + 1);
129 sids = talloc_array(mem_ctx, char, sidslen);
130 if (sids == NULL) {
131 close(fd);
132 TALLOC_FREE(mem_ctx);
133 return NT_STATUS_NO_MEMORY;
136 p = sids;
137 for (i=0; i<count; i++) {
138 p += dom_sid_string_buf(ids[i].sid, p, sidslen - (p - sids));
139 *p++ = '\n';
141 *p++ = '\0';
143 DEBUG(10, ("sids=\n%s", sids));
145 req.length = sizeof(struct winbindd_request);
146 req.cmd = WINBINDD_SIDS_TO_XIDS;
147 req.pid = getpid();
148 req.extra_data.data = sids;
149 req.extra_len = (p - sids);
151 ret = wb_simple_trans(ev, fd, &req, mem_ctx, &resp, &err);
152 if (ret == -1) {
153 return map_nt_error_from_unix_common(err);
156 close(fd);
158 if (resp->result != WINBINDD_OK || p == NULL) {
159 return NT_STATUS_INTERNAL_ERROR;
162 p = resp->extra_data.data;
164 for (i=0; i<count; i++) {
165 struct unixid *id = &ids[i].xid;
166 char *q;
168 switch (p[0]) {
169 case 'U':
170 id->type = ID_TYPE_UID;
171 id->id = strtoul(p+1, &q, 10);
172 break;
173 case 'G':
174 id->type = ID_TYPE_GID;
175 id->id = strtoul(p+1, &q, 10);
176 break;
177 case 'B':
178 id->type = ID_TYPE_BOTH;
179 id->id = strtoul(p+1, &q, 10);
180 break;
181 default:
182 id->type = ID_TYPE_NOT_SPECIFIED;
183 id->id = UINT32_MAX;
184 q = strchr(p, '\n');
185 break;
187 ids[i].status = ID_MAPPED;
189 if (q == NULL || q[0] != '\n') {
190 TALLOC_FREE(mem_ctx);
191 return NT_STATUS_INTERNAL_ERROR;
193 p = q+1;
196 return NT_STATUS_OK;
199 struct wbc_id_to_sid_state {
200 struct winbindd_request wbreq;
201 struct dom_sid sid;
204 static void wbc_id_to_sid_done(struct tevent_req *subreq);
206 static struct tevent_req *wbc_id_to_sid_send(TALLOC_CTX *mem_ctx,
207 struct tevent_context *ev,
208 int fd, const struct unixid *id)
210 struct tevent_req *req, *subreq;
211 struct wbc_id_to_sid_state *state;
213 req = tevent_req_create(mem_ctx, &state, struct wbc_id_to_sid_state);
214 if (req == NULL) {
215 return NULL;
218 switch(id->type) {
219 case ID_TYPE_UID:
220 state->wbreq.cmd = WINBINDD_UID_TO_SID;
221 state->wbreq.data.uid = id->id;
222 break;
223 case ID_TYPE_GID:
224 state->wbreq.cmd = WINBINDD_GID_TO_SID;
225 state->wbreq.data.gid = id->id;
226 break;
227 default:
228 tevent_req_error(req, ENOENT);
229 return tevent_req_post(req, ev);
232 subreq = wb_simple_trans_send(state, ev, NULL, fd, &state->wbreq);
233 if (tevent_req_nomem(subreq, req)) {
234 return tevent_req_post(req, ev);
236 tevent_req_set_callback(subreq, wbc_id_to_sid_done, req);
237 return req;
240 static void wbc_id_to_sid_done(struct tevent_req *subreq)
242 struct tevent_req *req = tevent_req_callback_data(
243 subreq, struct tevent_req);
244 struct wbc_id_to_sid_state *state = tevent_req_data(
245 req, struct wbc_id_to_sid_state);
246 struct winbindd_response *wbresp;
247 int ret, err;
249 ret = wb_simple_trans_recv(subreq, state, &wbresp, &err);
250 TALLOC_FREE(subreq);
251 if (ret == -1) {
252 tevent_req_error(req, err);
253 return;
255 if ((wbresp->result != WINBINDD_OK) ||
256 !dom_sid_parse(wbresp->data.sid.sid, &state->sid)) {
257 tevent_req_error(req, ENOENT);
258 return;
260 tevent_req_done(req);
263 static int wbc_id_to_sid_recv(struct tevent_req *req, struct dom_sid *sid)
265 struct wbc_id_to_sid_state *state = tevent_req_data(
266 req, struct wbc_id_to_sid_state);
267 int err;
269 if (tevent_req_is_unix_error(req, &err)) {
270 return err;
272 sid_copy(sid, &state->sid);
273 return 0;
276 struct wbc_ids_to_sids_state {
277 struct tevent_context *ev;
278 int fd;
279 struct id_map *ids;
280 uint32_t count;
281 uint32_t idx;
284 static void wbc_ids_to_sids_done(struct tevent_req *subreq);
286 static struct tevent_req *wbc_ids_to_sids_send(
287 TALLOC_CTX *mem_ctx, struct tevent_context *ev,
288 int fd, struct id_map *ids, uint32_t count)
290 struct tevent_req *req, *subreq;
291 struct wbc_ids_to_sids_state *state;
293 req = tevent_req_create(mem_ctx, &state,
294 struct wbc_ids_to_sids_state);
295 if (req == NULL) {
296 return NULL;
298 state->ev = ev;
299 state->fd = fd;
300 state->ids = ids;
301 state->count = count;
303 if (count == 0) {
304 tevent_req_done(req);
305 return tevent_req_post(req, ev);
308 subreq = wbc_id_to_sid_send(state, state->ev, state->fd,
309 &state->ids[state->idx].xid);
310 if (tevent_req_nomem(subreq, req)) {
311 return tevent_req_post(req, ev);
313 tevent_req_set_callback(subreq, wbc_ids_to_sids_done, req);
314 return req;
317 static void wbc_ids_to_sids_done(struct tevent_req *subreq)
319 struct tevent_req *req = tevent_req_callback_data(
320 subreq, struct tevent_req);
321 struct wbc_ids_to_sids_state *state = tevent_req_data(
322 req, struct wbc_ids_to_sids_state);
323 struct id_map *id;
324 struct dom_sid sid;
325 int ret;
327 ret = wbc_id_to_sid_recv(subreq, &sid);
328 TALLOC_FREE(subreq);
330 id = &state->ids[state->idx];
331 if (ret == 0) {
332 id->status = ID_MAPPED;
333 id->sid = dom_sid_dup(state->ids, &sid);
334 if (id->sid == NULL) {
335 tevent_req_error(req, ENOMEM);
336 return;
338 } else {
339 id->status = ID_UNMAPPED;
340 id->sid = NULL;
343 state->idx += 1;
344 if (state->idx == state->count) {
345 tevent_req_done(req);
346 return;
349 subreq = wbc_id_to_sid_send(state, state->ev, state->fd,
350 &state->ids[state->idx].xid);
351 if (tevent_req_nomem(subreq, req)) {
352 return;
354 tevent_req_set_callback(subreq, wbc_ids_to_sids_done, req);
357 static int wbc_ids_to_sids_recv(struct tevent_req *req)
359 int err;
360 if (tevent_req_is_unix_error(req, &err)) {
361 return err;
363 return 0;
366 NTSTATUS wbc_xids_to_sids(struct tevent_context *ev, struct id_map *ids,
367 uint32_t count)
369 struct tevent_req *req;
370 NTSTATUS status;
371 bool polled;
372 int ret, fd;
374 DEBUG(5, ("wbc_xids_to_sids called: %u ids\n", (unsigned)count));
376 fd = winbindd_pipe_sock();
377 if (fd == -1) {
378 status = map_nt_error_from_unix_common(errno);
379 DEBUG(10, ("winbindd_pipe_sock returned %s\n",
380 strerror(errno)));
381 return status;
384 req = wbc_ids_to_sids_send(ev, ev, fd, ids, count);
385 if (req == NULL) {
386 status = NT_STATUS_NO_MEMORY;
387 goto done;
390 polled = tevent_req_poll(req, ev);
391 if (!polled) {
392 status = map_nt_error_from_unix_common(errno);
393 DEBUG(10, ("tevent_req_poll returned %s\n",
394 strerror(errno)));
395 goto done;
398 ret = wbc_ids_to_sids_recv(req);
399 TALLOC_FREE(req);
400 if (ret != 0) {
401 status = map_nt_error_from_unix_common(ret);
402 DEBUG(10, ("tevent_req_poll returned %s\n",
403 strerror(ret)));
404 } else {
405 status = NT_STATUS_OK;
408 done:
409 close(fd);
410 return status;