python:tests: Store keys as bytes rather than as lists of ints
[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 static const uint32_t posix_whoami_max_rdata = 62*1024;
574
575 struct tevent_req *cli_posix_whoami_send(TALLOC_CTX *mem_ctx,
576                                         struct tevent_context *ev,
577                                         struct cli_state *cli)
578 {
579         struct tevent_req *req = NULL, *subreq = NULL;
580         struct posix_whoami_state *state = NULL;
581
582         req = tevent_req_create(mem_ctx, &state, struct posix_whoami_state);
583         if (req == NULL) {
584                 return NULL;
585         }
586
587         /* Setup setup word. */
588         SSVAL(state->setup, 0, TRANSACT2_QFSINFO);
589         SSVAL(state->param, 0, SMB_QUERY_POSIX_WHOAMI);
590
591         state->max_rdata = posix_whoami_max_rdata;
592
593         subreq = cli_trans_send(state,                  /* mem ctx. */
594                                 ev,                     /* event ctx. */
595                                 cli,                    /* cli_state. */
596                                 0,                      /* additional_flags2 */
597                                 SMBtrans2,              /* cmd. */
598                                 NULL,                   /* pipe name. */
599                                 -1,                     /* fid. */
600                                 0,                      /* function. */
601                                 0,                      /* flags. */
602                                 state->setup,           /* setup. */
603                                 1,                      /* num setup uint16_t words. */
604                                 0,                      /* max returned setup. */
605                                 state->param,           /* param. */
606                                 2,                      /* num param. */
607                                 0,                      /* max returned param. */
608                                 NULL,                   /* data. */
609                                 0,                      /* num data. */
610                                 state->max_rdata);      /* max returned data. */
611
612         if (tevent_req_nomem(subreq, req)) {
613                 return tevent_req_post(req, ev);
614         }
615         tevent_req_set_callback(subreq, cli_posix_whoami_done, req);
616         return req;
617 }
618
619 static void cli_posix_whoami_done(struct tevent_req *subreq)
620 {
621         struct tevent_req *req = tevent_req_callback_data(
622                         subreq, struct tevent_req);
623         struct posix_whoami_state *state = tevent_req_data(
624                         req, struct posix_whoami_state);
625         uint8_t *rdata = NULL;
626         uint8_t *p = NULL;
627         uint32_t num_rdata = 0;
628         uint32_t i;
629         NTSTATUS status;
630
631         status = cli_trans_recv(subreq,
632                                 state,
633                                 NULL,
634                                 NULL,
635                                 0,
636                                 NULL,
637                                 NULL,
638                                 0,
639                                 NULL,
640                                 &rdata,
641                                 40,
642                                 &num_rdata);
643         TALLOC_FREE(subreq);
644         if (tevent_req_nterror(req, status)) {
645                 return;
646         }
647
648         /*
649          * Not strictly needed - cli_trans_recv()
650          * will ensure at least 40 bytes here. Added
651          * as more of a reminder to be careful when
652          * parsing network packets in C.
653          */
654
655         if (num_rdata < 40 || num_rdata > posix_whoami_max_rdata) {
656                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
657                 return;
658         }
659
660         state->guest = (IVAL(rdata, 0) & SMB_WHOAMI_GUEST);
661         state->uid = BVAL(rdata, 8);
662         state->gid = BVAL(rdata, 16);
663         state->num_gids = IVAL(rdata, 24);
664         state->num_sids = IVAL(rdata, 28);
665
666         /* Ensure the gid array doesn't overflow */
667         if (state->num_gids > (num_rdata - 40) / sizeof(uint64_t)) {
668                 tevent_req_nterror(req,
669                         NT_STATUS_INVALID_NETWORK_RESPONSE);
670                 return;
671         }
672
673         state->gids = talloc_array(state, uint64_t, state->num_gids);
674         if (tevent_req_nomem(state->gids, req)) {
675                 return;
676         }
677         state->sids = talloc_array(state, struct dom_sid, state->num_sids);
678         if (tevent_req_nomem(state->sids, req)) {
679                 return;
680         }
681
682         p = rdata + 40;
683
684         for (i = 0; i < state->num_gids; i++) {
685                 state->gids[i] = BVAL(p, 0);
686                 p += 8;
687         }
688
689         num_rdata -= (p - rdata);
690
691         for (i = 0; i < state->num_sids; i++) {
692                 size_t sid_size;
693                 DATA_BLOB in = data_blob_const(p, num_rdata);
694                 enum ndr_err_code ndr_err;
695
696                 ndr_err = ndr_pull_struct_blob(&in,
697                                 state,
698                                 &state->sids[i],
699                                 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
700                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
701                         tevent_req_nterror(req,
702                                 NT_STATUS_INVALID_NETWORK_RESPONSE);
703                         return;
704                 }
705
706                 sid_size = ndr_size_dom_sid(&state->sids[i], 0);
707
708                 if (sid_size > num_rdata) {
709                         tevent_req_nterror(req,
710                                 NT_STATUS_INVALID_NETWORK_RESPONSE);
711                         return;
712                 }
713
714                 p += sid_size;
715                 num_rdata -= sid_size;
716         }
717
718         if (num_rdata != 0) {
719                 tevent_req_nterror(req,
720                         NT_STATUS_INVALID_NETWORK_RESPONSE);
721                 return;
722         }
723
724         tevent_req_done(req);
725 }
726
727 NTSTATUS cli_posix_whoami_recv(struct tevent_req *req,
728                         TALLOC_CTX *mem_ctx,
729                         uint64_t *puid,
730                         uint64_t *pgid,
731                         uint32_t *pnum_gids,
732                         uint64_t **pgids,
733                         uint32_t *pnum_sids,
734                         struct dom_sid **psids,
735                         bool *pguest)
736 {
737         NTSTATUS status;
738         struct posix_whoami_state *state = tevent_req_data(
739                         req, struct posix_whoami_state);
740
741         if (tevent_req_is_nterror(req, &status)) {
742                 return status;
743         }
744
745         if (puid) {
746                 *puid = state->uid;
747         }
748         if (pgid) {
749                 *pgid = state->gid;
750         }
751         if (pnum_gids) {
752                 *pnum_gids = state->num_gids;
753         }
754         if (pgids) {
755                 *pgids = talloc_move(mem_ctx, &state->gids);
756         }
757         if (pnum_sids) {
758                 *pnum_sids = state->num_sids;
759         }
760         if (psids) {
761                 *psids = talloc_move(mem_ctx, &state->sids);
762         }
763         if (pguest) {
764                 *pguest = state->guest;
765         }
766         return NT_STATUS_OK;
767 }
768
769 NTSTATUS cli_posix_whoami(struct cli_state *cli,
770                         TALLOC_CTX *mem_ctx,
771                         uint64_t *puid,
772                         uint64_t *pgid,
773                         uint32_t *num_gids,
774                         uint64_t **gids,
775                         uint32_t *num_sids,
776                         struct dom_sid **sids,
777                         bool *pguest)
778 {
779         TALLOC_CTX *frame = talloc_stackframe();
780         struct tevent_context *ev = NULL;
781         struct tevent_req *req = NULL;
782         NTSTATUS status = NT_STATUS_OK;
783
784         if (smbXcli_conn_has_async_calls(cli->conn)) {
785                 /*
786                  * Can't use sync call while an async call is in flight
787                  */
788                 status = NT_STATUS_INVALID_PARAMETER;
789                 goto fail;
790         }
791
792         ev = samba_tevent_context_init(frame);
793         if (ev == NULL) {
794                 status = NT_STATUS_NO_MEMORY;
795                 goto fail;
796         }
797
798         req = cli_posix_whoami_send(frame,
799                                 ev,
800                                 cli);
801         if (req == NULL) {
802                 status = NT_STATUS_NO_MEMORY;
803                 goto fail;
804         }
805
806         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
807                 goto fail;
808         }
809
810         status = cli_posix_whoami_recv(req,
811                         mem_ctx,
812                         puid,
813                         pgid,
814                         num_gids,
815                         gids,
816                         num_sids,
817                         sids,
818                         pguest);
819
820  fail:
821         TALLOC_FREE(frame);
822         return status;
823 }