Line data Source code
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 0 : 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 0 : req = tevent_req_create(mem_ctx, &state,
55 : struct cli_unix_extensions_version_state);
56 0 : if (req == NULL) {
57 0 : return NULL;
58 : }
59 0 : state->cli = cli;
60 0 : SSVAL(state->setup, 0, TRANSACT2_QFSINFO);
61 0 : SSVAL(state->param, 0, SMB_QUERY_CIFS_UNIX_INFO);
62 :
63 0 : subreq = cli_trans_send(state, ev, cli, 0, SMBtrans2,
64 : NULL, 0, 0, 0,
65 0 : state->setup, 1, 0,
66 0 : state->param, 2, 0,
67 : NULL, 0, 560);
68 0 : if (tevent_req_nomem(subreq, req)) {
69 0 : return tevent_req_post(req, ev);
70 : }
71 0 : tevent_req_set_callback(subreq, cli_unix_extensions_version_done, req);
72 0 : return req;
73 : }
74 :
75 0 : static void cli_unix_extensions_version_done(struct tevent_req *subreq)
76 : {
77 0 : struct tevent_req *req = tevent_req_callback_data(
78 : subreq, struct tevent_req);
79 0 : 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 0 : status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
86 : NULL, 0, NULL, &data, 12, &num_data);
87 0 : TALLOC_FREE(subreq);
88 0 : if (!NT_STATUS_IS_OK(status)) {
89 0 : tevent_req_nterror(req, status);
90 0 : return;
91 : }
92 :
93 0 : state->major = SVAL(data, 0);
94 0 : state->minor = SVAL(data, 2);
95 0 : state->caplow = IVAL(data, 4);
96 0 : state->caphigh = IVAL(data, 8);
97 0 : TALLOC_FREE(data);
98 0 : tevent_req_done(req);
99 : }
100 :
101 0 : 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 0 : struct cli_unix_extensions_version_state *state = tevent_req_data(
107 : req, struct cli_unix_extensions_version_state);
108 : NTSTATUS status;
109 :
110 0 : if (tevent_req_is_nterror(req, &status)) {
111 0 : return status;
112 : }
113 0 : *pmajor = state->major;
114 0 : *pminor = state->minor;
115 0 : *pcaplow = state->caplow;
116 0 : *pcaphigh = state->caphigh;
117 0 : state->cli->server_posix_capabilities = *pcaplow;
118 0 : return NT_STATUS_OK;
119 : }
120 :
121 0 : 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 0 : TALLOC_CTX *frame = talloc_stackframe();
126 : struct tevent_context *ev;
127 : struct tevent_req *req;
128 0 : NTSTATUS status = NT_STATUS_OK;
129 :
130 0 : if (smbXcli_conn_has_async_calls(cli->conn)) {
131 : /*
132 : * Can't use sync call while an async call is in flight
133 : */
134 0 : status = NT_STATUS_INVALID_PARAMETER;
135 0 : goto fail;
136 : }
137 :
138 0 : ev = samba_tevent_context_init(frame);
139 0 : if (ev == NULL) {
140 0 : status = NT_STATUS_NO_MEMORY;
141 0 : goto fail;
142 : }
143 :
144 0 : req = cli_unix_extensions_version_send(frame, ev, cli);
145 0 : if (req == NULL) {
146 0 : status = NT_STATUS_NO_MEMORY;
147 0 : goto fail;
148 : }
149 :
150 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
151 0 : goto fail;
152 : }
153 :
154 0 : status = cli_unix_extensions_version_recv(req, pmajor, pminor, pcaplow,
155 : pcaphigh);
156 0 : fail:
157 0 : TALLOC_FREE(frame);
158 0 : 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 0 : 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 0 : req = tevent_req_create(
183 : mem_ctx, &state,
184 : struct cli_set_unix_extensions_capabilities_state);
185 0 : if (req == NULL) {
186 0 : return NULL;
187 : }
188 :
189 0 : state->cli = cli;
190 0 : SSVAL(state->setup+0, 0, TRANSACT2_SETFSINFO);
191 :
192 0 : SSVAL(state->param, 0, 0);
193 0 : SSVAL(state->param, 2, SMB_SET_CIFS_UNIX_INFO);
194 :
195 0 : SSVAL(state->data, 0, major);
196 0 : SSVAL(state->data, 2, minor);
197 0 : SIVAL(state->data, 4, caplow);
198 0 : SIVAL(state->data, 8, caphigh);
199 :
200 0 : subreq = cli_trans_send(state, ev, cli, 0, SMBtrans2,
201 : NULL, 0, 0, 0,
202 0 : state->setup, 1, 0,
203 0 : state->param, 4, 0,
204 0 : state->data, 12, 560);
205 0 : if (tevent_req_nomem(subreq, req)) {
206 0 : return tevent_req_post(req, ev);
207 : }
208 0 : tevent_req_set_callback(
209 : subreq, cli_set_unix_extensions_capabilities_done, req);
210 0 : return req;
211 : }
212 :
213 0 : static void cli_set_unix_extensions_capabilities_done(
214 : struct tevent_req *subreq)
215 : {
216 0 : struct tevent_req *req = tevent_req_callback_data(
217 : subreq, struct tevent_req);
218 0 : struct cli_set_unix_extensions_capabilities_state *state = tevent_req_data(
219 : req, struct cli_set_unix_extensions_capabilities_state);
220 :
221 0 : NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
222 : NULL, 0, NULL, NULL, 0, NULL);
223 0 : if (NT_STATUS_IS_OK(status)) {
224 0 : state->cli->requested_posix_capabilities = IVAL(state->data, 4);
225 : }
226 0 : tevent_req_simple_finish_ntstatus(subreq, status);
227 0 : }
228 :
229 0 : NTSTATUS cli_set_unix_extensions_capabilities_recv(struct tevent_req *req)
230 : {
231 0 : return tevent_req_simple_recv_ntstatus(req);
232 : }
233 :
234 0 : 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 0 : NTSTATUS status = NT_STATUS_NO_MEMORY;
241 :
242 0 : if (smbXcli_conn_has_async_calls(cli->conn)) {
243 0 : return NT_STATUS_INVALID_PARAMETER;
244 : }
245 0 : ev = samba_tevent_context_init(talloc_tos());
246 0 : if (ev == NULL) {
247 0 : goto fail;
248 : }
249 0 : req = cli_set_unix_extensions_capabilities_send(
250 : ev, ev, cli, major, minor, caplow, caphigh);
251 0 : if (req == NULL) {
252 0 : goto fail;
253 : }
254 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
255 0 : goto fail;
256 : }
257 0 : status = cli_set_unix_extensions_capabilities_recv(req);
258 0 : fail:
259 0 : TALLOC_FREE(ev);
260 0 : 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 1 : 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 1 : req = tevent_req_create(mem_ctx, &state,
279 : struct cli_get_fs_attr_info_state);
280 1 : if (req == NULL) {
281 0 : return NULL;
282 : }
283 1 : SSVAL(state->setup+0, 0, TRANSACT2_QFSINFO);
284 1 : SSVAL(state->param+0, 0, SMB_QUERY_FS_ATTRIBUTE_INFO);
285 :
286 1 : subreq = cli_trans_send(state, ev, cli, 0, SMBtrans2,
287 : NULL, 0, 0, 0,
288 1 : state->setup, 1, 0,
289 1 : state->param, 2, 0,
290 : NULL, 0, 560);
291 1 : if (tevent_req_nomem(subreq, req)) {
292 0 : return tevent_req_post(req, ev);
293 : }
294 1 : tevent_req_set_callback(subreq, cli_get_fs_attr_info_done, req);
295 1 : return req;
296 : }
297 :
298 1 : static void cli_get_fs_attr_info_done(struct tevent_req *subreq)
299 : {
300 1 : struct tevent_req *req = tevent_req_callback_data(
301 : subreq, struct tevent_req);
302 1 : 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 1 : status = cli_trans_recv(subreq, talloc_tos(), NULL, NULL, 0, NULL,
309 : NULL, 0, NULL, &data, 12, &num_data);
310 1 : TALLOC_FREE(subreq);
311 1 : if (!NT_STATUS_IS_OK(status)) {
312 0 : tevent_req_nterror(req, status);
313 0 : return;
314 : }
315 1 : state->fs_attr = IVAL(data, 0);
316 1 : TALLOC_FREE(data);
317 1 : tevent_req_done(req);
318 : }
319 :
320 1 : NTSTATUS cli_get_fs_attr_info_recv(struct tevent_req *req, uint32_t *fs_attr)
321 : {
322 1 : 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 1 : if (tevent_req_is_nterror(req, &status)) {
327 0 : return status;
328 : }
329 1 : *fs_attr = state->fs_attr;
330 1 : return NT_STATUS_OK;
331 : }
332 :
333 1 : 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 1 : NTSTATUS status = NT_STATUS_NO_MEMORY;
338 :
339 1 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
340 0 : return cli_smb2_get_fs_attr_info(cli, fs_attr);
341 : }
342 :
343 1 : if (smbXcli_conn_has_async_calls(cli->conn)) {
344 0 : return NT_STATUS_INVALID_PARAMETER;
345 : }
346 1 : ev = samba_tevent_context_init(talloc_tos());
347 1 : if (ev == NULL) {
348 0 : goto fail;
349 : }
350 1 : req = cli_get_fs_attr_info_send(ev, ev, cli);
351 1 : if (req == NULL) {
352 0 : goto fail;
353 : }
354 1 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
355 0 : goto fail;
356 : }
357 1 : status = cli_get_fs_attr_info_recv(req, fs_attr);
358 1 : fail:
359 1 : TALLOC_FREE(ev);
360 1 : return status;
361 : }
362 :
363 4 : 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 4 : char *volume_name = NULL;
377 :
378 4 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
379 4 : return cli_smb2_get_fs_volume_info(cli,
380 : mem_ctx,
381 : _volume_name,
382 : pserial_number,
383 : pdate);
384 : }
385 :
386 0 : SSVAL(setup, 0, TRANSACT2_QFSINFO);
387 0 : SSVAL(param,0,SMB_QUERY_FS_VOLUME_INFO);
388 :
389 0 : 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 0 : if (!NT_STATUS_IS_OK(status)) {
399 0 : return status;
400 : }
401 :
402 0 : if (pdate) {
403 : struct timespec ts;
404 0 : ts = interpret_long_date((char *)rdata);
405 0 : *pdate = ts.tv_sec;
406 : }
407 0 : if (pserial_number) {
408 0 : *pserial_number = IVAL(rdata,8);
409 : }
410 0 : nlen = IVAL(rdata,12);
411 0 : if (nlen > (rdata_count - 18)) {
412 0 : TALLOC_FREE(rdata);
413 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
414 : }
415 :
416 0 : pull_string_talloc(mem_ctx,
417 : (const char *)rdata,
418 : recv_flags2,
419 : &volume_name,
420 0 : rdata + 18,
421 : nlen, STR_UNICODE);
422 0 : if (volume_name == NULL) {
423 0 : status = map_nt_error_from_unix(errno);
424 0 : TALLOC_FREE(rdata);
425 0 : return status;
426 : }
427 :
428 : /* todo: but not yet needed
429 : * return the other stuff
430 : */
431 :
432 0 : *_volume_name = volume_name;
433 0 : TALLOC_FREE(rdata);
434 0 : return NT_STATUS_OK;
435 : }
436 :
437 0 : 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 0 : uint8_t *rdata = NULL;
447 : uint32_t rdata_count;
448 : NTSTATUS status;
449 :
450 0 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
451 0 : 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 0 : SSVAL(setup, 0, TRANSACT2_QFSINFO);
460 0 : SSVAL(param, 0, SMB_FS_FULL_SIZE_INFORMATION);
461 :
462 0 : 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 0 : if (!NT_STATUS_IS_OK(status)) {
472 0 : goto fail;
473 : }
474 :
475 0 : if (total_allocation_units) {
476 0 : *total_allocation_units = BIG_UINT(rdata, 0);
477 : }
478 0 : if (caller_allocation_units) {
479 0 : *caller_allocation_units = BIG_UINT(rdata,8);
480 : }
481 0 : if (actual_allocation_units) {
482 0 : *actual_allocation_units = BIG_UINT(rdata,16);
483 : }
484 0 : if (sectors_per_allocation_unit) {
485 0 : *sectors_per_allocation_unit = IVAL(rdata,24);
486 : }
487 0 : if (bytes_per_sector) {
488 0 : *bytes_per_sector = IVAL(rdata,28);
489 : }
490 :
491 0 : fail:
492 0 : TALLOC_FREE(rdata);
493 0 : return status;
494 : }
495 :
496 0 : 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 0 : uint8_t *rdata = NULL;
509 : uint32_t rdata_count;
510 : NTSTATUS status;
511 :
512 0 : SSVAL(setup, 0, TRANSACT2_QFSINFO);
513 0 : SSVAL(param,0,SMB_QUERY_POSIX_FS_INFO);
514 :
515 0 : 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 0 : if (!NT_STATUS_IS_OK(status)) {
524 0 : return status;
525 : }
526 :
527 0 : if (optimal_transfer_size) {
528 0 : *optimal_transfer_size = IVAL(rdata, 0);
529 : }
530 0 : if (block_size) {
531 0 : *block_size = IVAL(rdata,4);
532 : }
533 0 : if (total_blocks) {
534 0 : *total_blocks = BIG_UINT(rdata,8);
535 : }
536 0 : if (blocks_available) {
537 0 : *blocks_available = BIG_UINT(rdata,16);
538 : }
539 0 : if (user_blocks_available) {
540 0 : *user_blocks_available = BIG_UINT(rdata,24);
541 : }
542 0 : if (total_file_nodes) {
543 0 : *total_file_nodes = BIG_UINT(rdata,32);
544 : }
545 0 : if (free_file_nodes) {
546 0 : *free_file_nodes = BIG_UINT(rdata,40);
547 : }
548 0 : if (fs_identifier) {
549 0 : *fs_identifier = BIG_UINT(rdata,48);
550 : }
551 0 : 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 8 : struct tevent_req *cli_posix_whoami_send(TALLOC_CTX *mem_ctx,
576 : struct tevent_context *ev,
577 : struct cli_state *cli)
578 : {
579 8 : struct tevent_req *req = NULL, *subreq = NULL;
580 8 : struct posix_whoami_state *state = NULL;
581 :
582 8 : req = tevent_req_create(mem_ctx, &state, struct posix_whoami_state);
583 8 : if (req == NULL) {
584 0 : return NULL;
585 : }
586 :
587 : /* Setup setup word. */
588 8 : SSVAL(state->setup, 0, TRANSACT2_QFSINFO);
589 8 : SSVAL(state->param, 0, SMB_QUERY_POSIX_WHOAMI);
590 :
591 8 : state->max_rdata = posix_whoami_max_rdata;
592 :
593 12 : 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 8 : state->setup, /* setup. */
603 : 1, /* num setup uint16_t words. */
604 : 0, /* max returned setup. */
605 8 : state->param, /* param. */
606 : 2, /* num param. */
607 : 0, /* max returned param. */
608 : NULL, /* data. */
609 : 0, /* num data. */
610 8 : state->max_rdata); /* max returned data. */
611 :
612 8 : if (tevent_req_nomem(subreq, req)) {
613 0 : return tevent_req_post(req, ev);
614 : }
615 8 : tevent_req_set_callback(subreq, cli_posix_whoami_done, req);
616 8 : return req;
617 : }
618 :
619 8 : static void cli_posix_whoami_done(struct tevent_req *subreq)
620 : {
621 8 : struct tevent_req *req = tevent_req_callback_data(
622 : subreq, struct tevent_req);
623 8 : struct posix_whoami_state *state = tevent_req_data(
624 : req, struct posix_whoami_state);
625 8 : uint8_t *rdata = NULL;
626 8 : uint8_t *p = NULL;
627 8 : uint32_t num_rdata = 0;
628 : uint32_t i;
629 : NTSTATUS status;
630 :
631 8 : 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 8 : TALLOC_FREE(subreq);
644 8 : if (tevent_req_nterror(req, status)) {
645 0 : 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 8 : if (num_rdata < 40 || num_rdata > posix_whoami_max_rdata) {
656 0 : tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
657 0 : return;
658 : }
659 :
660 8 : state->guest = (IVAL(rdata, 0) & SMB_WHOAMI_GUEST);
661 8 : state->uid = BVAL(rdata, 8);
662 8 : state->gid = BVAL(rdata, 16);
663 8 : state->num_gids = IVAL(rdata, 24);
664 8 : state->num_sids = IVAL(rdata, 28);
665 :
666 : /* Ensure the gid array doesn't overflow */
667 8 : if (state->num_gids > (num_rdata - 40) / sizeof(uint64_t)) {
668 0 : tevent_req_nterror(req,
669 : NT_STATUS_INVALID_NETWORK_RESPONSE);
670 0 : return;
671 : }
672 :
673 8 : state->gids = talloc_array(state, uint64_t, state->num_gids);
674 8 : if (tevent_req_nomem(state->gids, req)) {
675 0 : return;
676 : }
677 8 : state->sids = talloc_array(state, struct dom_sid, state->num_sids);
678 8 : if (tevent_req_nomem(state->sids, req)) {
679 0 : return;
680 : }
681 :
682 8 : p = rdata + 40;
683 :
684 44 : for (i = 0; i < state->num_gids; i++) {
685 36 : state->gids[i] = BVAL(p, 0);
686 36 : p += 8;
687 : }
688 :
689 8 : num_rdata -= (p - rdata);
690 :
691 147 : for (i = 0; i < state->num_sids; i++) {
692 : size_t sid_size;
693 90 : DATA_BLOB in = data_blob_const(p, num_rdata);
694 : enum ndr_err_code ndr_err;
695 :
696 90 : ndr_err = ndr_pull_struct_blob(&in,
697 : state,
698 90 : &state->sids[i],
699 : (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
700 90 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
701 0 : tevent_req_nterror(req,
702 : NT_STATUS_INVALID_NETWORK_RESPONSE);
703 0 : return;
704 : }
705 :
706 90 : sid_size = ndr_size_dom_sid(&state->sids[i], 0);
707 :
708 90 : if (sid_size > num_rdata) {
709 0 : tevent_req_nterror(req,
710 : NT_STATUS_INVALID_NETWORK_RESPONSE);
711 0 : return;
712 : }
713 :
714 90 : p += sid_size;
715 90 : num_rdata -= sid_size;
716 : }
717 :
718 8 : if (num_rdata != 0) {
719 0 : tevent_req_nterror(req,
720 : NT_STATUS_INVALID_NETWORK_RESPONSE);
721 0 : return;
722 : }
723 :
724 8 : tevent_req_done(req);
725 : }
726 :
727 8 : 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 8 : struct posix_whoami_state *state = tevent_req_data(
739 : req, struct posix_whoami_state);
740 :
741 8 : if (tevent_req_is_nterror(req, &status)) {
742 0 : return status;
743 : }
744 :
745 8 : if (puid) {
746 8 : *puid = state->uid;
747 : }
748 8 : if (pgid) {
749 8 : *pgid = state->gid;
750 : }
751 8 : if (pnum_gids) {
752 8 : *pnum_gids = state->num_gids;
753 : }
754 8 : if (pgids) {
755 8 : *pgids = talloc_move(mem_ctx, &state->gids);
756 : }
757 8 : if (pnum_sids) {
758 8 : *pnum_sids = state->num_sids;
759 : }
760 8 : if (psids) {
761 8 : *psids = talloc_move(mem_ctx, &state->sids);
762 : }
763 8 : if (pguest) {
764 8 : *pguest = state->guest;
765 : }
766 8 : return NT_STATUS_OK;
767 : }
768 :
769 0 : 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 0 : TALLOC_CTX *frame = talloc_stackframe();
780 0 : struct tevent_context *ev = NULL;
781 0 : struct tevent_req *req = NULL;
782 0 : NTSTATUS status = NT_STATUS_OK;
783 :
784 0 : if (smbXcli_conn_has_async_calls(cli->conn)) {
785 : /*
786 : * Can't use sync call while an async call is in flight
787 : */
788 0 : status = NT_STATUS_INVALID_PARAMETER;
789 0 : goto fail;
790 : }
791 :
792 0 : ev = samba_tevent_context_init(frame);
793 0 : if (ev == NULL) {
794 0 : status = NT_STATUS_NO_MEMORY;
795 0 : goto fail;
796 : }
797 :
798 0 : req = cli_posix_whoami_send(frame,
799 : ev,
800 : cli);
801 0 : if (req == NULL) {
802 0 : status = NT_STATUS_NO_MEMORY;
803 0 : goto fail;
804 : }
805 :
806 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
807 0 : goto fail;
808 : }
809 :
810 0 : 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 0 : fail:
821 0 : TALLOC_FREE(frame);
822 0 : return status;
823 : }
|