s3:libsmb/clifsinfo: make use of cli_state_remote_name()
[metze/samba/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 "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         NTSTATUS status;
487
488         SSVAL(setup, 0, TRANSACT2_QFSINFO);
489         SSVAL(param,0,SMB_QUERY_POSIX_FS_INFO);
490
491         status = cli_trans(talloc_tos(), cli, SMBtrans2, NULL, 0, 0, 0,
492                            setup, 1, 0,
493                            param, 2, 0,
494                            NULL, 0, 560,
495                            NULL,
496                            NULL, 0, NULL, /* rsetup */
497                            NULL, 0, NULL, /* rparam */
498                            &rdata, 56, NULL);
499         if (!NT_STATUS_IS_OK(status)) {
500                 return status;
501         }
502
503         if (optimal_transfer_size) {
504                 *optimal_transfer_size = IVAL(rdata, 0);
505         }
506         if (block_size) {
507                 *block_size = IVAL(rdata,4);
508         }
509         if (total_blocks) {
510                 *total_blocks = BIG_UINT(rdata,8);
511         }
512         if (blocks_available) {
513                 *blocks_available = BIG_UINT(rdata,16);
514         }
515         if (user_blocks_available) {
516                 *user_blocks_available = BIG_UINT(rdata,24);
517         }
518         if (total_file_nodes) {
519                 *total_file_nodes = BIG_UINT(rdata,32);
520         }
521         if (free_file_nodes) {
522                 *free_file_nodes = BIG_UINT(rdata,40);
523         }
524         if (fs_identifier) {
525                 *fs_identifier = BIG_UINT(rdata,48);
526         }
527         return NT_STATUS_OK;
528 }
529
530
531 /******************************************************************************
532  Send/receive the request encryption blob.
533 ******************************************************************************/
534
535 static NTSTATUS enc_blob_send_receive(struct cli_state *cli, DATA_BLOB *in, DATA_BLOB *out, DATA_BLOB *param_out)
536 {
537         uint16_t setup[1];
538         uint8_t param[4];
539         uint8_t *rparam=NULL, *rdata=NULL;
540         uint32_t num_rparam, num_rdata;
541         NTSTATUS status;
542
543         SSVAL(setup+0, 0, TRANSACT2_SETFSINFO);
544         SSVAL(param,0,0);
545         SSVAL(param,2,SMB_REQUEST_TRANSPORT_ENCRYPTION);
546
547         status = cli_trans(talloc_tos(), cli, SMBtrans2, NULL, 0, 0, 0,
548                            setup, 1, 0,
549                            param, 4, 2,
550                            (uint8_t *)in->data, in->length, CLI_BUFFER_SIZE,
551                            NULL,          /* recv_flags */
552                            NULL, 0, NULL, /* rsetup */
553                            &rparam, 0, &num_rparam,
554                            &rdata, 0, &num_rdata);
555
556         if (!NT_STATUS_IS_OK(status) &&
557             !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
558                 return status;
559         }
560
561         *out = data_blob(rdata, num_rdata);
562         *param_out = data_blob(rparam, num_rparam);
563
564         TALLOC_FREE(rparam);
565         TALLOC_FREE(rdata);
566         return status;
567 }
568
569 /******************************************************************************
570  Make a client state struct.
571 ******************************************************************************/
572
573 static struct smb_trans_enc_state *make_cli_enc_state(enum smb_trans_enc_type smb_enc_type)
574 {
575         struct smb_trans_enc_state *es = NULL;
576         es = SMB_MALLOC_P(struct smb_trans_enc_state);
577         if (!es) {
578                 return NULL;
579         }
580         ZERO_STRUCTP(es);
581         es->smb_enc_type = smb_enc_type;
582
583 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
584         if (smb_enc_type == SMB_TRANS_ENC_GSS) {
585                 es->s.gss_state = SMB_MALLOC_P(struct smb_tran_enc_state_gss);
586                 if (!es->s.gss_state) {
587                         SAFE_FREE(es);
588                         return NULL;
589                 }
590                 ZERO_STRUCTP(es->s.gss_state);
591         }
592 #endif
593         return es;
594 }
595
596 /******************************************************************************
597  Start a raw ntlmssp encryption.
598 ******************************************************************************/
599
600 NTSTATUS cli_raw_ntlm_smb_encryption_start(struct cli_state *cli, 
601                                 const char *user,
602                                 const char *pass,
603                                 const char *domain)
604 {
605         DATA_BLOB blob_in = data_blob_null;
606         DATA_BLOB blob_out = data_blob_null;
607         DATA_BLOB param_out = data_blob_null;
608         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
609         struct smb_trans_enc_state *es = make_cli_enc_state(SMB_TRANS_ENC_NTLM);
610
611         if (!es) {
612                 return NT_STATUS_NO_MEMORY;
613         }
614         status = ntlmssp_client_start(NULL,
615                                       lp_netbios_name(),
616                                       lp_workgroup(),
617                                       lp_client_ntlmv2_auth(),
618                                       &es->s.ntlmssp_state);
619         if (!NT_STATUS_IS_OK(status)) {
620                 goto fail;
621         }
622
623         ntlmssp_want_feature(es->s.ntlmssp_state, NTLMSSP_FEATURE_SESSION_KEY);
624         es->s.ntlmssp_state->neg_flags |= (NTLMSSP_NEGOTIATE_SIGN|NTLMSSP_NEGOTIATE_SEAL);
625
626         if (!NT_STATUS_IS_OK(status = ntlmssp_set_username(es->s.ntlmssp_state, user))) {
627                 goto fail;
628         }
629         if (!NT_STATUS_IS_OK(status = ntlmssp_set_domain(es->s.ntlmssp_state, domain))) {
630                 goto fail;
631         }
632         if (!NT_STATUS_IS_OK(status = ntlmssp_set_password(es->s.ntlmssp_state, pass))) {
633                 goto fail;
634         }
635
636         do {
637                 status = ntlmssp_update(es->s.ntlmssp_state, blob_in, &blob_out);
638                 data_blob_free(&blob_in);
639                 data_blob_free(&param_out);
640                 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) || NT_STATUS_IS_OK(status)) {
641                         NTSTATUS trans_status = enc_blob_send_receive(cli,
642                                                                         &blob_out,
643                                                                         &blob_in,
644                                                                         &param_out);
645                         if (!NT_STATUS_EQUAL(trans_status,
646                                         NT_STATUS_MORE_PROCESSING_REQUIRED) &&
647                                         !NT_STATUS_IS_OK(trans_status)) {
648                                 status = trans_status;
649                         } else {
650                                 if (param_out.length == 2) {
651                                         es->enc_ctx_num = SVAL(param_out.data, 0);
652                                 }
653                         }
654                 }
655                 data_blob_free(&blob_out);
656         } while (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED));
657
658         data_blob_free(&blob_in);
659
660         if (NT_STATUS_IS_OK(status)) {
661                 /* Replace the old state, if any. */
662                 if (cli->trans_enc_state) {
663                         common_free_encryption_state(&cli->trans_enc_state);
664                 }
665                 cli->trans_enc_state = es;
666                 cli->trans_enc_state->enc_on = True;
667                 es = NULL;
668         }
669
670   fail:
671
672         common_free_encryption_state(&es);
673         return status;
674 }
675
676 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
677
678 #ifndef SMB_GSS_REQUIRED_FLAGS
679 #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)
680 #endif
681
682 /******************************************************************************
683  Get client gss blob to send to a server.
684 ******************************************************************************/
685
686 static NTSTATUS make_cli_gss_blob(TALLOC_CTX *ctx,
687                                 struct smb_trans_enc_state *es,
688                                 const char *service,
689                                 const char *host,
690                                 NTSTATUS status_in,
691                                 DATA_BLOB spnego_blob_in,
692                                 DATA_BLOB *p_blob_out)
693 {
694         const char *krb_mechs[] = {OID_KERBEROS5, NULL};
695         OM_uint32 ret;
696         OM_uint32 min;
697         gss_name_t srv_name;
698         gss_buffer_desc input_name;
699         gss_buffer_desc *p_tok_in;
700         gss_buffer_desc tok_out, tok_in;
701         DATA_BLOB blob_out = data_blob_null;
702         DATA_BLOB blob_in = data_blob_null;
703         char *host_princ_s = NULL;
704         OM_uint32 ret_flags = 0;
705         NTSTATUS status = NT_STATUS_OK;
706
707         gss_OID_desc nt_hostbased_service =
708         {10, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04")};
709
710         memset(&tok_out, '\0', sizeof(tok_out));
711
712         /* Get a ticket for the service@host */
713         if (asprintf(&host_princ_s, "%s@%s", service, host) == -1) {
714                 return NT_STATUS_NO_MEMORY;
715         }
716
717         input_name.value = host_princ_s;
718         input_name.length = strlen(host_princ_s) + 1;
719
720         ret = gss_import_name(&min,
721                                 &input_name,
722                                 &nt_hostbased_service,
723                                 &srv_name);
724
725         if (ret != GSS_S_COMPLETE) {
726                 SAFE_FREE(host_princ_s);
727                 return map_nt_error_from_gss(ret, min);
728         }
729
730         if (spnego_blob_in.length == 0) {
731                 p_tok_in = GSS_C_NO_BUFFER;
732         } else {
733                 /* Remove the SPNEGO wrapper */
734                 if (!spnego_parse_auth_response(ctx, spnego_blob_in, status_in, OID_KERBEROS5, &blob_in)) {
735                         status = NT_STATUS_UNSUCCESSFUL;
736                         goto fail;
737                 }
738                 tok_in.value = blob_in.data;
739                 tok_in.length = blob_in.length;
740                 p_tok_in = &tok_in;
741         }
742
743         ret = gss_init_sec_context(&min,
744                                 GSS_C_NO_CREDENTIAL, /* Use our default cred. */
745                                 &es->s.gss_state->gss_ctx,
746                                 srv_name,
747                                 GSS_C_NO_OID, /* default OID. */
748                                 GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG,
749                                 GSS_C_INDEFINITE,       /* requested ticket lifetime. */
750                                 NULL,   /* no channel bindings */
751                                 p_tok_in,
752                                 NULL,   /* ignore mech type */
753                                 &tok_out,
754                                 &ret_flags,
755                                 NULL);  /* ignore time_rec */
756
757         status = map_nt_error_from_gss(ret, min);
758         if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED)) {
759                 ADS_STATUS adss = ADS_ERROR_GSS(ret, min);
760                 DEBUG(10,("make_cli_gss_blob: gss_init_sec_context failed with %s\n",
761                         ads_errstr(adss)));
762                 goto fail;
763         }
764
765         if ((ret_flags & SMB_GSS_REQUIRED_FLAGS) != SMB_GSS_REQUIRED_FLAGS) {
766                 status = NT_STATUS_ACCESS_DENIED;
767         }
768
769         blob_out = data_blob_talloc(ctx, tok_out.value, tok_out.length);
770
771         /* Wrap in an SPNEGO wrapper */
772         *p_blob_out = spnego_gen_negTokenInit(ctx, krb_mechs, &blob_out, NULL);
773
774   fail:
775
776         data_blob_free(&blob_out);
777         data_blob_free(&blob_in);
778         SAFE_FREE(host_princ_s);
779         gss_release_name(&min, &srv_name);
780         if (tok_out.value) {
781                 gss_release_buffer(&min, &tok_out);
782         }
783         return status;
784 }
785
786 /******************************************************************************
787  Start a SPNEGO gssapi encryption context.
788 ******************************************************************************/
789
790 NTSTATUS cli_gss_smb_encryption_start(struct cli_state *cli)
791 {
792         DATA_BLOB blob_recv = data_blob_null;
793         DATA_BLOB blob_send = data_blob_null;
794         DATA_BLOB param_out = data_blob_null;
795         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
796         fstring fqdn;
797         const char *servicename;
798         struct smb_trans_enc_state *es = make_cli_enc_state(SMB_TRANS_ENC_GSS);
799
800         if (!es) {
801                 return NT_STATUS_NO_MEMORY;
802         }
803
804         name_to_fqdn(fqdn, cli_state_remote_name(cli));
805         strlower_m(fqdn);
806
807         servicename = "cifs";
808         status = make_cli_gss_blob(talloc_tos(), es, servicename, fqdn, NT_STATUS_OK, blob_recv, &blob_send);
809         if (!NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED)) {
810                 servicename = "host";
811                 status = make_cli_gss_blob(talloc_tos(), es, servicename, fqdn, NT_STATUS_OK, blob_recv, &blob_send);
812                 if (!NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED)) {
813                         goto fail;
814                 }
815         }
816
817         do {
818                 data_blob_free(&blob_recv);
819                 status = enc_blob_send_receive(cli, &blob_send, &blob_recv, &param_out);
820                 if (param_out.length == 2) {
821                         es->enc_ctx_num = SVAL(param_out.data, 0);
822                 }
823                 data_blob_free(&blob_send);
824                 status = make_cli_gss_blob(talloc_tos(), es, servicename, fqdn, status, blob_recv, &blob_send);
825         } while (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED));
826         data_blob_free(&blob_recv);
827
828         if (NT_STATUS_IS_OK(status)) {
829                 /* Replace the old state, if any. */
830                 if (cli->trans_enc_state) {
831                         common_free_encryption_state(&cli->trans_enc_state);
832                 }
833                 cli->trans_enc_state = es;
834                 cli->trans_enc_state->enc_on = True;
835                 es = NULL;
836         }
837
838   fail:
839
840         common_free_encryption_state(&es);
841         return status;
842 }
843 #else
844 NTSTATUS cli_gss_smb_encryption_start(struct cli_state *cli)
845 {
846         return NT_STATUS_NOT_SUPPORTED;
847 }
848 #endif
849
850 /********************************************************************
851  Ensure a connection is encrypted.
852 ********************************************************************/
853
854 NTSTATUS cli_force_encryption(struct cli_state *c,
855                         const char *username,
856                         const char *password,
857                         const char *domain)
858 {
859         uint16 major, minor;
860         uint32 caplow, caphigh;
861         NTSTATUS status;
862
863         if (!SERVER_HAS_UNIX_CIFS(c)) {
864                 return NT_STATUS_NOT_SUPPORTED;
865         }
866
867         status = cli_unix_extensions_version(c, &major, &minor, &caplow,
868                                              &caphigh);
869         if (!NT_STATUS_IS_OK(status)) {
870                 DEBUG(10, ("cli_force_encryption: cli_unix_extensions_version "
871                            "returned %s\n", nt_errstr(status)));
872                 return NT_STATUS_UNKNOWN_REVISION;
873         }
874
875         if (!(caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP)) {
876                 return NT_STATUS_UNSUPPORTED_COMPRESSION;
877         }
878
879         if (c->use_kerberos) {
880                 return cli_gss_smb_encryption_start(c);
881         }
882         return cli_raw_ntlm_smb_encryption_start(c,
883                                         username,
884                                         password,
885                                         domain);
886 }