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