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