s3-spnego: Fix Bug #6815. Windows 2008 R2 SPNEGO negTokenTarg parsing failure.
[ira/wip.git] / source3 / libsmb / clifsinfo.c
1 /* 
2    Unix SMB/CIFS implementation.
3    FS info functions
4    Copyright (C) Stefan (metze) Metzmacher      2003
5    Copyright (C) Jeremy Allison 2007
6    
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.
11    
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.
16    
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/>.
19 */
20
21 #include "includes.h"
22 #include "../libcli/auth/spnego.h"
23
24 /****************************************************************************
25  Get UNIX extensions version info.
26 ****************************************************************************/
27
28 bool cli_unix_extensions_version(struct cli_state *cli, uint16 *pmajor, uint16 *pminor,
29                                         uint32 *pcaplow, uint32 *pcaphigh)
30 {
31         bool ret = False;
32         uint16 setup;
33         char param[2];
34         char *rparam=NULL, *rdata=NULL;
35         unsigned int rparam_count=0, rdata_count=0;
36
37         setup = TRANSACT2_QFSINFO;
38
39         SSVAL(param,0,SMB_QUERY_CIFS_UNIX_INFO);
40
41         if (!cli_send_trans(cli, SMBtrans2,
42                     NULL,
43                     0, 0,
44                     &setup, 1, 0,
45                     param, 2, 0,
46                     NULL, 0, 560)) {
47                 goto cleanup;
48         }
49
50         if (!cli_receive_trans(cli, SMBtrans2,
51                               &rparam, &rparam_count,
52                               &rdata, &rdata_count)) {
53                 goto cleanup;
54         }
55
56         if (cli_is_error(cli)) {
57                 ret = False;
58                 goto cleanup;
59         } else {
60                 ret = True;
61         }
62
63         if (rdata_count < 12) {
64                 goto cleanup;
65         }
66
67         *pmajor = SVAL(rdata,0);
68         *pminor = SVAL(rdata,2);
69         cli->posix_capabilities = *pcaplow = IVAL(rdata,4);
70         *pcaphigh = IVAL(rdata,8);
71
72         /* todo: but not yet needed
73          *       return the other stuff
74          */
75
76 cleanup:
77         SAFE_FREE(rparam);
78         SAFE_FREE(rdata);
79
80         return ret;
81 }
82
83 /****************************************************************************
84  Set UNIX extensions capabilities.
85 ****************************************************************************/
86
87 bool cli_set_unix_extensions_capabilities(struct cli_state *cli, uint16 major, uint16 minor,
88                                         uint32 caplow, uint32 caphigh)
89 {
90         bool ret = False;
91         uint16 setup;
92         char param[4];
93         char data[12];
94         char *rparam=NULL, *rdata=NULL;
95         unsigned int rparam_count=0, rdata_count=0;
96
97         setup = TRANSACT2_SETFSINFO;
98
99         SSVAL(param,0,0);
100         SSVAL(param,2,SMB_SET_CIFS_UNIX_INFO);
101
102         SSVAL(data,0,major);
103         SSVAL(data,2,minor);
104         SIVAL(data,4,caplow);
105         SIVAL(data,8,caphigh);
106
107         if (!cli_send_trans(cli, SMBtrans2,
108                     NULL,
109                     0, 0,
110                     &setup, 1, 0,
111                     param, 4, 0,
112                     data, 12, 560)) {
113                 goto cleanup;
114         }
115
116         if (!cli_receive_trans(cli, SMBtrans2,
117                               &rparam, &rparam_count,
118                               &rdata, &rdata_count)) {
119                 goto cleanup;
120         }
121
122         if (cli_is_error(cli)) {
123                 ret = False;
124                 goto cleanup;
125         } else {
126                 ret = True;
127         }
128
129 cleanup:
130         SAFE_FREE(rparam);
131         SAFE_FREE(rdata);
132
133         return ret;
134 }
135
136 bool cli_get_fs_attr_info(struct cli_state *cli, uint32 *fs_attr)
137 {
138         bool ret = False;
139         uint16 setup;
140         char param[2];
141         char *rparam=NULL, *rdata=NULL;
142         unsigned int rparam_count=0, rdata_count=0;
143
144         if (!cli||!fs_attr)
145                 smb_panic("cli_get_fs_attr_info() called with NULL Pionter!");
146
147         setup = TRANSACT2_QFSINFO;
148
149         SSVAL(param,0,SMB_QUERY_FS_ATTRIBUTE_INFO);
150
151         if (!cli_send_trans(cli, SMBtrans2,
152                     NULL,
153                     0, 0,
154                     &setup, 1, 0,
155                     param, 2, 0,
156                     NULL, 0, 560)) {
157                 goto cleanup;
158         }
159
160         if (!cli_receive_trans(cli, SMBtrans2,
161                               &rparam, &rparam_count,
162                               &rdata, &rdata_count)) {
163                 goto cleanup;
164         }
165
166         if (cli_is_error(cli)) {
167                 ret = False;
168                 goto cleanup;
169         } else {
170                 ret = True;
171         }
172
173         if (rdata_count < 12) {
174                 goto cleanup;
175         }
176
177         *fs_attr = IVAL(rdata,0);
178
179         /* todo: but not yet needed
180          *       return the other stuff
181          */
182
183 cleanup:
184         SAFE_FREE(rparam);
185         SAFE_FREE(rdata);
186
187         return ret;
188 }
189
190 bool cli_get_fs_volume_info_old(struct cli_state *cli, fstring volume_name, uint32 *pserial_number)
191 {
192         bool ret = False;
193         uint16 setup;
194         char param[2];
195         char *rparam=NULL, *rdata=NULL;
196         unsigned int rparam_count=0, rdata_count=0;
197         unsigned char nlen;
198
199         setup = TRANSACT2_QFSINFO;
200
201         SSVAL(param,0,SMB_INFO_VOLUME);
202
203         if (!cli_send_trans(cli, SMBtrans2,
204                     NULL,
205                     0, 0,
206                     &setup, 1, 0,
207                     param, 2, 0,
208                     NULL, 0, 560)) {
209                 goto cleanup;
210         }
211
212         if (!cli_receive_trans(cli, SMBtrans2,
213                               &rparam, &rparam_count,
214                               &rdata, &rdata_count)) {
215                 goto cleanup;
216         }
217
218         if (cli_is_error(cli)) {
219                 ret = False;
220                 goto cleanup;
221         } else {
222                 ret = True;
223         }
224
225         if (rdata_count < 5) {
226                 goto cleanup;
227         }
228
229         if (pserial_number) {
230                 *pserial_number = IVAL(rdata,0);
231         }
232         nlen = CVAL(rdata,l2_vol_cch);
233         clistr_pull(cli->inbuf, volume_name, rdata + l2_vol_szVolLabel,
234                     sizeof(fstring), nlen, STR_NOALIGN);
235
236         /* todo: but not yet needed
237          *       return the other stuff
238          */
239
240 cleanup:
241         SAFE_FREE(rparam);
242         SAFE_FREE(rdata);
243
244         return ret;
245 }
246
247 bool cli_get_fs_volume_info(struct cli_state *cli, fstring volume_name, uint32 *pserial_number, time_t *pdate)
248 {
249         bool ret = False;
250         uint16 setup;
251         char param[2];
252         char *rparam=NULL, *rdata=NULL;
253         unsigned int rparam_count=0, rdata_count=0;
254         unsigned int nlen;
255
256         setup = TRANSACT2_QFSINFO;
257
258         SSVAL(param,0,SMB_QUERY_FS_VOLUME_INFO);
259
260         if (!cli_send_trans(cli, SMBtrans2,
261                     NULL,
262                     0, 0,
263                     &setup, 1, 0,
264                     param, 2, 0,
265                     NULL, 0, 560)) {
266                 goto cleanup;
267         }
268
269         if (!cli_receive_trans(cli, SMBtrans2,
270                               &rparam, &rparam_count,
271                               &rdata, &rdata_count)) {
272                 goto cleanup;
273         }
274
275         if (cli_is_error(cli)) {
276                 ret = False;
277                 goto cleanup;
278         } else {
279                 ret = True;
280         }
281
282         if (rdata_count < 19) {
283                 goto cleanup;
284         }
285
286         if (pdate) {
287                 struct timespec ts;
288                 ts = interpret_long_date(rdata);
289                 *pdate = ts.tv_sec;
290         }
291         if (pserial_number) {
292                 *pserial_number = IVAL(rdata,8);
293         }
294         nlen = IVAL(rdata,12);
295         clistr_pull(cli->inbuf, volume_name, rdata + 18, sizeof(fstring),
296                     nlen, STR_UNICODE);
297
298         /* todo: but not yet needed
299          *       return the other stuff
300          */
301
302 cleanup:
303         SAFE_FREE(rparam);
304         SAFE_FREE(rdata);
305
306         return ret;
307 }
308
309 bool cli_get_fs_full_size_info(struct cli_state *cli,
310                                uint64_t *total_allocation_units,
311                                uint64_t *caller_allocation_units,
312                                uint64_t *actual_allocation_units,
313                                uint64_t *sectors_per_allocation_unit,
314                                uint64_t *bytes_per_sector)
315 {
316         bool ret = False;
317         uint16 setup;
318         char param[2];
319         char *rparam=NULL, *rdata=NULL;
320         unsigned int rparam_count=0, rdata_count=0;
321
322         setup = TRANSACT2_QFSINFO;
323
324         SSVAL(param,0,SMB_FS_FULL_SIZE_INFORMATION);
325
326         if (!cli_send_trans(cli, SMBtrans2,
327                     NULL,
328                     0, 0,
329                     &setup, 1, 0,
330                     param, 2, 0,
331                     NULL, 0, 560)) {
332                 goto cleanup;
333         }
334
335         if (!cli_receive_trans(cli, SMBtrans2,
336                               &rparam, &rparam_count,
337                               &rdata, &rdata_count)) {
338                 goto cleanup;
339         }
340
341         if (cli_is_error(cli)) {
342                 ret = False;
343                 goto cleanup;
344         } else {
345                 ret = True;
346         }
347
348         if (rdata_count != 32) {
349                 goto cleanup;
350         }
351
352         if (total_allocation_units) {
353                 *total_allocation_units = BIG_UINT(rdata, 0);
354         }
355         if (caller_allocation_units) {
356                 *caller_allocation_units = BIG_UINT(rdata,8);
357         }
358         if (actual_allocation_units) {
359                 *actual_allocation_units = BIG_UINT(rdata,16);
360         }
361         if (sectors_per_allocation_unit) {
362                 *sectors_per_allocation_unit = IVAL(rdata,24);
363         }
364         if (bytes_per_sector) {
365                 *bytes_per_sector = IVAL(rdata,28);
366         }
367
368 cleanup:
369         SAFE_FREE(rparam);
370         SAFE_FREE(rdata);
371
372         return ret;
373 }
374
375 bool cli_get_posix_fs_info(struct cli_state *cli,
376                            uint32 *optimal_transfer_size,
377                            uint32 *block_size,
378                            uint64_t *total_blocks,
379                            uint64_t *blocks_available,
380                            uint64_t *user_blocks_available,
381                            uint64_t *total_file_nodes,
382                            uint64_t *free_file_nodes,
383                            uint64_t *fs_identifier)
384 {
385         bool ret = False;
386         uint16 setup;
387         char param[2];
388         char *rparam=NULL, *rdata=NULL;
389         unsigned int rparam_count=0, rdata_count=0;
390
391         setup = TRANSACT2_QFSINFO;
392
393         SSVAL(param,0,SMB_QUERY_POSIX_FS_INFO);
394
395         if (!cli_send_trans(cli, SMBtrans2,
396                     NULL,
397                     0, 0,
398                     &setup, 1, 0,
399                     param, 2, 0,
400                     NULL, 0, 560)) {
401                 goto cleanup;
402         }
403
404         if (!cli_receive_trans(cli, SMBtrans2,
405                               &rparam, &rparam_count,
406                               &rdata, &rdata_count)) {
407                 goto cleanup;
408         }
409
410         if (cli_is_error(cli)) {
411                 ret = False;
412                 goto cleanup;
413         } else {
414                 ret = True;
415         }
416
417         if (rdata_count != 56) {
418                 goto cleanup;
419         }
420
421         if (optimal_transfer_size) {
422                 *optimal_transfer_size = IVAL(rdata, 0);
423         }
424         if (block_size) {
425                 *block_size = IVAL(rdata,4);
426         }
427         if (total_blocks) {
428                 *total_blocks = BIG_UINT(rdata,8);
429         }
430         if (blocks_available) {
431                 *blocks_available = BIG_UINT(rdata,16);
432         }
433         if (user_blocks_available) {
434                 *user_blocks_available = BIG_UINT(rdata,24);
435         }
436         if (total_file_nodes) {
437                 *total_file_nodes = BIG_UINT(rdata,32);
438         }
439         if (free_file_nodes) {
440                 *free_file_nodes = BIG_UINT(rdata,40);
441         }
442         if (fs_identifier) {
443                 *fs_identifier = BIG_UINT(rdata,48);
444         }
445
446 cleanup:
447         SAFE_FREE(rparam);
448         SAFE_FREE(rdata);
449
450         return ret;
451 }
452
453
454 /******************************************************************************
455  Send/receive the request encryption blob.
456 ******************************************************************************/
457
458 static NTSTATUS enc_blob_send_receive(struct cli_state *cli, DATA_BLOB *in, DATA_BLOB *out, DATA_BLOB *param_out)
459 {
460         uint16 setup;
461         char param[4];
462         char *rparam=NULL, *rdata=NULL;
463         unsigned int rparam_count=0, rdata_count=0;
464         NTSTATUS status = NT_STATUS_OK;
465
466         setup = TRANSACT2_SETFSINFO;
467
468         SSVAL(param,0,0);
469         SSVAL(param,2,SMB_REQUEST_TRANSPORT_ENCRYPTION);
470
471         if (!cli_send_trans(cli, SMBtrans2,
472                                 NULL,
473                                 0, 0,
474                                 &setup, 1, 0,
475                                 param, 4, 0,
476                                 (char *)in->data, in->length, CLI_BUFFER_SIZE)) {
477                 status = cli_nt_error(cli);
478                 goto out;
479         }
480
481         if (!cli_receive_trans(cli, SMBtrans2,
482                                 &rparam, &rparam_count,
483                                 &rdata, &rdata_count)) {
484                 status = cli_nt_error(cli);
485                 goto out;
486         }
487
488         if (cli_is_error(cli)) {
489                 status = cli_nt_error(cli);
490                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
491                         goto out;
492                 }
493         }
494
495         *out = data_blob(rdata, rdata_count);
496         *param_out = data_blob(rparam, rparam_count);
497
498   out:
499
500         SAFE_FREE(rparam);
501         SAFE_FREE(rdata);
502         return status;
503 }
504
505 /******************************************************************************
506  Make a client state struct.
507 ******************************************************************************/
508
509 static struct smb_trans_enc_state *make_cli_enc_state(enum smb_trans_enc_type smb_enc_type)
510 {
511         struct smb_trans_enc_state *es = NULL;
512         es = SMB_MALLOC_P(struct smb_trans_enc_state);
513         if (!es) {
514                 return NULL;
515         }
516         ZERO_STRUCTP(es);
517         es->smb_enc_type = smb_enc_type;
518
519 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
520         if (smb_enc_type == SMB_TRANS_ENC_GSS) {
521                 es->s.gss_state = SMB_MALLOC_P(struct smb_tran_enc_state_gss);
522                 if (!es->s.gss_state) {
523                         SAFE_FREE(es);
524                         return NULL;
525                 }
526                 ZERO_STRUCTP(es->s.gss_state);
527         }
528 #endif
529         return es;
530 }
531
532 /******************************************************************************
533  Start a raw ntlmssp encryption.
534 ******************************************************************************/
535
536 NTSTATUS cli_raw_ntlm_smb_encryption_start(struct cli_state *cli, 
537                                 const char *user,
538                                 const char *pass,
539                                 const char *domain)
540 {
541         DATA_BLOB blob_in = data_blob_null;
542         DATA_BLOB blob_out = data_blob_null;
543         DATA_BLOB param_out = data_blob_null;
544         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
545         struct smb_trans_enc_state *es = make_cli_enc_state(SMB_TRANS_ENC_NTLM);
546
547         if (!es) {
548                 return NT_STATUS_NO_MEMORY;
549         }
550         status = ntlmssp_client_start(&es->s.ntlmssp_state);
551         if (!NT_STATUS_IS_OK(status)) {
552                 goto fail;
553         }
554
555         ntlmssp_want_feature(es->s.ntlmssp_state, NTLMSSP_FEATURE_SESSION_KEY);
556         es->s.ntlmssp_state->neg_flags |= (NTLMSSP_NEGOTIATE_SIGN|NTLMSSP_NEGOTIATE_SEAL);
557
558         if (!NT_STATUS_IS_OK(status = ntlmssp_set_username(es->s.ntlmssp_state, user))) {
559                 goto fail;
560         }
561         if (!NT_STATUS_IS_OK(status = ntlmssp_set_domain(es->s.ntlmssp_state, domain))) {
562                 goto fail;
563         }
564         if (!NT_STATUS_IS_OK(status = ntlmssp_set_password(es->s.ntlmssp_state, pass))) {
565                 goto fail;
566         }
567
568         do {
569                 status = ntlmssp_update(es->s.ntlmssp_state, blob_in, &blob_out);
570                 data_blob_free(&blob_in);
571                 data_blob_free(&param_out);
572                 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) || NT_STATUS_IS_OK(status)) {
573                         NTSTATUS trans_status = enc_blob_send_receive(cli,
574                                                                         &blob_out,
575                                                                         &blob_in,
576                                                                         &param_out);
577                         if (!NT_STATUS_EQUAL(trans_status,
578                                         NT_STATUS_MORE_PROCESSING_REQUIRED) &&
579                                         !NT_STATUS_IS_OK(trans_status)) {
580                                 status = trans_status;
581                         } else {
582                                 if (param_out.length == 2) {
583                                         es->enc_ctx_num = SVAL(param_out.data, 0);
584                                 }
585                         }
586                 }
587                 data_blob_free(&blob_out);
588         } while (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED));
589
590         data_blob_free(&blob_in);
591
592         if (NT_STATUS_IS_OK(status)) {
593                 /* Replace the old state, if any. */
594                 if (cli->trans_enc_state) {
595                         common_free_encryption_state(&cli->trans_enc_state);
596                 }
597                 cli->trans_enc_state = es;
598                 cli->trans_enc_state->enc_on = True;
599                 es = NULL;
600         }
601
602   fail:
603
604         common_free_encryption_state(&es);
605         return status;
606 }
607
608 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
609
610 #ifndef SMB_GSS_REQUIRED_FLAGS
611 #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)
612 #endif
613
614 /******************************************************************************
615  Get client gss blob to send to a server.
616 ******************************************************************************/
617
618 static NTSTATUS make_cli_gss_blob(struct smb_trans_enc_state *es,
619                                 const char *service,
620                                 const char *host,
621                                 NTSTATUS status_in,
622                                 DATA_BLOB spnego_blob_in,
623                                 DATA_BLOB *p_blob_out)
624 {
625         const char *krb_mechs[] = {OID_KERBEROS5, NULL};
626         OM_uint32 ret;
627         OM_uint32 min;
628         gss_name_t srv_name;
629         gss_buffer_desc input_name;
630         gss_buffer_desc *p_tok_in;
631         gss_buffer_desc tok_out, tok_in;
632         DATA_BLOB blob_out = data_blob_null;
633         DATA_BLOB blob_in = data_blob_null;
634         char *host_princ_s = NULL;
635         OM_uint32 ret_flags = 0;
636         NTSTATUS status = NT_STATUS_OK;
637
638         gss_OID_desc nt_hostbased_service =
639         {10, CONST_DISCARD(char *,"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04")};
640
641         memset(&tok_out, '\0', sizeof(tok_out));
642
643         /* Get a ticket for the service@host */
644         if (asprintf(&host_princ_s, "%s@%s", service, host) == -1) {
645                 return NT_STATUS_NO_MEMORY;
646         }
647
648         input_name.value = host_princ_s;
649         input_name.length = strlen(host_princ_s) + 1;
650
651         ret = gss_import_name(&min,
652                                 &input_name,
653                                 &nt_hostbased_service,
654                                 &srv_name);
655
656         if (ret != GSS_S_COMPLETE) {
657                 SAFE_FREE(host_princ_s);
658                 return map_nt_error_from_gss(ret, min);
659         }
660
661         if (spnego_blob_in.length == 0) {
662                 p_tok_in = GSS_C_NO_BUFFER;
663         } else {
664                 /* Remove the SPNEGO wrapper */
665                 if (!spnego_parse_auth_response(spnego_blob_in, status_in, OID_KERBEROS5, &blob_in)) {
666                         status = NT_STATUS_UNSUCCESSFUL;
667                         goto fail;
668                 }
669                 tok_in.value = blob_in.data;
670                 tok_in.length = blob_in.length;
671                 p_tok_in = &tok_in;
672         }
673
674         ret = gss_init_sec_context(&min,
675                                 GSS_C_NO_CREDENTIAL, /* Use our default cred. */
676                                 &es->s.gss_state->gss_ctx,
677                                 srv_name,
678                                 GSS_C_NO_OID, /* default OID. */
679                                 GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG,
680                                 GSS_C_INDEFINITE,       /* requested ticket lifetime. */
681                                 NULL,   /* no channel bindings */
682                                 p_tok_in,
683                                 NULL,   /* ignore mech type */
684                                 &tok_out,
685                                 &ret_flags,
686                                 NULL);  /* ignore time_rec */
687
688         status = map_nt_error_from_gss(ret, min);
689         if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED)) {
690                 ADS_STATUS adss = ADS_ERROR_GSS(ret, min);
691                 DEBUG(10,("make_cli_gss_blob: gss_init_sec_context failed with %s\n",
692                         ads_errstr(adss)));
693                 goto fail;
694         }
695
696         if ((ret_flags & SMB_GSS_REQUIRED_FLAGS) != SMB_GSS_REQUIRED_FLAGS) {
697                 status = NT_STATUS_ACCESS_DENIED;
698         }
699
700         blob_out = data_blob(tok_out.value, tok_out.length);
701
702         /* Wrap in an SPNEGO wrapper */
703         *p_blob_out = gen_negTokenTarg(krb_mechs, blob_out);
704
705   fail:
706
707         data_blob_free(&blob_out);
708         data_blob_free(&blob_in);
709         SAFE_FREE(host_princ_s);
710         gss_release_name(&min, &srv_name);
711         if (tok_out.value) {
712                 gss_release_buffer(&min, &tok_out);
713         }
714         return status;
715 }
716
717 /******************************************************************************
718  Start a SPNEGO gssapi encryption context.
719 ******************************************************************************/
720
721 NTSTATUS cli_gss_smb_encryption_start(struct cli_state *cli)
722 {
723         DATA_BLOB blob_recv = data_blob_null;
724         DATA_BLOB blob_send = data_blob_null;
725         DATA_BLOB param_out = data_blob_null;
726         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
727         fstring fqdn;
728         const char *servicename;
729         struct smb_trans_enc_state *es = make_cli_enc_state(SMB_TRANS_ENC_GSS);
730
731         if (!es) {
732                 return NT_STATUS_NO_MEMORY;
733         }
734
735         name_to_fqdn(fqdn, cli->desthost);
736         strlower_m(fqdn);
737
738         servicename = "cifs";
739         status = make_cli_gss_blob(es, servicename, fqdn, NT_STATUS_OK, blob_recv, &blob_send);
740         if (!NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED)) {
741                 servicename = "host";
742                 status = make_cli_gss_blob(es, servicename, fqdn, NT_STATUS_OK, blob_recv, &blob_send);
743                 if (!NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED)) {
744                         goto fail;
745                 }
746         }
747
748         do {
749                 data_blob_free(&blob_recv);
750                 status = enc_blob_send_receive(cli, &blob_send, &blob_recv, &param_out);
751                 if (param_out.length == 2) {
752                         es->enc_ctx_num = SVAL(param_out.data, 0);
753                 }
754                 data_blob_free(&blob_send);
755                 status = make_cli_gss_blob(es, servicename, fqdn, status, blob_recv, &blob_send);
756         } while (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED));
757         data_blob_free(&blob_recv);
758
759         if (NT_STATUS_IS_OK(status)) {
760                 /* Replace the old state, if any. */
761                 if (cli->trans_enc_state) {
762                         common_free_encryption_state(&cli->trans_enc_state);
763                 }
764                 cli->trans_enc_state = es;
765                 cli->trans_enc_state->enc_on = True;
766                 es = NULL;
767         }
768
769   fail:
770
771         common_free_encryption_state(&es);
772         return status;
773 }
774 #else
775 NTSTATUS cli_gss_smb_encryption_start(struct cli_state *cli)
776 {
777         return NT_STATUS_NOT_SUPPORTED;
778 }
779 #endif
780
781 /********************************************************************
782  Ensure a connection is encrypted.
783 ********************************************************************/
784
785 NTSTATUS cli_force_encryption(struct cli_state *c,
786                         const char *username,
787                         const char *password,
788                         const char *domain)
789 {
790         uint16 major, minor;
791         uint32 caplow, caphigh;
792
793         if (!SERVER_HAS_UNIX_CIFS(c)) {
794                 return NT_STATUS_NOT_SUPPORTED;
795         }
796
797         if (!cli_unix_extensions_version(c, &major, &minor, &caplow, &caphigh)) {
798                 return NT_STATUS_UNKNOWN_REVISION;
799         }
800
801         if (!(caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP)) {
802                 return NT_STATUS_UNSUPPORTED_COMPRESSION;
803         }
804
805         if (c->use_kerberos) {
806                 return cli_gss_smb_encryption_start(c);
807         }
808         return cli_raw_ntlm_smb_encryption_start(c,
809                                         username,
810                                         password,
811                                         domain);
812 }