119b1216fb28095bfc74d3ec1ddb8bf22bf0b393
[metze/samba/wip.git] / source3 / libsmb / clifsinfo.c
1 /* 
2    Unix SMB/CIFS implementation.
3    FS info functions
4    Copyright (C) Stefan (metze) Metzmacher      2003
5    Copyright (C) Jeremy Allison 2007
6    Copyright (C) Andrew Bartlett 2011
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 "libsmb/libsmb.h"
24 #include "../lib/util/tevent_ntstatus.h"
25 #include "async_smb.h"
26 #include "trans2.h"
27 #include "auth_generic.h"
28 #include "auth/gensec/gensec.h"
29 #include "../libcli/smb/smbXcli_base.h"
30 #include "auth/credentials/credentials.h"
31 #include "../librpc/gen_ndr/ndr_security.h"
32
33 /****************************************************************************
34  Get UNIX extensions version info.
35 ****************************************************************************/
36
37 struct cli_unix_extensions_version_state {
38         struct cli_state *cli;
39         uint16_t setup[1];
40         uint8_t param[2];
41         uint16_t major, minor;
42         uint32_t caplow, caphigh;
43 };
44
45 static void cli_unix_extensions_version_done(struct tevent_req *subreq);
46
47 struct tevent_req *cli_unix_extensions_version_send(TALLOC_CTX *mem_ctx,
48                                                     struct tevent_context *ev,
49                                                     struct cli_state *cli)
50 {
51         struct tevent_req *req, *subreq;
52         struct cli_unix_extensions_version_state *state;
53
54         req = tevent_req_create(mem_ctx, &state,
55                                 struct cli_unix_extensions_version_state);
56         if (req == NULL) {
57                 return NULL;
58         }
59         state->cli = cli;
60         SSVAL(state->setup, 0, TRANSACT2_QFSINFO);
61         SSVAL(state->param, 0, SMB_QUERY_CIFS_UNIX_INFO);
62
63         subreq = cli_trans_send(state, ev, cli, 0, SMBtrans2,
64                                 NULL, 0, 0, 0,
65                                 state->setup, 1, 0,
66                                 state->param, 2, 0,
67                                 NULL, 0, 560);
68         if (tevent_req_nomem(subreq, req)) {
69                 return tevent_req_post(req, ev);
70         }
71         tevent_req_set_callback(subreq, cli_unix_extensions_version_done, req);
72         return req;
73 }
74
75 static void cli_unix_extensions_version_done(struct tevent_req *subreq)
76 {
77         struct tevent_req *req = tevent_req_callback_data(
78                 subreq, struct tevent_req);
79         struct cli_unix_extensions_version_state *state = tevent_req_data(
80                 req, struct cli_unix_extensions_version_state);
81         uint8_t *data;
82         uint32_t num_data;
83         NTSTATUS status;
84
85         status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
86                                 NULL, 0, NULL, &data, 12, &num_data);
87         TALLOC_FREE(subreq);
88         if (!NT_STATUS_IS_OK(status)) {
89                 tevent_req_nterror(req, status);
90                 return;
91         }
92
93         state->major = SVAL(data, 0);
94         state->minor = SVAL(data, 2);
95         state->caplow = IVAL(data, 4);
96         state->caphigh = IVAL(data, 8);
97         TALLOC_FREE(data);
98         tevent_req_done(req);
99 }
100
101 NTSTATUS cli_unix_extensions_version_recv(struct tevent_req *req,
102                                           uint16_t *pmajor, uint16_t *pminor,
103                                           uint32_t *pcaplow,
104                                           uint32_t *pcaphigh)
105 {
106         struct cli_unix_extensions_version_state *state = tevent_req_data(
107                 req, struct cli_unix_extensions_version_state);
108         NTSTATUS status;
109
110         if (tevent_req_is_nterror(req, &status)) {
111                 return status;
112         }
113         *pmajor = state->major;
114         *pminor = state->minor;
115         *pcaplow = state->caplow;
116         *pcaphigh = state->caphigh;
117         state->cli->server_posix_capabilities = *pcaplow;
118         return NT_STATUS_OK;
119 }
120
121 NTSTATUS cli_unix_extensions_version(struct cli_state *cli, uint16_t *pmajor,
122                                      uint16_t *pminor, uint32_t *pcaplow,
123                                      uint32_t *pcaphigh)
124 {
125         TALLOC_CTX *frame = talloc_stackframe();
126         struct tevent_context *ev;
127         struct tevent_req *req;
128         NTSTATUS status = NT_STATUS_OK;
129
130         if (smbXcli_conn_has_async_calls(cli->conn)) {
131                 /*
132                  * Can't use sync call while an async call is in flight
133                  */
134                 status = NT_STATUS_INVALID_PARAMETER;
135                 goto fail;
136         }
137
138         ev = samba_tevent_context_init(frame);
139         if (ev == NULL) {
140                 status = NT_STATUS_NO_MEMORY;
141                 goto fail;
142         }
143
144         req = cli_unix_extensions_version_send(frame, ev, cli);
145         if (req == NULL) {
146                 status = NT_STATUS_NO_MEMORY;
147                 goto fail;
148         }
149
150         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
151                 goto fail;
152         }
153
154         status = cli_unix_extensions_version_recv(req, pmajor, pminor, pcaplow,
155                                                   pcaphigh);
156  fail:
157         TALLOC_FREE(frame);
158         return status;
159 }
160
161 /****************************************************************************
162  Set UNIX extensions capabilities.
163 ****************************************************************************/
164
165 struct cli_set_unix_extensions_capabilities_state {
166         struct cli_state *cli;
167         uint16_t setup[1];
168         uint8_t param[4];
169         uint8_t data[12];
170 };
171
172 static void cli_set_unix_extensions_capabilities_done(
173         struct tevent_req *subreq);
174
175 struct tevent_req *cli_set_unix_extensions_capabilities_send(
176         TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
177         uint16_t major, uint16_t minor, uint32_t caplow, uint32_t caphigh)
178 {
179         struct tevent_req *req, *subreq;
180         struct cli_set_unix_extensions_capabilities_state *state;
181
182         req = tevent_req_create(
183                 mem_ctx, &state,
184                 struct cli_set_unix_extensions_capabilities_state);
185         if (req == NULL) {
186                 return NULL;
187         }
188
189         state->cli = cli;
190         SSVAL(state->setup+0, 0, TRANSACT2_SETFSINFO);
191
192         SSVAL(state->param, 0, 0);
193         SSVAL(state->param, 2, SMB_SET_CIFS_UNIX_INFO);
194
195         SSVAL(state->data, 0, major);
196         SSVAL(state->data, 2, minor);
197         SIVAL(state->data, 4, caplow);
198         SIVAL(state->data, 8, caphigh);
199
200         subreq = cli_trans_send(state, ev, cli, 0, SMBtrans2,
201                                 NULL, 0, 0, 0,
202                                 state->setup, 1, 0,
203                                 state->param, 4, 0,
204                                 state->data, 12, 560);
205         if (tevent_req_nomem(subreq, req)) {
206                 return tevent_req_post(req, ev);
207         }
208         tevent_req_set_callback(
209                 subreq, cli_set_unix_extensions_capabilities_done, req);
210         return req;
211 }
212
213 static void cli_set_unix_extensions_capabilities_done(
214         struct tevent_req *subreq)
215 {
216         struct tevent_req *req = tevent_req_callback_data(
217                 subreq, struct tevent_req);
218         struct cli_set_unix_extensions_capabilities_state *state = tevent_req_data(
219                 req, struct cli_set_unix_extensions_capabilities_state);
220
221         NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
222                                          NULL, 0, NULL, NULL, 0, NULL);
223         if (NT_STATUS_IS_OK(status)) {
224                 state->cli->requested_posix_capabilities = IVAL(state->data, 4);
225         }
226         tevent_req_simple_finish_ntstatus(subreq, status);
227 }
228
229 NTSTATUS cli_set_unix_extensions_capabilities_recv(struct tevent_req *req)
230 {
231         return tevent_req_simple_recv_ntstatus(req);
232 }
233
234 NTSTATUS cli_set_unix_extensions_capabilities(struct cli_state *cli,
235                                               uint16_t major, uint16_t minor,
236                                               uint32_t caplow, uint32_t caphigh)
237 {
238         struct tevent_context *ev;
239         struct tevent_req *req;
240         NTSTATUS status = NT_STATUS_NO_MEMORY;
241
242         if (smbXcli_conn_has_async_calls(cli->conn)) {
243                 return NT_STATUS_INVALID_PARAMETER;
244         }
245         ev = samba_tevent_context_init(talloc_tos());
246         if (ev == NULL) {
247                 goto fail;
248         }
249         req = cli_set_unix_extensions_capabilities_send(
250                 ev, ev, cli, major, minor, caplow, caphigh);
251         if (req == NULL) {
252                 goto fail;
253         }
254         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
255                 goto fail;
256         }
257         status = cli_set_unix_extensions_capabilities_recv(req);
258 fail:
259         TALLOC_FREE(ev);
260         return status;
261 }
262
263 struct cli_get_fs_attr_info_state {
264         uint16_t setup[1];
265         uint8_t param[2];
266         uint32_t fs_attr;
267 };
268
269 static void cli_get_fs_attr_info_done(struct tevent_req *subreq);
270
271 struct tevent_req *cli_get_fs_attr_info_send(TALLOC_CTX *mem_ctx,
272                                              struct tevent_context *ev,
273                                              struct cli_state *cli)
274 {
275         struct tevent_req *subreq, *req;
276         struct cli_get_fs_attr_info_state *state;
277
278         req = tevent_req_create(mem_ctx, &state,
279                                 struct cli_get_fs_attr_info_state);
280         if (req == NULL) {
281                 return NULL;
282         }
283         SSVAL(state->setup+0, 0, TRANSACT2_QFSINFO);
284         SSVAL(state->param+0, 0, SMB_QUERY_FS_ATTRIBUTE_INFO);
285
286         subreq = cli_trans_send(state, ev, cli, 0, SMBtrans2,
287                                 NULL, 0, 0, 0,
288                                 state->setup, 1, 0,
289                                 state->param, 2, 0,
290                                 NULL, 0, 560);
291         if (tevent_req_nomem(subreq, req)) {
292                 return tevent_req_post(req, ev);
293         }
294         tevent_req_set_callback(subreq, cli_get_fs_attr_info_done, req);
295         return req;
296 }
297
298 static void cli_get_fs_attr_info_done(struct tevent_req *subreq)
299 {
300         struct tevent_req *req = tevent_req_callback_data(
301                 subreq, struct tevent_req);
302         struct cli_get_fs_attr_info_state *state = tevent_req_data(
303                 req, struct cli_get_fs_attr_info_state);
304         uint8_t *data;
305         uint32_t num_data;
306         NTSTATUS status;
307
308         status = cli_trans_recv(subreq, talloc_tos(), NULL, NULL, 0, NULL,
309                                 NULL, 0, NULL, &data, 12, &num_data);
310         TALLOC_FREE(subreq);
311         if (!NT_STATUS_IS_OK(status)) {
312                 tevent_req_nterror(req, status);
313                 return;
314         }
315         state->fs_attr = IVAL(data, 0);
316         TALLOC_FREE(data);
317         tevent_req_done(req);
318 }
319
320 NTSTATUS cli_get_fs_attr_info_recv(struct tevent_req *req, uint32_t *fs_attr)
321 {
322         struct cli_get_fs_attr_info_state *state = tevent_req_data(
323                 req, struct cli_get_fs_attr_info_state);
324         NTSTATUS status;
325
326         if (tevent_req_is_nterror(req, &status)) {
327                 return status;
328         }
329         *fs_attr = state->fs_attr;
330         return NT_STATUS_OK;
331 }
332
333 NTSTATUS cli_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
334 {
335         struct tevent_context *ev;
336         struct tevent_req *req;
337         NTSTATUS status = NT_STATUS_NO_MEMORY;
338
339         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
340                 return cli_smb2_get_fs_attr_info(cli, fs_attr);
341         }
342
343         if (smbXcli_conn_has_async_calls(cli->conn)) {
344                 return NT_STATUS_INVALID_PARAMETER;
345         }
346         ev = samba_tevent_context_init(talloc_tos());
347         if (ev == NULL) {
348                 goto fail;
349         }
350         req = cli_get_fs_attr_info_send(ev, ev, cli);
351         if (req == NULL) {
352                 goto fail;
353         }
354         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
355                 goto fail;
356         }
357         status = cli_get_fs_attr_info_recv(req, fs_attr);
358 fail:
359         TALLOC_FREE(ev);
360         return status;
361 }
362
363 NTSTATUS cli_get_fs_volume_info(struct cli_state *cli,
364                                 TALLOC_CTX *mem_ctx,
365                                 char **_volume_name,
366                                 uint32_t *pserial_number,
367                                 time_t *pdate)
368 {
369         NTSTATUS status;
370         uint16_t recv_flags2;
371         uint16_t setup[1];
372         uint8_t param[2];
373         uint8_t *rdata;
374         uint32_t rdata_count;
375         unsigned int nlen;
376         char *volume_name = NULL;
377
378         SSVAL(setup, 0, TRANSACT2_QFSINFO);
379         SSVAL(param,0,SMB_QUERY_FS_VOLUME_INFO);
380
381         status = cli_trans(talloc_tos(), cli, SMBtrans2,
382                            NULL, 0, 0, 0,
383                            setup, 1, 0,
384                            param, 2, 0,
385                            NULL, 0, 560,
386                            &recv_flags2,
387                            NULL, 0, NULL,
388                            NULL, 0, NULL,
389                            &rdata, 18, &rdata_count);
390         if (!NT_STATUS_IS_OK(status)) {
391                 return status;
392         }
393
394         if (pdate) {
395                 struct timespec ts;
396                 ts = interpret_long_date((char *)rdata);
397                 *pdate = ts.tv_sec;
398         }
399         if (pserial_number) {
400                 *pserial_number = IVAL(rdata,8);
401         }
402         nlen = IVAL(rdata,12);
403         if (nlen > (rdata_count - 18)) {
404                 TALLOC_FREE(rdata);
405                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
406         }
407
408         clistr_pull_talloc(mem_ctx,
409                            (const char *)rdata,
410                            recv_flags2,
411                            &volume_name,
412                            rdata + 18,
413                            nlen, STR_UNICODE);
414         if (volume_name == NULL) {
415                 status = map_nt_error_from_unix(errno);
416                 TALLOC_FREE(rdata);
417                 return status;
418         }
419
420         /* todo: but not yet needed
421          *       return the other stuff
422          */
423
424         *_volume_name = volume_name;
425         TALLOC_FREE(rdata);
426         return NT_STATUS_OK;
427 }
428
429 NTSTATUS cli_get_fs_full_size_info(struct cli_state *cli,
430                                    uint64_t *total_allocation_units,
431                                    uint64_t *caller_allocation_units,
432                                    uint64_t *actual_allocation_units,
433                                    uint64_t *sectors_per_allocation_unit,
434                                    uint64_t *bytes_per_sector)
435 {
436         uint16_t setup[1];
437         uint8_t param[2];
438         uint8_t *rdata = NULL;
439         uint32_t rdata_count;
440         NTSTATUS status;
441
442         SSVAL(setup, 0, TRANSACT2_QFSINFO);
443         SSVAL(param, 0, SMB_FS_FULL_SIZE_INFORMATION);
444
445         status = cli_trans(talloc_tos(), cli, SMBtrans2,
446                            NULL, 0, 0, 0,
447                            setup, 1, 0, /* setup */
448                            param, 2, 0,  /* param */
449                            NULL, 0, 560, /* data */
450                            NULL,
451                            NULL, 0, NULL, /* rsetup */
452                            NULL, 0, NULL, /* rparam */
453                            &rdata, 32, &rdata_count);  /* rdata */
454         if (!NT_STATUS_IS_OK(status)) {
455                 goto fail;
456         }
457
458         if (total_allocation_units) {
459                 *total_allocation_units = BIG_UINT(rdata, 0);
460         }
461         if (caller_allocation_units) {
462                 *caller_allocation_units = BIG_UINT(rdata,8);
463         }
464         if (actual_allocation_units) {
465                 *actual_allocation_units = BIG_UINT(rdata,16);
466         }
467         if (sectors_per_allocation_unit) {
468                 *sectors_per_allocation_unit = IVAL(rdata,24);
469         }
470         if (bytes_per_sector) {
471                 *bytes_per_sector = IVAL(rdata,28);
472         }
473
474 fail:
475         TALLOC_FREE(rdata);
476         return status;
477 }
478
479 NTSTATUS cli_get_posix_fs_info(struct cli_state *cli,
480                                uint32_t *optimal_transfer_size,
481                                uint32_t *block_size,
482                                uint64_t *total_blocks,
483                                uint64_t *blocks_available,
484                                uint64_t *user_blocks_available,
485                                uint64_t *total_file_nodes,
486                                uint64_t *free_file_nodes,
487                                uint64_t *fs_identifier)
488 {
489         uint16_t setup[1];
490         uint8_t param[2];
491         uint8_t *rdata = NULL;
492         uint32_t rdata_count;
493         NTSTATUS status;
494
495         SSVAL(setup, 0, TRANSACT2_QFSINFO);
496         SSVAL(param,0,SMB_QUERY_POSIX_FS_INFO);
497
498         status = cli_trans(talloc_tos(), cli, SMBtrans2, NULL, 0, 0, 0,
499                            setup, 1, 0,
500                            param, 2, 0,
501                            NULL, 0, 560,
502                            NULL,
503                            NULL, 0, NULL, /* rsetup */
504                            NULL, 0, NULL, /* rparam */
505                            &rdata, 56, &rdata_count);
506         if (!NT_STATUS_IS_OK(status)) {
507                 return status;
508         }
509
510         if (optimal_transfer_size) {
511                 *optimal_transfer_size = IVAL(rdata, 0);
512         }
513         if (block_size) {
514                 *block_size = IVAL(rdata,4);
515         }
516         if (total_blocks) {
517                 *total_blocks = BIG_UINT(rdata,8);
518         }
519         if (blocks_available) {
520                 *blocks_available = BIG_UINT(rdata,16);
521         }
522         if (user_blocks_available) {
523                 *user_blocks_available = BIG_UINT(rdata,24);
524         }
525         if (total_file_nodes) {
526                 *total_file_nodes = BIG_UINT(rdata,32);
527         }
528         if (free_file_nodes) {
529                 *free_file_nodes = BIG_UINT(rdata,40);
530         }
531         if (fs_identifier) {
532                 *fs_identifier = BIG_UINT(rdata,48);
533         }
534         return NT_STATUS_OK;
535 }
536
537 /****************************************************************************
538  Do a UNIX extensions SMB_QUERY_POSIX_WHOAMI call.
539 ****************************************************************************/
540
541 struct posix_whoami_state {
542         uint16_t setup[1];
543         uint8_t param[2];
544         uint32_t max_rdata;
545         bool guest;
546         uint64_t uid;
547         uint64_t gid;
548         uint32_t num_gids;
549         uint64_t *gids;
550         uint32_t num_sids;
551         struct dom_sid *sids;
552 };
553
554 static void cli_posix_whoami_done(struct tevent_req *subreq);
555
556 struct tevent_req *cli_posix_whoami_send(TALLOC_CTX *mem_ctx,
557                                         struct tevent_context *ev,
558                                         struct cli_state *cli)
559 {
560         struct tevent_req *req = NULL, *subreq = NULL;
561         struct posix_whoami_state *state = NULL;
562
563         req = tevent_req_create(mem_ctx, &state, struct posix_whoami_state);
564         if (req == NULL) {
565                 return NULL;
566         }
567
568         /* Setup setup word. */
569         SSVAL(state->setup, 0, TRANSACT2_QFSINFO);
570         SSVAL(state->param, 0, SMB_QUERY_POSIX_WHOAMI);
571
572         state->max_rdata = 62*1024;
573
574         subreq = cli_trans_send(state,                  /* mem ctx. */
575                                 ev,                     /* event ctx. */
576                                 cli,                    /* cli_state. */
577                                 0,                      /* additional_flags2 */
578                                 SMBtrans2,              /* cmd. */
579                                 NULL,                   /* pipe name. */
580                                 -1,                     /* fid. */
581                                 0,                      /* function. */
582                                 0,                      /* flags. */
583                                 state->setup,           /* setup. */
584                                 1,                      /* num setup uint16_t words. */
585                                 0,                      /* max returned setup. */
586                                 state->param,           /* param. */
587                                 2,                      /* num param. */
588                                 0,                      /* max returned param. */
589                                 NULL,                   /* data. */
590                                 0,                      /* num data. */
591                                 state->max_rdata);      /* max returned data. */
592
593         if (tevent_req_nomem(subreq, req)) {
594                 return tevent_req_post(req, ev);
595         }
596         tevent_req_set_callback(subreq, cli_posix_whoami_done, req);
597         return req;
598 }
599
600 static void cli_posix_whoami_done(struct tevent_req *subreq)
601 {
602         struct tevent_req *req = tevent_req_callback_data(
603                         subreq, struct tevent_req);
604         struct posix_whoami_state *state = tevent_req_data(
605                         req, struct posix_whoami_state);
606         uint8_t *rdata = NULL;
607         uint8_t *p = NULL;
608         uint32_t num_rdata = 0;
609         uint32_t i;
610         NTSTATUS status;
611
612         status = cli_trans_recv(subreq,
613                                 state,
614                                 NULL,
615                                 NULL,
616                                 0,
617                                 NULL,
618                                 NULL,
619                                 0,
620                                 NULL,
621                                 &rdata,
622                                 40,
623                                 &num_rdata);
624         TALLOC_FREE(subreq);
625         if (tevent_req_nterror(req, status)) {
626                 return;
627         }
628
629         /*
630          * Not strictly needed - cli_trans_recv()
631          * will ensure at least 40 bytes here. Added
632          * as more of a reminder to be careful when
633          * parsing network packets in C.
634          */
635
636         if (num_rdata < 40 || rdata + num_rdata < rdata) {
637                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
638                 return;
639         }
640
641         state->guest = (IVAL(rdata, 0) & SMB_WHOAMI_GUEST);
642         state->uid = BVAL(rdata, 8);
643         state->gid = BVAL(rdata, 16);
644         state->num_gids = IVAL(rdata, 24);
645         state->num_sids = IVAL(rdata, 28);
646
647         state->gids = talloc_array(state, uint64_t, state->num_gids);
648         if (tevent_req_nomem(state->gids, req)) {
649                 return;
650         }
651         state->sids = talloc_array(state, struct dom_sid, state->num_sids);
652         if (tevent_req_nomem(state->sids, req)) {
653                 return;
654         }
655
656         p = rdata + 40;
657
658         for (i = 0; i < state->num_gids; i++) {
659                 if (p + 8 > rdata + num_rdata) {
660                         tevent_req_nterror(req,
661                                 NT_STATUS_INVALID_NETWORK_RESPONSE);
662                         return;
663                 }
664                 state->gids[i] = BVAL(p, 0);
665                 p += 8;
666         }
667
668         num_rdata -= (p - rdata);
669
670         for (i = 0; i < state->num_sids; i++) {
671                 size_t sid_size;
672                 DATA_BLOB in = data_blob_const(p, num_rdata);
673                 enum ndr_err_code ndr_err;
674
675                 ndr_err = ndr_pull_struct_blob(&in,
676                                 state,
677                                 &state->sids[i],
678                                 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
679                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
680                         tevent_req_nterror(req,
681                                 NT_STATUS_INVALID_NETWORK_RESPONSE);
682                         return;
683                 }
684
685                 sid_size = ndr_size_dom_sid(&state->sids[i], 0);
686
687                 if (sid_size > num_rdata) {
688                         tevent_req_nterror(req,
689                                 NT_STATUS_INVALID_NETWORK_RESPONSE);
690                         return;
691                 }
692
693                 p += sid_size;
694                 num_rdata -= sid_size;
695         }
696         tevent_req_done(req);
697 }
698
699 NTSTATUS cli_posix_whoami_recv(struct tevent_req *req,
700                         TALLOC_CTX *mem_ctx,
701                         uint64_t *puid,
702                         uint64_t *pgid,
703                         uint32_t *pnum_gids,
704                         uint64_t **pgids,
705                         uint32_t *pnum_sids,
706                         struct dom_sid **psids,
707                         bool *pguest)
708 {
709         NTSTATUS status;
710         struct posix_whoami_state *state = tevent_req_data(
711                         req, struct posix_whoami_state);
712
713         if (tevent_req_is_nterror(req, &status)) {
714                 return status;
715         }
716
717         if (puid) {
718                 *puid = state->uid;
719         }
720         if (pgid) {
721                 *pgid = state->gid;
722         }
723         if (pnum_gids) {
724                 *pnum_gids = state->num_gids;
725         }
726         if (pgids) {
727                 *pgids = talloc_move(mem_ctx, &state->gids);
728         }
729         if (pnum_sids) {
730                 *pnum_sids = state->num_sids;
731         }
732         if (psids) {
733                 *psids = talloc_move(mem_ctx, &state->sids);
734         }
735         if (pguest) {
736                 *pguest = state->guest;
737         }
738         return NT_STATUS_OK;
739 }
740
741 NTSTATUS cli_posix_whoami(struct cli_state *cli,
742                         TALLOC_CTX *mem_ctx,
743                         uint64_t *puid,
744                         uint64_t *pgid,
745                         uint32_t *num_gids,
746                         uint64_t **gids,
747                         uint32_t *num_sids,
748                         struct dom_sid **sids,
749                         bool *pguest)
750 {
751         TALLOC_CTX *frame = talloc_stackframe();
752         struct tevent_context *ev = NULL;
753         struct tevent_req *req = NULL;
754         NTSTATUS status = NT_STATUS_OK;
755
756         if (smbXcli_conn_has_async_calls(cli->conn)) {
757                 /*
758                  * Can't use sync call while an async call is in flight
759                  */
760                 status = NT_STATUS_INVALID_PARAMETER;
761                 goto fail;
762         }
763
764         ev = samba_tevent_context_init(frame);
765         if (ev == NULL) {
766                 status = NT_STATUS_NO_MEMORY;
767                 goto fail;
768         }
769
770         req = cli_posix_whoami_send(frame,
771                                 ev,
772                                 cli);
773         if (req == NULL) {
774                 status = NT_STATUS_NO_MEMORY;
775                 goto fail;
776         }
777
778         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
779                 goto fail;
780         }
781
782         status = cli_posix_whoami_recv(req,
783                         mem_ctx,
784                         puid,
785                         pgid,
786                         num_gids,
787                         gids,
788                         num_sids,
789                         sids,
790                         pguest);
791
792  fail:
793         TALLOC_FREE(frame);
794         return status;
795 }