s3:libsmb: avoid passing a function call as function parameter
[Samba.git] / source3 / libsmb / clifsinfo.c
blob00fd47264b2b85bd8e142b928d6812b8d77137eb
1 /*
2 Unix SMB/CIFS implementation.
3 FS info functions
4 Copyright (C) Stefan (metze) Metzmacher 2003
5 Copyright (C) Jeremy Allison 2007
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
22 #include "../libcli/auth/spnego.h"
24 /****************************************************************************
25 Get UNIX extensions version info.
26 ****************************************************************************/
28 struct cli_unix_extensions_version_state {
29 uint16_t setup[1];
30 uint8_t param[2];
31 uint16_t major, minor;
32 uint32_t caplow, caphigh;
35 static void cli_unix_extensions_version_done(struct tevent_req *subreq);
37 struct tevent_req *cli_unix_extensions_version_send(TALLOC_CTX *mem_ctx,
38 struct tevent_context *ev,
39 struct cli_state *cli)
41 struct tevent_req *req, *subreq;
42 struct cli_unix_extensions_version_state *state;
44 req = tevent_req_create(mem_ctx, &state,
45 struct cli_unix_extensions_version_state);
46 if (req == NULL) {
47 return NULL;
49 SSVAL(state->setup, 0, TRANSACT2_QFSINFO);
50 SSVAL(state->param, 0, SMB_QUERY_CIFS_UNIX_INFO);
52 subreq = cli_trans_send(state, ev, cli, SMBtrans2,
53 NULL, 0, 0, 0,
54 state->setup, 1, 0,
55 state->param, 2, 0,
56 NULL, 0, 560);
57 if (tevent_req_nomem(subreq, req)) {
58 return tevent_req_post(req, ev);
60 tevent_req_set_callback(subreq, cli_unix_extensions_version_done, req);
61 return req;
64 static void cli_unix_extensions_version_done(struct tevent_req *subreq)
66 struct tevent_req *req = tevent_req_callback_data(
67 subreq, struct tevent_req);
68 struct cli_unix_extensions_version_state *state = tevent_req_data(
69 req, struct cli_unix_extensions_version_state);
70 uint8_t *data;
71 uint32_t num_data;
72 NTSTATUS status;
74 status = cli_trans_recv(subreq, state, NULL, 0, NULL, NULL, 0, NULL,
75 &data, 12, &num_data);
76 TALLOC_FREE(subreq);
77 if (!NT_STATUS_IS_OK(status)) {
78 tevent_req_nterror(req, status);
79 return;
82 state->major = SVAL(data, 0);
83 state->minor = SVAL(data, 2);
84 state->caplow = IVAL(data, 4);
85 state->caphigh = IVAL(data, 8);
86 TALLOC_FREE(data);
87 tevent_req_done(req);
90 NTSTATUS cli_unix_extensions_version_recv(struct tevent_req *req,
91 uint16_t *pmajor, uint16_t *pminor,
92 uint32_t *pcaplow,
93 uint32_t *pcaphigh)
95 struct cli_unix_extensions_version_state *state = tevent_req_data(
96 req, struct cli_unix_extensions_version_state);
97 NTSTATUS status;
99 if (tevent_req_is_nterror(req, &status)) {
100 return status;
102 *pmajor = state->major;
103 *pminor = state->minor;
104 *pcaplow = state->caplow;
105 *pcaphigh = state->caphigh;
106 return NT_STATUS_OK;
109 NTSTATUS cli_unix_extensions_version(struct cli_state *cli, uint16 *pmajor,
110 uint16 *pminor, uint32 *pcaplow,
111 uint32 *pcaphigh)
113 TALLOC_CTX *frame = talloc_stackframe();
114 struct event_context *ev;
115 struct tevent_req *req;
116 NTSTATUS status = NT_STATUS_OK;
118 if (cli_has_async_calls(cli)) {
120 * Can't use sync call while an async call is in flight
122 status = NT_STATUS_INVALID_PARAMETER;
123 goto fail;
126 ev = event_context_init(frame);
127 if (ev == NULL) {
128 status = NT_STATUS_NO_MEMORY;
129 goto fail;
132 req = cli_unix_extensions_version_send(frame, ev, cli);
133 if (req == NULL) {
134 status = NT_STATUS_NO_MEMORY;
135 goto fail;
138 if (!tevent_req_poll(req, ev)) {
139 status = map_nt_error_from_unix(errno);
140 goto fail;
143 status = cli_unix_extensions_version_recv(req, pmajor, pminor, pcaplow,
144 pcaphigh);
145 if (NT_STATUS_IS_OK(status)) {
146 cli->posix_capabilities = *pcaplow;
148 fail:
149 TALLOC_FREE(frame);
150 if (!NT_STATUS_IS_OK(status)) {
151 cli_set_error(cli, status);
153 return status;
156 /****************************************************************************
157 Set UNIX extensions capabilities.
158 ****************************************************************************/
160 struct cli_set_unix_extensions_capabilities_state {
161 uint16_t setup[1];
162 uint8_t param[4];
163 uint8_t data[12];
166 static void cli_set_unix_extensions_capabilities_done(
167 struct tevent_req *subreq);
169 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)
173 struct tevent_req *req, *subreq;
174 struct cli_set_unix_extensions_capabilities_state *state;
176 req = tevent_req_create(
177 mem_ctx, &state,
178 struct cli_set_unix_extensions_capabilities_state);
179 if (req == NULL) {
180 return NULL;
183 SSVAL(state->setup+0, 0, TRANSACT2_SETFSINFO);
185 SSVAL(state->param, 0, 0);
186 SSVAL(state->param, 2, SMB_SET_CIFS_UNIX_INFO);
188 SSVAL(state->data, 0, major);
189 SSVAL(state->data, 2, minor);
190 SIVAL(state->data, 4, caplow);
191 SIVAL(state->data, 8, caphigh);
193 subreq = cli_trans_send(state, ev, cli, SMBtrans2,
194 NULL, 0, 0, 0,
195 state->setup, 1, 0,
196 state->param, 4, 0,
197 state->data, 12, 560);
198 if (tevent_req_nomem(subreq, req)) {
199 return tevent_req_post(req, ev);
201 tevent_req_set_callback(
202 subreq, cli_set_unix_extensions_capabilities_done, req);
203 return req;
206 static void cli_set_unix_extensions_capabilities_done(
207 struct tevent_req *subreq)
209 NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, 0, NULL,
210 NULL, 0, NULL, NULL, 0, NULL);
211 return tevent_req_simple_finish_ntstatus(subreq, status);
214 NTSTATUS cli_set_unix_extensions_capabilities_recv(struct tevent_req *req)
216 return tevent_req_simple_recv_ntstatus(req);
219 NTSTATUS cli_set_unix_extensions_capabilities(struct cli_state *cli,
220 uint16 major, uint16 minor,
221 uint32 caplow, uint32 caphigh)
223 struct tevent_context *ev;
224 struct tevent_req *req;
225 NTSTATUS status = NT_STATUS_NO_MEMORY;
227 if (cli_has_async_calls(cli)) {
228 return NT_STATUS_INVALID_PARAMETER;
230 ev = tevent_context_init(talloc_tos());
231 if (ev == NULL) {
232 goto fail;
234 req = cli_set_unix_extensions_capabilities_send(
235 ev, ev, cli, major, minor, caplow, caphigh);
236 if (req == NULL) {
237 goto fail;
239 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
240 goto fail;
242 status = cli_set_unix_extensions_capabilities_recv(req);
243 fail:
244 TALLOC_FREE(ev);
245 if (!NT_STATUS_IS_OK(status)) {
246 cli_set_error(cli, status);
248 return status;
251 bool cli_get_fs_attr_info(struct cli_state *cli, uint32 *fs_attr)
253 bool ret = False;
254 uint16 setup;
255 char param[2];
256 char *rparam=NULL, *rdata=NULL;
257 unsigned int rparam_count=0, rdata_count=0;
259 if (!cli||!fs_attr)
260 smb_panic("cli_get_fs_attr_info() called with NULL Pionter!");
262 setup = TRANSACT2_QFSINFO;
264 SSVAL(param,0,SMB_QUERY_FS_ATTRIBUTE_INFO);
266 if (!cli_send_trans(cli, SMBtrans2,
267 NULL,
268 0, 0,
269 &setup, 1, 0,
270 param, 2, 0,
271 NULL, 0, 560)) {
272 goto cleanup;
275 if (!cli_receive_trans(cli, SMBtrans2,
276 &rparam, &rparam_count,
277 &rdata, &rdata_count)) {
278 goto cleanup;
281 if (cli_is_error(cli)) {
282 ret = False;
283 goto cleanup;
284 } else {
285 ret = True;
288 if (rdata_count < 12) {
289 goto cleanup;
292 *fs_attr = IVAL(rdata,0);
294 /* todo: but not yet needed
295 * return the other stuff
298 cleanup:
299 SAFE_FREE(rparam);
300 SAFE_FREE(rdata);
302 return ret;
305 bool cli_get_fs_volume_info_old(struct cli_state *cli, fstring volume_name, uint32 *pserial_number)
307 bool ret = False;
308 uint16 setup;
309 char param[2];
310 char *rparam=NULL, *rdata=NULL;
311 unsigned int rparam_count=0, rdata_count=0;
312 unsigned char nlen;
314 setup = TRANSACT2_QFSINFO;
316 SSVAL(param,0,SMB_INFO_VOLUME);
318 if (!cli_send_trans(cli, SMBtrans2,
319 NULL,
320 0, 0,
321 &setup, 1, 0,
322 param, 2, 0,
323 NULL, 0, 560)) {
324 goto cleanup;
327 if (!cli_receive_trans(cli, SMBtrans2,
328 &rparam, &rparam_count,
329 &rdata, &rdata_count)) {
330 goto cleanup;
333 if (cli_is_error(cli)) {
334 ret = False;
335 goto cleanup;
336 } else {
337 ret = True;
340 if (rdata_count < 5) {
341 goto cleanup;
344 if (pserial_number) {
345 *pserial_number = IVAL(rdata,0);
347 nlen = CVAL(rdata,l2_vol_cch);
348 clistr_pull(cli->inbuf, volume_name, rdata + l2_vol_szVolLabel,
349 sizeof(fstring), nlen, STR_NOALIGN);
351 /* todo: but not yet needed
352 * return the other stuff
355 cleanup:
356 SAFE_FREE(rparam);
357 SAFE_FREE(rdata);
359 return ret;
362 bool cli_get_fs_volume_info(struct cli_state *cli, fstring volume_name, uint32 *pserial_number, time_t *pdate)
364 bool ret = False;
365 uint16 setup;
366 char param[2];
367 char *rparam=NULL, *rdata=NULL;
368 unsigned int rparam_count=0, rdata_count=0;
369 unsigned int nlen;
371 setup = TRANSACT2_QFSINFO;
373 SSVAL(param,0,SMB_QUERY_FS_VOLUME_INFO);
375 if (!cli_send_trans(cli, SMBtrans2,
376 NULL,
377 0, 0,
378 &setup, 1, 0,
379 param, 2, 0,
380 NULL, 0, 560)) {
381 goto cleanup;
384 if (!cli_receive_trans(cli, SMBtrans2,
385 &rparam, &rparam_count,
386 &rdata, &rdata_count)) {
387 goto cleanup;
390 if (cli_is_error(cli)) {
391 ret = False;
392 goto cleanup;
393 } else {
394 ret = True;
397 if (rdata_count < 19) {
398 goto cleanup;
401 if (pdate) {
402 struct timespec ts;
403 ts = interpret_long_date(rdata);
404 *pdate = ts.tv_sec;
406 if (pserial_number) {
407 *pserial_number = IVAL(rdata,8);
409 nlen = IVAL(rdata,12);
410 clistr_pull(cli->inbuf, volume_name, rdata + 18, sizeof(fstring),
411 nlen, STR_UNICODE);
413 /* todo: but not yet needed
414 * return the other stuff
417 cleanup:
418 SAFE_FREE(rparam);
419 SAFE_FREE(rdata);
421 return ret;
424 bool cli_get_fs_full_size_info(struct cli_state *cli,
425 uint64_t *total_allocation_units,
426 uint64_t *caller_allocation_units,
427 uint64_t *actual_allocation_units,
428 uint64_t *sectors_per_allocation_unit,
429 uint64_t *bytes_per_sector)
431 bool ret = False;
432 uint16 setup;
433 char param[2];
434 char *rparam=NULL, *rdata=NULL;
435 unsigned int rparam_count=0, rdata_count=0;
437 setup = TRANSACT2_QFSINFO;
439 SSVAL(param,0,SMB_FS_FULL_SIZE_INFORMATION);
441 if (!cli_send_trans(cli, SMBtrans2,
442 NULL,
443 0, 0,
444 &setup, 1, 0,
445 param, 2, 0,
446 NULL, 0, 560)) {
447 goto cleanup;
450 if (!cli_receive_trans(cli, SMBtrans2,
451 &rparam, &rparam_count,
452 &rdata, &rdata_count)) {
453 goto cleanup;
456 if (cli_is_error(cli)) {
457 ret = False;
458 goto cleanup;
459 } else {
460 ret = True;
463 if (rdata_count != 32) {
464 goto cleanup;
467 if (total_allocation_units) {
468 *total_allocation_units = BIG_UINT(rdata, 0);
470 if (caller_allocation_units) {
471 *caller_allocation_units = BIG_UINT(rdata,8);
473 if (actual_allocation_units) {
474 *actual_allocation_units = BIG_UINT(rdata,16);
476 if (sectors_per_allocation_unit) {
477 *sectors_per_allocation_unit = IVAL(rdata,24);
479 if (bytes_per_sector) {
480 *bytes_per_sector = IVAL(rdata,28);
483 cleanup:
484 SAFE_FREE(rparam);
485 SAFE_FREE(rdata);
487 return ret;
490 bool cli_get_posix_fs_info(struct cli_state *cli,
491 uint32 *optimal_transfer_size,
492 uint32 *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)
500 bool ret = False;
501 uint16 setup;
502 char param[2];
503 char *rparam=NULL, *rdata=NULL;
504 unsigned int rparam_count=0, rdata_count=0;
506 setup = TRANSACT2_QFSINFO;
508 SSVAL(param,0,SMB_QUERY_POSIX_FS_INFO);
510 if (!cli_send_trans(cli, SMBtrans2,
511 NULL,
512 0, 0,
513 &setup, 1, 0,
514 param, 2, 0,
515 NULL, 0, 560)) {
516 goto cleanup;
519 if (!cli_receive_trans(cli, SMBtrans2,
520 &rparam, &rparam_count,
521 &rdata, &rdata_count)) {
522 goto cleanup;
525 if (cli_is_error(cli)) {
526 ret = False;
527 goto cleanup;
528 } else {
529 ret = True;
532 if (rdata_count != 56) {
533 goto cleanup;
536 if (optimal_transfer_size) {
537 *optimal_transfer_size = IVAL(rdata, 0);
539 if (block_size) {
540 *block_size = IVAL(rdata,4);
542 if (total_blocks) {
543 *total_blocks = BIG_UINT(rdata,8);
545 if (blocks_available) {
546 *blocks_available = BIG_UINT(rdata,16);
548 if (user_blocks_available) {
549 *user_blocks_available = BIG_UINT(rdata,24);
551 if (total_file_nodes) {
552 *total_file_nodes = BIG_UINT(rdata,32);
554 if (free_file_nodes) {
555 *free_file_nodes = BIG_UINT(rdata,40);
557 if (fs_identifier) {
558 *fs_identifier = BIG_UINT(rdata,48);
561 cleanup:
562 SAFE_FREE(rparam);
563 SAFE_FREE(rdata);
565 return ret;
569 /******************************************************************************
570 Send/receive the request encryption blob.
571 ******************************************************************************/
573 static NTSTATUS enc_blob_send_receive(struct cli_state *cli, DATA_BLOB *in, DATA_BLOB *out, DATA_BLOB *param_out)
575 uint16 setup;
576 char param[4];
577 char *rparam=NULL, *rdata=NULL;
578 unsigned int rparam_count=0, rdata_count=0;
579 NTSTATUS status = NT_STATUS_OK;
581 setup = TRANSACT2_SETFSINFO;
583 SSVAL(param,0,0);
584 SSVAL(param,2,SMB_REQUEST_TRANSPORT_ENCRYPTION);
586 if (!cli_send_trans(cli, SMBtrans2,
587 NULL,
588 0, 0,
589 &setup, 1, 0,
590 param, 4, 0,
591 (char *)in->data, in->length, CLI_BUFFER_SIZE)) {
592 status = cli_nt_error(cli);
593 goto out;
596 if (!cli_receive_trans(cli, SMBtrans2,
597 &rparam, &rparam_count,
598 &rdata, &rdata_count)) {
599 status = cli_nt_error(cli);
600 goto out;
603 if (cli_is_error(cli)) {
604 status = cli_nt_error(cli);
605 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
606 goto out;
610 *out = data_blob(rdata, rdata_count);
611 *param_out = data_blob(rparam, rparam_count);
613 out:
615 SAFE_FREE(rparam);
616 SAFE_FREE(rdata);
617 return status;
620 /******************************************************************************
621 Make a client state struct.
622 ******************************************************************************/
624 static struct smb_trans_enc_state *make_cli_enc_state(enum smb_trans_enc_type smb_enc_type)
626 struct smb_trans_enc_state *es = NULL;
627 es = SMB_MALLOC_P(struct smb_trans_enc_state);
628 if (!es) {
629 return NULL;
631 ZERO_STRUCTP(es);
632 es->smb_enc_type = smb_enc_type;
634 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
635 if (smb_enc_type == SMB_TRANS_ENC_GSS) {
636 es->s.gss_state = SMB_MALLOC_P(struct smb_tran_enc_state_gss);
637 if (!es->s.gss_state) {
638 SAFE_FREE(es);
639 return NULL;
641 ZERO_STRUCTP(es->s.gss_state);
643 #endif
644 return es;
647 /******************************************************************************
648 Start a raw ntlmssp encryption.
649 ******************************************************************************/
651 NTSTATUS cli_raw_ntlm_smb_encryption_start(struct cli_state *cli,
652 const char *user,
653 const char *pass,
654 const char *domain)
656 DATA_BLOB blob_in = data_blob_null;
657 DATA_BLOB blob_out = data_blob_null;
658 DATA_BLOB param_out = data_blob_null;
659 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
660 struct smb_trans_enc_state *es = make_cli_enc_state(SMB_TRANS_ENC_NTLM);
662 if (!es) {
663 return NT_STATUS_NO_MEMORY;
665 status = ntlmssp_client_start(&es->s.ntlmssp_state);
666 if (!NT_STATUS_IS_OK(status)) {
667 goto fail;
670 ntlmssp_want_feature(es->s.ntlmssp_state, NTLMSSP_FEATURE_SESSION_KEY);
671 es->s.ntlmssp_state->neg_flags |= (NTLMSSP_NEGOTIATE_SIGN|NTLMSSP_NEGOTIATE_SEAL);
673 if (!NT_STATUS_IS_OK(status = ntlmssp_set_username(es->s.ntlmssp_state, user))) {
674 goto fail;
676 if (!NT_STATUS_IS_OK(status = ntlmssp_set_domain(es->s.ntlmssp_state, domain))) {
677 goto fail;
679 if (!NT_STATUS_IS_OK(status = ntlmssp_set_password(es->s.ntlmssp_state, pass))) {
680 goto fail;
683 do {
684 status = ntlmssp_update(es->s.ntlmssp_state, blob_in, &blob_out);
685 data_blob_free(&blob_in);
686 data_blob_free(&param_out);
687 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) || NT_STATUS_IS_OK(status)) {
688 NTSTATUS trans_status = enc_blob_send_receive(cli,
689 &blob_out,
690 &blob_in,
691 &param_out);
692 if (!NT_STATUS_EQUAL(trans_status,
693 NT_STATUS_MORE_PROCESSING_REQUIRED) &&
694 !NT_STATUS_IS_OK(trans_status)) {
695 status = trans_status;
696 } else {
697 if (param_out.length == 2) {
698 es->enc_ctx_num = SVAL(param_out.data, 0);
702 data_blob_free(&blob_out);
703 } while (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED));
705 data_blob_free(&blob_in);
707 if (NT_STATUS_IS_OK(status)) {
708 /* Replace the old state, if any. */
709 if (cli->trans_enc_state) {
710 common_free_encryption_state(&cli->trans_enc_state);
712 cli->trans_enc_state = es;
713 cli->trans_enc_state->enc_on = True;
714 es = NULL;
717 fail:
719 common_free_encryption_state(&es);
720 return status;
723 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
725 #ifndef SMB_GSS_REQUIRED_FLAGS
726 #define SMB_GSS_REQUIRED_FLAGS (GSS_C_CONF_FLAG|GSS_C_INTEG_FLAG|GSS_C_MUTUAL_FLAG|GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG)
727 #endif
729 /******************************************************************************
730 Get client gss blob to send to a server.
731 ******************************************************************************/
733 static NTSTATUS make_cli_gss_blob(struct smb_trans_enc_state *es,
734 const char *service,
735 const char *host,
736 NTSTATUS status_in,
737 DATA_BLOB spnego_blob_in,
738 DATA_BLOB *p_blob_out)
740 const char *krb_mechs[] = {OID_KERBEROS5, NULL};
741 OM_uint32 ret;
742 OM_uint32 min;
743 gss_name_t srv_name;
744 gss_buffer_desc input_name;
745 gss_buffer_desc *p_tok_in;
746 gss_buffer_desc tok_out, tok_in;
747 DATA_BLOB blob_out = data_blob_null;
748 DATA_BLOB blob_in = data_blob_null;
749 char *host_princ_s = NULL;
750 OM_uint32 ret_flags = 0;
751 NTSTATUS status = NT_STATUS_OK;
753 gss_OID_desc nt_hostbased_service =
754 {10, CONST_DISCARD(char *,"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04")};
756 memset(&tok_out, '\0', sizeof(tok_out));
758 /* Get a ticket for the service@host */
759 if (asprintf(&host_princ_s, "%s@%s", service, host) == -1) {
760 return NT_STATUS_NO_MEMORY;
763 input_name.value = host_princ_s;
764 input_name.length = strlen(host_princ_s) + 1;
766 ret = gss_import_name(&min,
767 &input_name,
768 &nt_hostbased_service,
769 &srv_name);
771 if (ret != GSS_S_COMPLETE) {
772 SAFE_FREE(host_princ_s);
773 return map_nt_error_from_gss(ret, min);
776 if (spnego_blob_in.length == 0) {
777 p_tok_in = GSS_C_NO_BUFFER;
778 } else {
779 /* Remove the SPNEGO wrapper */
780 if (!spnego_parse_auth_response(spnego_blob_in, status_in, OID_KERBEROS5, &blob_in)) {
781 status = NT_STATUS_UNSUCCESSFUL;
782 goto fail;
784 tok_in.value = blob_in.data;
785 tok_in.length = blob_in.length;
786 p_tok_in = &tok_in;
789 ret = gss_init_sec_context(&min,
790 GSS_C_NO_CREDENTIAL, /* Use our default cred. */
791 &es->s.gss_state->gss_ctx,
792 srv_name,
793 GSS_C_NO_OID, /* default OID. */
794 GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG,
795 GSS_C_INDEFINITE, /* requested ticket lifetime. */
796 NULL, /* no channel bindings */
797 p_tok_in,
798 NULL, /* ignore mech type */
799 &tok_out,
800 &ret_flags,
801 NULL); /* ignore time_rec */
803 status = map_nt_error_from_gss(ret, min);
804 if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED)) {
805 ADS_STATUS adss = ADS_ERROR_GSS(ret, min);
806 DEBUG(10,("make_cli_gss_blob: gss_init_sec_context failed with %s\n",
807 ads_errstr(adss)));
808 goto fail;
811 if ((ret_flags & SMB_GSS_REQUIRED_FLAGS) != SMB_GSS_REQUIRED_FLAGS) {
812 status = NT_STATUS_ACCESS_DENIED;
815 blob_out = data_blob(tok_out.value, tok_out.length);
817 /* Wrap in an SPNEGO wrapper */
818 *p_blob_out = gen_negTokenTarg(krb_mechs, blob_out);
820 fail:
822 data_blob_free(&blob_out);
823 data_blob_free(&blob_in);
824 SAFE_FREE(host_princ_s);
825 gss_release_name(&min, &srv_name);
826 if (tok_out.value) {
827 gss_release_buffer(&min, &tok_out);
829 return status;
832 /******************************************************************************
833 Start a SPNEGO gssapi encryption context.
834 ******************************************************************************/
836 NTSTATUS cli_gss_smb_encryption_start(struct cli_state *cli)
838 DATA_BLOB blob_recv = data_blob_null;
839 DATA_BLOB blob_send = data_blob_null;
840 DATA_BLOB param_out = data_blob_null;
841 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
842 fstring fqdn;
843 const char *servicename;
844 struct smb_trans_enc_state *es = make_cli_enc_state(SMB_TRANS_ENC_GSS);
846 if (!es) {
847 return NT_STATUS_NO_MEMORY;
850 name_to_fqdn(fqdn, cli->desthost);
851 strlower_m(fqdn);
853 servicename = "cifs";
854 status = make_cli_gss_blob(es, servicename, fqdn, NT_STATUS_OK, blob_recv, &blob_send);
855 if (!NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED)) {
856 servicename = "host";
857 status = make_cli_gss_blob(es, servicename, fqdn, NT_STATUS_OK, blob_recv, &blob_send);
858 if (!NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED)) {
859 goto fail;
863 do {
864 data_blob_free(&blob_recv);
865 status = enc_blob_send_receive(cli, &blob_send, &blob_recv, &param_out);
866 if (param_out.length == 2) {
867 es->enc_ctx_num = SVAL(param_out.data, 0);
869 data_blob_free(&blob_send);
870 status = make_cli_gss_blob(es, servicename, fqdn, status, blob_recv, &blob_send);
871 } while (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED));
872 data_blob_free(&blob_recv);
874 if (NT_STATUS_IS_OK(status)) {
875 /* Replace the old state, if any. */
876 if (cli->trans_enc_state) {
877 common_free_encryption_state(&cli->trans_enc_state);
879 cli->trans_enc_state = es;
880 cli->trans_enc_state->enc_on = True;
881 es = NULL;
884 fail:
886 common_free_encryption_state(&es);
887 return status;
889 #else
890 NTSTATUS cli_gss_smb_encryption_start(struct cli_state *cli)
892 return NT_STATUS_NOT_SUPPORTED;
894 #endif
896 /********************************************************************
897 Ensure a connection is encrypted.
898 ********************************************************************/
900 NTSTATUS cli_force_encryption(struct cli_state *c,
901 const char *username,
902 const char *password,
903 const char *domain)
905 uint16 major, minor;
906 uint32 caplow, caphigh;
907 NTSTATUS status;
909 if (!SERVER_HAS_UNIX_CIFS(c)) {
910 return NT_STATUS_NOT_SUPPORTED;
913 status = cli_unix_extensions_version(c, &major, &minor, &caplow,
914 &caphigh);
915 if (!NT_STATUS_IS_OK(status)) {
916 DEBUG(10, ("cli_force_encryption: cli_unix_extensions_version "
917 "returned %s\n", nt_errstr(status)));
918 return NT_STATUS_UNKNOWN_REVISION;
921 if (!(caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP)) {
922 return NT_STATUS_UNSUPPORTED_COMPRESSION;
925 if (c->use_kerberos) {
926 return cli_gss_smb_encryption_start(c);
928 return cli_raw_ntlm_smb_encryption_start(c,
929 username,
930 password,
931 domain);