2 Unix SMB/CIFS implementation.
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/>.
22 #include "../libcli/auth/spnego.h"
24 /****************************************************************************
25 Get UNIX extensions version info.
26 ****************************************************************************/
28 struct cli_unix_extensions_version_state {
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);
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,
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);
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);
74 status = cli_trans_recv(subreq, state, NULL, 0, NULL, NULL, 0, NULL,
75 &data, 12, &num_data);
77 if (!NT_STATUS_IS_OK(status)) {
78 tevent_req_nterror(req, status);
82 state->major = SVAL(data, 0);
83 state->minor = SVAL(data, 2);
84 state->caplow = IVAL(data, 4);
85 state->caphigh = IVAL(data, 8);
90 NTSTATUS cli_unix_extensions_version_recv(struct tevent_req *req,
91 uint16_t *pmajor, uint16_t *pminor,
95 struct cli_unix_extensions_version_state *state = tevent_req_data(
96 req, struct cli_unix_extensions_version_state);
99 if (tevent_req_is_nterror(req, &status)) {
102 *pmajor = state->major;
103 *pminor = state->minor;
104 *pcaplow = state->caplow;
105 *pcaphigh = state->caphigh;
109 NTSTATUS cli_unix_extensions_version(struct cli_state *cli, uint16 *pmajor,
110 uint16 *pminor, uint32 *pcaplow,
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;
126 ev = event_context_init(frame);
128 status = NT_STATUS_NO_MEMORY;
132 req = cli_unix_extensions_version_send(frame, ev, cli);
134 status = NT_STATUS_NO_MEMORY;
138 if (!tevent_req_poll(req, ev)) {
139 status = map_nt_error_from_unix(errno);
143 status = cli_unix_extensions_version_recv(req, pmajor, pminor, pcaplow,
145 if (NT_STATUS_IS_OK(status)) {
146 cli->posix_capabilities = *pcaplow;
150 if (!NT_STATUS_IS_OK(status)) {
151 cli_set_error(cli, status);
156 /****************************************************************************
157 Set UNIX extensions capabilities.
158 ****************************************************************************/
160 struct cli_set_unix_extensions_capabilities_state {
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(
178 struct cli_set_unix_extensions_capabilities_state);
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,
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);
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());
234 req = cli_set_unix_extensions_capabilities_send(
235 ev, ev, cli, major, minor, caplow, caphigh);
239 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
242 status = cli_set_unix_extensions_capabilities_recv(req);
245 if (!NT_STATUS_IS_OK(status)) {
246 cli_set_error(cli, status);
251 bool cli_get_fs_attr_info(struct cli_state *cli, uint32 *fs_attr)
256 char *rparam=NULL, *rdata=NULL;
257 unsigned int rparam_count=0, rdata_count=0;
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,
275 if (!cli_receive_trans(cli, SMBtrans2,
276 &rparam, &rparam_count,
277 &rdata, &rdata_count)) {
281 if (cli_is_error(cli)) {
288 if (rdata_count < 12) {
292 *fs_attr = IVAL(rdata,0);
294 /* todo: but not yet needed
295 * return the other stuff
305 bool cli_get_fs_volume_info_old(struct cli_state *cli, fstring volume_name, uint32 *pserial_number)
310 char *rparam=NULL, *rdata=NULL;
311 unsigned int rparam_count=0, rdata_count=0;
314 setup = TRANSACT2_QFSINFO;
316 SSVAL(param,0,SMB_INFO_VOLUME);
318 if (!cli_send_trans(cli, SMBtrans2,
327 if (!cli_receive_trans(cli, SMBtrans2,
328 &rparam, &rparam_count,
329 &rdata, &rdata_count)) {
333 if (cli_is_error(cli)) {
340 if (rdata_count < 5) {
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
362 bool cli_get_fs_volume_info(struct cli_state *cli, fstring volume_name, uint32 *pserial_number, time_t *pdate)
367 char *rparam=NULL, *rdata=NULL;
368 unsigned int rparam_count=0, rdata_count=0;
371 setup = TRANSACT2_QFSINFO;
373 SSVAL(param,0,SMB_QUERY_FS_VOLUME_INFO);
375 if (!cli_send_trans(cli, SMBtrans2,
384 if (!cli_receive_trans(cli, SMBtrans2,
385 &rparam, &rparam_count,
386 &rdata, &rdata_count)) {
390 if (cli_is_error(cli)) {
397 if (rdata_count < 19) {
403 ts = interpret_long_date(rdata);
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),
413 /* todo: but not yet needed
414 * return the other stuff
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)
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,
450 if (!cli_receive_trans(cli, SMBtrans2,
451 &rparam, &rparam_count,
452 &rdata, &rdata_count)) {
456 if (cli_is_error(cli)) {
463 if (rdata_count != 32) {
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);
490 bool cli_get_posix_fs_info(struct cli_state *cli,
491 uint32 *optimal_transfer_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)
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,
519 if (!cli_receive_trans(cli, SMBtrans2,
520 &rparam, &rparam_count,
521 &rdata, &rdata_count)) {
525 if (cli_is_error(cli)) {
532 if (rdata_count != 56) {
536 if (optimal_transfer_size) {
537 *optimal_transfer_size = IVAL(rdata, 0);
540 *block_size = IVAL(rdata,4);
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);
558 *fs_identifier = BIG_UINT(rdata,48);
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)
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;
584 SSVAL(param,2,SMB_REQUEST_TRANSPORT_ENCRYPTION);
586 if (!cli_send_trans(cli, SMBtrans2,
591 (char *)in->data, in->length, CLI_BUFFER_SIZE)) {
592 status = cli_nt_error(cli);
596 if (!cli_receive_trans(cli, SMBtrans2,
597 &rparam, &rparam_count,
598 &rdata, &rdata_count)) {
599 status = cli_nt_error(cli);
603 if (cli_is_error(cli)) {
604 status = cli_nt_error(cli);
605 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
610 *out = data_blob(rdata, rdata_count);
611 *param_out = data_blob(rparam, rparam_count);
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);
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) {
641 ZERO_STRUCTP(es->s.gss_state);
647 /******************************************************************************
648 Start a raw ntlmssp encryption.
649 ******************************************************************************/
651 NTSTATUS cli_raw_ntlm_smb_encryption_start(struct cli_state *cli,
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);
663 return NT_STATUS_NO_MEMORY;
665 status = ntlmssp_client_start(&es->s.ntlmssp_state);
666 if (!NT_STATUS_IS_OK(status)) {
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))) {
676 if (!NT_STATUS_IS_OK(status = ntlmssp_set_domain(es->s.ntlmssp_state, domain))) {
679 if (!NT_STATUS_IS_OK(status = ntlmssp_set_password(es->s.ntlmssp_state, pass))) {
684 status = ntlmssp_update(es->s.ntlmssp_state, blob_in, &blob_out);
685 data_blob_free(&blob_in);
686 data_blob_free(¶m_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,
692 if (!NT_STATUS_EQUAL(trans_status,
693 NT_STATUS_MORE_PROCESSING_REQUIRED) &&
694 !NT_STATUS_IS_OK(trans_status)) {
695 status = trans_status;
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;
719 common_free_encryption_state(&es);
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)
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,
737 DATA_BLOB spnego_blob_in,
738 DATA_BLOB *p_blob_out)
740 const char *krb_mechs[] = {OID_KERBEROS5, NULL};
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,
768 &nt_hostbased_service,
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;
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;
784 tok_in.value = blob_in.data;
785 tok_in.length = blob_in.length;
789 ret = gss_init_sec_context(&min,
790 GSS_C_NO_CREDENTIAL, /* Use our default cred. */
791 &es->s.gss_state->gss_ctx,
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 */
798 NULL, /* ignore mech type */
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",
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);
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);
827 gss_release_buffer(&min, &tok_out);
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;
843 const char *servicename;
844 struct smb_trans_enc_state *es = make_cli_enc_state(SMB_TRANS_ENC_GSS);
847 return NT_STATUS_NO_MEMORY;
850 name_to_fqdn(fqdn, cli->desthost);
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)) {
864 data_blob_free(&blob_recv);
865 status = enc_blob_send_receive(cli, &blob_send, &blob_recv, ¶m_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;
886 common_free_encryption_state(&es);
890 NTSTATUS cli_gss_smb_encryption_start(struct cli_state *cli)
892 return NT_STATUS_NOT_SUPPORTED;
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,
906 uint32 caplow, caphigh;
909 if (!SERVER_HAS_UNIX_CIFS(c)) {
910 return NT_STATUS_NOT_SUPPORTED;
913 status = cli_unix_extensions_version(c, &major, &minor, &caplow,
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,