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