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