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