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