libsmb: Remove overflow check
[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 (!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         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
379                 return cli_smb2_get_fs_volume_info(cli,
380                                                 mem_ctx,
381                                                 _volume_name,
382                                                 pserial_number,
383                                                 pdate);
384         }
385
386         SSVAL(setup, 0, TRANSACT2_QFSINFO);
387         SSVAL(param,0,SMB_QUERY_FS_VOLUME_INFO);
388
389         status = cli_trans(talloc_tos(), cli, SMBtrans2,
390                            NULL, 0, 0, 0,
391                            setup, 1, 0,
392                            param, 2, 0,
393                            NULL, 0, 560,
394                            &recv_flags2,
395                            NULL, 0, NULL,
396                            NULL, 0, NULL,
397                            &rdata, 18, &rdata_count);
398         if (!NT_STATUS_IS_OK(status)) {
399                 return status;
400         }
401
402         if (pdate) {
403                 struct timespec ts;
404                 ts = interpret_long_date((char *)rdata);
405                 *pdate = ts.tv_sec;
406         }
407         if (pserial_number) {
408                 *pserial_number = IVAL(rdata,8);
409         }
410         nlen = IVAL(rdata,12);
411         if (nlen > (rdata_count - 18)) {
412                 TALLOC_FREE(rdata);
413                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
414         }
415
416         pull_string_talloc(mem_ctx,
417                            (const char *)rdata,
418                            recv_flags2,
419                            &volume_name,
420                            rdata + 18,
421                            nlen, STR_UNICODE);
422         if (volume_name == NULL) {
423                 status = map_nt_error_from_unix(errno);
424                 TALLOC_FREE(rdata);
425                 return status;
426         }
427
428         /* todo: but not yet needed
429          *       return the other stuff
430          */
431
432         *_volume_name = volume_name;
433         TALLOC_FREE(rdata);
434         return NT_STATUS_OK;
435 }
436
437 NTSTATUS cli_get_fs_full_size_info(struct cli_state *cli,
438                                    uint64_t *total_allocation_units,
439                                    uint64_t *caller_allocation_units,
440                                    uint64_t *actual_allocation_units,
441                                    uint64_t *sectors_per_allocation_unit,
442                                    uint64_t *bytes_per_sector)
443 {
444         uint16_t setup[1];
445         uint8_t param[2];
446         uint8_t *rdata = NULL;
447         uint32_t rdata_count;
448         NTSTATUS status;
449
450         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
451                 return cli_smb2_get_fs_full_size_info(cli,
452                                                 total_allocation_units,
453                                                 caller_allocation_units,
454                                                 actual_allocation_units,
455                                                 sectors_per_allocation_unit,
456                                                 bytes_per_sector);
457         }
458
459         SSVAL(setup, 0, TRANSACT2_QFSINFO);
460         SSVAL(param, 0, SMB_FS_FULL_SIZE_INFORMATION);
461
462         status = cli_trans(talloc_tos(), cli, SMBtrans2,
463                            NULL, 0, 0, 0,
464                            setup, 1, 0, /* setup */
465                            param, 2, 0,  /* param */
466                            NULL, 0, 560, /* data */
467                            NULL,
468                            NULL, 0, NULL, /* rsetup */
469                            NULL, 0, NULL, /* rparam */
470                            &rdata, 32, &rdata_count);  /* rdata */
471         if (!NT_STATUS_IS_OK(status)) {
472                 goto fail;
473         }
474
475         if (total_allocation_units) {
476                 *total_allocation_units = BIG_UINT(rdata, 0);
477         }
478         if (caller_allocation_units) {
479                 *caller_allocation_units = BIG_UINT(rdata,8);
480         }
481         if (actual_allocation_units) {
482                 *actual_allocation_units = BIG_UINT(rdata,16);
483         }
484         if (sectors_per_allocation_unit) {
485                 *sectors_per_allocation_unit = IVAL(rdata,24);
486         }
487         if (bytes_per_sector) {
488                 *bytes_per_sector = IVAL(rdata,28);
489         }
490
491 fail:
492         TALLOC_FREE(rdata);
493         return status;
494 }
495
496 NTSTATUS cli_get_posix_fs_info(struct cli_state *cli,
497                                uint32_t *optimal_transfer_size,
498                                uint32_t *block_size,
499                                uint64_t *total_blocks,
500                                uint64_t *blocks_available,
501                                uint64_t *user_blocks_available,
502                                uint64_t *total_file_nodes,
503                                uint64_t *free_file_nodes,
504                                uint64_t *fs_identifier)
505 {
506         uint16_t setup[1];
507         uint8_t param[2];
508         uint8_t *rdata = NULL;
509         uint32_t rdata_count;
510         NTSTATUS status;
511
512         SSVAL(setup, 0, TRANSACT2_QFSINFO);
513         SSVAL(param,0,SMB_QUERY_POSIX_FS_INFO);
514
515         status = cli_trans(talloc_tos(), cli, SMBtrans2, NULL, 0, 0, 0,
516                            setup, 1, 0,
517                            param, 2, 0,
518                            NULL, 0, 560,
519                            NULL,
520                            NULL, 0, NULL, /* rsetup */
521                            NULL, 0, NULL, /* rparam */
522                            &rdata, 56, &rdata_count);
523         if (!NT_STATUS_IS_OK(status)) {
524                 return status;
525         }
526
527         if (optimal_transfer_size) {
528                 *optimal_transfer_size = IVAL(rdata, 0);
529         }
530         if (block_size) {
531                 *block_size = IVAL(rdata,4);
532         }
533         if (total_blocks) {
534                 *total_blocks = BIG_UINT(rdata,8);
535         }
536         if (blocks_available) {
537                 *blocks_available = BIG_UINT(rdata,16);
538         }
539         if (user_blocks_available) {
540                 *user_blocks_available = BIG_UINT(rdata,24);
541         }
542         if (total_file_nodes) {
543                 *total_file_nodes = BIG_UINT(rdata,32);
544         }
545         if (free_file_nodes) {
546                 *free_file_nodes = BIG_UINT(rdata,40);
547         }
548         if (fs_identifier) {
549                 *fs_identifier = BIG_UINT(rdata,48);
550         }
551         return NT_STATUS_OK;
552 }
553
554 /****************************************************************************
555  Do a UNIX extensions SMB_QUERY_POSIX_WHOAMI call.
556 ****************************************************************************/
557
558 struct posix_whoami_state {
559         uint16_t setup[1];
560         uint8_t param[2];
561         uint32_t max_rdata;
562         bool guest;
563         uint64_t uid;
564         uint64_t gid;
565         uint32_t num_gids;
566         uint64_t *gids;
567         uint32_t num_sids;
568         struct dom_sid *sids;
569 };
570
571 static void cli_posix_whoami_done(struct tevent_req *subreq);
572
573 struct tevent_req *cli_posix_whoami_send(TALLOC_CTX *mem_ctx,
574                                         struct tevent_context *ev,
575                                         struct cli_state *cli)
576 {
577         struct tevent_req *req = NULL, *subreq = NULL;
578         struct posix_whoami_state *state = NULL;
579
580         req = tevent_req_create(mem_ctx, &state, struct posix_whoami_state);
581         if (req == NULL) {
582                 return NULL;
583         }
584
585         /* Setup setup word. */
586         SSVAL(state->setup, 0, TRANSACT2_QFSINFO);
587         SSVAL(state->param, 0, SMB_QUERY_POSIX_WHOAMI);
588
589         state->max_rdata = 62*1024;
590
591         subreq = cli_trans_send(state,                  /* mem ctx. */
592                                 ev,                     /* event ctx. */
593                                 cli,                    /* cli_state. */
594                                 0,                      /* additional_flags2 */
595                                 SMBtrans2,              /* cmd. */
596                                 NULL,                   /* pipe name. */
597                                 -1,                     /* fid. */
598                                 0,                      /* function. */
599                                 0,                      /* flags. */
600                                 state->setup,           /* setup. */
601                                 1,                      /* num setup uint16_t words. */
602                                 0,                      /* max returned setup. */
603                                 state->param,           /* param. */
604                                 2,                      /* num param. */
605                                 0,                      /* max returned param. */
606                                 NULL,                   /* data. */
607                                 0,                      /* num data. */
608                                 state->max_rdata);      /* max returned data. */
609
610         if (tevent_req_nomem(subreq, req)) {
611                 return tevent_req_post(req, ev);
612         }
613         tevent_req_set_callback(subreq, cli_posix_whoami_done, req);
614         return req;
615 }
616
617 static void cli_posix_whoami_done(struct tevent_req *subreq)
618 {
619         struct tevent_req *req = tevent_req_callback_data(
620                         subreq, struct tevent_req);
621         struct posix_whoami_state *state = tevent_req_data(
622                         req, struct posix_whoami_state);
623         uint8_t *rdata = NULL;
624         uint8_t *p = NULL;
625         uint32_t num_rdata = 0;
626         uint32_t i;
627         NTSTATUS status;
628
629         status = cli_trans_recv(subreq,
630                                 state,
631                                 NULL,
632                                 NULL,
633                                 0,
634                                 NULL,
635                                 NULL,
636                                 0,
637                                 NULL,
638                                 &rdata,
639                                 40,
640                                 &num_rdata);
641         TALLOC_FREE(subreq);
642         if (tevent_req_nterror(req, status)) {
643                 return;
644         }
645
646         /*
647          * Not strictly needed - cli_trans_recv()
648          * will ensure at least 40 bytes here. Added
649          * as more of a reminder to be careful when
650          * parsing network packets in C.
651          */
652
653         if (num_rdata < 40) {
654                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
655                 return;
656         }
657
658         state->guest = (IVAL(rdata, 0) & SMB_WHOAMI_GUEST);
659         state->uid = BVAL(rdata, 8);
660         state->gid = BVAL(rdata, 16);
661         state->num_gids = IVAL(rdata, 24);
662         state->num_sids = IVAL(rdata, 28);
663
664         state->gids = talloc_array(state, uint64_t, state->num_gids);
665         if (tevent_req_nomem(state->gids, req)) {
666                 return;
667         }
668         state->sids = talloc_array(state, struct dom_sid, state->num_sids);
669         if (tevent_req_nomem(state->sids, req)) {
670                 return;
671         }
672
673         p = rdata + 40;
674
675         for (i = 0; i < state->num_gids; i++) {
676                 if (p + 8 > rdata + num_rdata) {
677                         tevent_req_nterror(req,
678                                 NT_STATUS_INVALID_NETWORK_RESPONSE);
679                         return;
680                 }
681                 state->gids[i] = BVAL(p, 0);
682                 p += 8;
683         }
684
685         num_rdata -= (p - rdata);
686
687         for (i = 0; i < state->num_sids; i++) {
688                 size_t sid_size;
689                 DATA_BLOB in = data_blob_const(p, num_rdata);
690                 enum ndr_err_code ndr_err;
691
692                 ndr_err = ndr_pull_struct_blob(&in,
693                                 state,
694                                 &state->sids[i],
695                                 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
696                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
697                         tevent_req_nterror(req,
698                                 NT_STATUS_INVALID_NETWORK_RESPONSE);
699                         return;
700                 }
701
702                 sid_size = ndr_size_dom_sid(&state->sids[i], 0);
703
704                 if (sid_size > num_rdata) {
705                         tevent_req_nterror(req,
706                                 NT_STATUS_INVALID_NETWORK_RESPONSE);
707                         return;
708                 }
709
710                 p += sid_size;
711                 num_rdata -= sid_size;
712         }
713         tevent_req_done(req);
714 }
715
716 NTSTATUS cli_posix_whoami_recv(struct tevent_req *req,
717                         TALLOC_CTX *mem_ctx,
718                         uint64_t *puid,
719                         uint64_t *pgid,
720                         uint32_t *pnum_gids,
721                         uint64_t **pgids,
722                         uint32_t *pnum_sids,
723                         struct dom_sid **psids,
724                         bool *pguest)
725 {
726         NTSTATUS status;
727         struct posix_whoami_state *state = tevent_req_data(
728                         req, struct posix_whoami_state);
729
730         if (tevent_req_is_nterror(req, &status)) {
731                 return status;
732         }
733
734         if (puid) {
735                 *puid = state->uid;
736         }
737         if (pgid) {
738                 *pgid = state->gid;
739         }
740         if (pnum_gids) {
741                 *pnum_gids = state->num_gids;
742         }
743         if (pgids) {
744                 *pgids = talloc_move(mem_ctx, &state->gids);
745         }
746         if (pnum_sids) {
747                 *pnum_sids = state->num_sids;
748         }
749         if (psids) {
750                 *psids = talloc_move(mem_ctx, &state->sids);
751         }
752         if (pguest) {
753                 *pguest = state->guest;
754         }
755         return NT_STATUS_OK;
756 }
757
758 NTSTATUS cli_posix_whoami(struct cli_state *cli,
759                         TALLOC_CTX *mem_ctx,
760                         uint64_t *puid,
761                         uint64_t *pgid,
762                         uint32_t *num_gids,
763                         uint64_t **gids,
764                         uint32_t *num_sids,
765                         struct dom_sid **sids,
766                         bool *pguest)
767 {
768         TALLOC_CTX *frame = talloc_stackframe();
769         struct tevent_context *ev = NULL;
770         struct tevent_req *req = NULL;
771         NTSTATUS status = NT_STATUS_OK;
772
773         if (smbXcli_conn_has_async_calls(cli->conn)) {
774                 /*
775                  * Can't use sync call while an async call is in flight
776                  */
777                 status = NT_STATUS_INVALID_PARAMETER;
778                 goto fail;
779         }
780
781         ev = samba_tevent_context_init(frame);
782         if (ev == NULL) {
783                 status = NT_STATUS_NO_MEMORY;
784                 goto fail;
785         }
786
787         req = cli_posix_whoami_send(frame,
788                                 ev,
789                                 cli);
790         if (req == NULL) {
791                 status = NT_STATUS_NO_MEMORY;
792                 goto fail;
793         }
794
795         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
796                 goto fail;
797         }
798
799         status = cli_posix_whoami_recv(req,
800                         mem_ctx,
801                         puid,
802                         pgid,
803                         num_gids,
804                         gids,
805                         num_sids,
806                         sids,
807                         pguest);
808
809  fail:
810         TALLOC_FREE(frame);
811         return status;
812 }