Merge commit 'release-4-0-0alpha15' into master4-tmp
[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, fstring volume_name,
358                                 uint32 *pserial_number, time_t *pdate)
359 {
360         NTSTATUS status;
361         uint16 setup[1];
362         uint8_t param[2];
363         uint8_t *rdata;
364         uint32_t rdata_count;
365         unsigned int nlen;
366
367         SSVAL(setup, 0, TRANSACT2_QFSINFO);
368         SSVAL(param,0,SMB_QUERY_FS_VOLUME_INFO);
369
370         status = cli_trans(talloc_tos(), cli, SMBtrans2,
371                            NULL, 0, 0, 0,
372                            setup, 1, 0,
373                            param, 2, 0,
374                            NULL, 0, 560,
375                            NULL,
376                            NULL, 0, NULL,
377                            NULL, 0, NULL,
378                            &rdata, 10, &rdata_count);
379         if (!NT_STATUS_IS_OK(status)) {
380                 return status;
381         }
382
383         if (pdate) {
384                 struct timespec ts;
385                 ts = interpret_long_date((char *)rdata);
386                 *pdate = ts.tv_sec;
387         }
388         if (pserial_number) {
389                 *pserial_number = IVAL(rdata,8);
390         }
391         nlen = IVAL(rdata,12);
392         clistr_pull(cli->inbuf, volume_name, rdata + 18, sizeof(fstring),
393                     nlen, STR_UNICODE);
394
395         /* todo: but not yet needed
396          *       return the other stuff
397          */
398
399         TALLOC_FREE(rdata);
400         return NT_STATUS_OK;
401 }
402
403 NTSTATUS cli_get_fs_full_size_info(struct cli_state *cli,
404                                    uint64_t *total_allocation_units,
405                                    uint64_t *caller_allocation_units,
406                                    uint64_t *actual_allocation_units,
407                                    uint64_t *sectors_per_allocation_unit,
408                                    uint64_t *bytes_per_sector)
409 {
410         uint16 setup[1];
411         uint8_t param[2];
412         uint8_t *rdata = NULL;
413         uint32_t rdata_count;
414         NTSTATUS status;
415
416         SSVAL(setup, 0, TRANSACT2_QFSINFO);
417         SSVAL(param, 0, SMB_FS_FULL_SIZE_INFORMATION);
418
419         status = cli_trans(talloc_tos(), cli, SMBtrans2,
420                            NULL, 0, 0, 0,
421                            setup, 1, 0, /* setup */
422                            param, 2, 0,  /* param */
423                            NULL, 0, 560, /* data */
424                            NULL,
425                            NULL, 0, NULL, /* rsetup */
426                            NULL, 0, NULL, /* rparam */
427                            &rdata, 32, &rdata_count);  /* rdata */
428         if (!NT_STATUS_IS_OK(status)) {
429                 goto fail;
430         }
431
432         if (total_allocation_units) {
433                 *total_allocation_units = BIG_UINT(rdata, 0);
434         }
435         if (caller_allocation_units) {
436                 *caller_allocation_units = BIG_UINT(rdata,8);
437         }
438         if (actual_allocation_units) {
439                 *actual_allocation_units = BIG_UINT(rdata,16);
440         }
441         if (sectors_per_allocation_unit) {
442                 *sectors_per_allocation_unit = IVAL(rdata,24);
443         }
444         if (bytes_per_sector) {
445                 *bytes_per_sector = IVAL(rdata,28);
446         }
447
448 fail:
449         TALLOC_FREE(rdata);
450         return status;
451 }
452
453 NTSTATUS cli_get_posix_fs_info(struct cli_state *cli,
454                                uint32 *optimal_transfer_size,
455                                uint32 *block_size,
456                                uint64_t *total_blocks,
457                                uint64_t *blocks_available,
458                                uint64_t *user_blocks_available,
459                                uint64_t *total_file_nodes,
460                                uint64_t *free_file_nodes,
461                                uint64_t *fs_identifier)
462 {
463         uint16 setup[1];
464         uint8_t param[2];
465         uint8_t *rdata = NULL;
466         NTSTATUS status;
467
468         SSVAL(setup, 0, TRANSACT2_QFSINFO);
469         SSVAL(param,0,SMB_QUERY_POSIX_FS_INFO);
470
471         status = cli_trans(talloc_tos(), cli, SMBtrans2, NULL, 0, 0, 0,
472                            setup, 1, 0,
473                            param, 2, 0,
474                            NULL, 0, 560,
475                            NULL,
476                            NULL, 0, NULL, /* rsetup */
477                            NULL, 0, NULL, /* rparam */
478                            &rdata, 56, NULL);
479         if (!NT_STATUS_IS_OK(status)) {
480                 return status;
481         }
482
483         if (optimal_transfer_size) {
484                 *optimal_transfer_size = IVAL(rdata, 0);
485         }
486         if (block_size) {
487                 *block_size = IVAL(rdata,4);
488         }
489         if (total_blocks) {
490                 *total_blocks = BIG_UINT(rdata,8);
491         }
492         if (blocks_available) {
493                 *blocks_available = BIG_UINT(rdata,16);
494         }
495         if (user_blocks_available) {
496                 *user_blocks_available = BIG_UINT(rdata,24);
497         }
498         if (total_file_nodes) {
499                 *total_file_nodes = BIG_UINT(rdata,32);
500         }
501         if (free_file_nodes) {
502                 *free_file_nodes = BIG_UINT(rdata,40);
503         }
504         if (fs_identifier) {
505                 *fs_identifier = BIG_UINT(rdata,48);
506         }
507         return NT_STATUS_OK;
508 }
509
510
511 /******************************************************************************
512  Send/receive the request encryption blob.
513 ******************************************************************************/
514
515 static NTSTATUS enc_blob_send_receive(struct cli_state *cli, DATA_BLOB *in, DATA_BLOB *out, DATA_BLOB *param_out)
516 {
517         uint16_t setup[1];
518         uint8_t param[4];
519         uint8_t *rparam=NULL, *rdata=NULL;
520         uint32_t num_rparam, num_rdata;
521         NTSTATUS status;
522
523         SSVAL(setup+0, 0, TRANSACT2_SETFSINFO);
524         SSVAL(param,0,0);
525         SSVAL(param,2,SMB_REQUEST_TRANSPORT_ENCRYPTION);
526
527         status = cli_trans(talloc_tos(), cli, SMBtrans2, NULL, 0, 0, 0,
528                            setup, 1, 0,
529                            param, 4, 2,
530                            (uint8_t *)in->data, in->length, CLI_BUFFER_SIZE,
531                            NULL,          /* recv_flags */
532                            NULL, 0, NULL, /* rsetup */
533                            &rparam, 0, &num_rparam,
534                            &rdata, 0, &num_rdata);
535
536         if (!NT_STATUS_IS_OK(status) &&
537             !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
538                 return status;
539         }
540
541         *out = data_blob(rdata, num_rdata);
542         *param_out = data_blob(rparam, num_rparam);
543
544         TALLOC_FREE(rparam);
545         TALLOC_FREE(rdata);
546         return status;
547 }
548
549 /******************************************************************************
550  Make a client state struct.
551 ******************************************************************************/
552
553 static struct smb_trans_enc_state *make_cli_enc_state(enum smb_trans_enc_type smb_enc_type)
554 {
555         struct smb_trans_enc_state *es = NULL;
556         es = SMB_MALLOC_P(struct smb_trans_enc_state);
557         if (!es) {
558                 return NULL;
559         }
560         ZERO_STRUCTP(es);
561         es->smb_enc_type = smb_enc_type;
562
563 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
564         if (smb_enc_type == SMB_TRANS_ENC_GSS) {
565                 es->s.gss_state = SMB_MALLOC_P(struct smb_tran_enc_state_gss);
566                 if (!es->s.gss_state) {
567                         SAFE_FREE(es);
568                         return NULL;
569                 }
570                 ZERO_STRUCTP(es->s.gss_state);
571         }
572 #endif
573         return es;
574 }
575
576 /******************************************************************************
577  Start a raw ntlmssp encryption.
578 ******************************************************************************/
579
580 NTSTATUS cli_raw_ntlm_smb_encryption_start(struct cli_state *cli, 
581                                 const char *user,
582                                 const char *pass,
583                                 const char *domain)
584 {
585         DATA_BLOB blob_in = data_blob_null;
586         DATA_BLOB blob_out = data_blob_null;
587         DATA_BLOB param_out = data_blob_null;
588         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
589         struct smb_trans_enc_state *es = make_cli_enc_state(SMB_TRANS_ENC_NTLM);
590
591         if (!es) {
592                 return NT_STATUS_NO_MEMORY;
593         }
594         status = ntlmssp_client_start(NULL,
595                                       lp_netbios_name(),
596                                       lp_workgroup(),
597                                       lp_client_ntlmv2_auth(),
598                                       &es->s.ntlmssp_state);
599         if (!NT_STATUS_IS_OK(status)) {
600                 goto fail;
601         }
602
603         ntlmssp_want_feature(es->s.ntlmssp_state, NTLMSSP_FEATURE_SESSION_KEY);
604         es->s.ntlmssp_state->neg_flags |= (NTLMSSP_NEGOTIATE_SIGN|NTLMSSP_NEGOTIATE_SEAL);
605
606         if (!NT_STATUS_IS_OK(status = ntlmssp_set_username(es->s.ntlmssp_state, user))) {
607                 goto fail;
608         }
609         if (!NT_STATUS_IS_OK(status = ntlmssp_set_domain(es->s.ntlmssp_state, domain))) {
610                 goto fail;
611         }
612         if (!NT_STATUS_IS_OK(status = ntlmssp_set_password(es->s.ntlmssp_state, pass))) {
613                 goto fail;
614         }
615
616         do {
617                 status = ntlmssp_update(es->s.ntlmssp_state, blob_in, &blob_out);
618                 data_blob_free(&blob_in);
619                 data_blob_free(&param_out);
620                 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) || NT_STATUS_IS_OK(status)) {
621                         NTSTATUS trans_status = enc_blob_send_receive(cli,
622                                                                         &blob_out,
623                                                                         &blob_in,
624                                                                         &param_out);
625                         if (!NT_STATUS_EQUAL(trans_status,
626                                         NT_STATUS_MORE_PROCESSING_REQUIRED) &&
627                                         !NT_STATUS_IS_OK(trans_status)) {
628                                 status = trans_status;
629                         } else {
630                                 if (param_out.length == 2) {
631                                         es->enc_ctx_num = SVAL(param_out.data, 0);
632                                 }
633                         }
634                 }
635                 data_blob_free(&blob_out);
636         } while (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED));
637
638         data_blob_free(&blob_in);
639
640         if (NT_STATUS_IS_OK(status)) {
641                 /* Replace the old state, if any. */
642                 if (cli->trans_enc_state) {
643                         common_free_encryption_state(&cli->trans_enc_state);
644                 }
645                 cli->trans_enc_state = es;
646                 cli->trans_enc_state->enc_on = True;
647                 es = NULL;
648         }
649
650   fail:
651
652         common_free_encryption_state(&es);
653         return status;
654 }
655
656 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
657
658 #ifndef SMB_GSS_REQUIRED_FLAGS
659 #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)
660 #endif
661
662 /******************************************************************************
663  Get client gss blob to send to a server.
664 ******************************************************************************/
665
666 static NTSTATUS make_cli_gss_blob(TALLOC_CTX *ctx,
667                                 struct smb_trans_enc_state *es,
668                                 const char *service,
669                                 const char *host,
670                                 NTSTATUS status_in,
671                                 DATA_BLOB spnego_blob_in,
672                                 DATA_BLOB *p_blob_out)
673 {
674         const char *krb_mechs[] = {OID_KERBEROS5, NULL};
675         OM_uint32 ret;
676         OM_uint32 min;
677         gss_name_t srv_name;
678         gss_buffer_desc input_name;
679         gss_buffer_desc *p_tok_in;
680         gss_buffer_desc tok_out, tok_in;
681         DATA_BLOB blob_out = data_blob_null;
682         DATA_BLOB blob_in = data_blob_null;
683         char *host_princ_s = NULL;
684         OM_uint32 ret_flags = 0;
685         NTSTATUS status = NT_STATUS_OK;
686
687         gss_OID_desc nt_hostbased_service =
688         {10, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04")};
689
690         memset(&tok_out, '\0', sizeof(tok_out));
691
692         /* Get a ticket for the service@host */
693         if (asprintf(&host_princ_s, "%s@%s", service, host) == -1) {
694                 return NT_STATUS_NO_MEMORY;
695         }
696
697         input_name.value = host_princ_s;
698         input_name.length = strlen(host_princ_s) + 1;
699
700         ret = gss_import_name(&min,
701                                 &input_name,
702                                 &nt_hostbased_service,
703                                 &srv_name);
704
705         if (ret != GSS_S_COMPLETE) {
706                 SAFE_FREE(host_princ_s);
707                 return map_nt_error_from_gss(ret, min);
708         }
709
710         if (spnego_blob_in.length == 0) {
711                 p_tok_in = GSS_C_NO_BUFFER;
712         } else {
713                 /* Remove the SPNEGO wrapper */
714                 if (!spnego_parse_auth_response(ctx, spnego_blob_in, status_in, OID_KERBEROS5, &blob_in)) {
715                         status = NT_STATUS_UNSUCCESSFUL;
716                         goto fail;
717                 }
718                 tok_in.value = blob_in.data;
719                 tok_in.length = blob_in.length;
720                 p_tok_in = &tok_in;
721         }
722
723         ret = gss_init_sec_context(&min,
724                                 GSS_C_NO_CREDENTIAL, /* Use our default cred. */
725                                 &es->s.gss_state->gss_ctx,
726                                 srv_name,
727                                 GSS_C_NO_OID, /* default OID. */
728                                 GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG,
729                                 GSS_C_INDEFINITE,       /* requested ticket lifetime. */
730                                 NULL,   /* no channel bindings */
731                                 p_tok_in,
732                                 NULL,   /* ignore mech type */
733                                 &tok_out,
734                                 &ret_flags,
735                                 NULL);  /* ignore time_rec */
736
737         status = map_nt_error_from_gss(ret, min);
738         if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED)) {
739                 ADS_STATUS adss = ADS_ERROR_GSS(ret, min);
740                 DEBUG(10,("make_cli_gss_blob: gss_init_sec_context failed with %s\n",
741                         ads_errstr(adss)));
742                 goto fail;
743         }
744
745         if ((ret_flags & SMB_GSS_REQUIRED_FLAGS) != SMB_GSS_REQUIRED_FLAGS) {
746                 status = NT_STATUS_ACCESS_DENIED;
747         }
748
749         blob_out = data_blob_talloc(ctx, tok_out.value, tok_out.length);
750
751         /* Wrap in an SPNEGO wrapper */
752         *p_blob_out = spnego_gen_negTokenInit(ctx, krb_mechs, &blob_out, NULL);
753
754   fail:
755
756         data_blob_free(&blob_out);
757         data_blob_free(&blob_in);
758         SAFE_FREE(host_princ_s);
759         gss_release_name(&min, &srv_name);
760         if (tok_out.value) {
761                 gss_release_buffer(&min, &tok_out);
762         }
763         return status;
764 }
765
766 /******************************************************************************
767  Start a SPNEGO gssapi encryption context.
768 ******************************************************************************/
769
770 NTSTATUS cli_gss_smb_encryption_start(struct cli_state *cli)
771 {
772         DATA_BLOB blob_recv = data_blob_null;
773         DATA_BLOB blob_send = data_blob_null;
774         DATA_BLOB param_out = data_blob_null;
775         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
776         fstring fqdn;
777         const char *servicename;
778         struct smb_trans_enc_state *es = make_cli_enc_state(SMB_TRANS_ENC_GSS);
779
780         if (!es) {
781                 return NT_STATUS_NO_MEMORY;
782         }
783
784         name_to_fqdn(fqdn, cli->desthost);
785         strlower_m(fqdn);
786
787         servicename = "cifs";
788         status = make_cli_gss_blob(talloc_tos(), es, servicename, fqdn, NT_STATUS_OK, blob_recv, &blob_send);
789         if (!NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED)) {
790                 servicename = "host";
791                 status = make_cli_gss_blob(talloc_tos(), es, servicename, fqdn, NT_STATUS_OK, blob_recv, &blob_send);
792                 if (!NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED)) {
793                         goto fail;
794                 }
795         }
796
797         do {
798                 data_blob_free(&blob_recv);
799                 status = enc_blob_send_receive(cli, &blob_send, &blob_recv, &param_out);
800                 if (param_out.length == 2) {
801                         es->enc_ctx_num = SVAL(param_out.data, 0);
802                 }
803                 data_blob_free(&blob_send);
804                 status = make_cli_gss_blob(talloc_tos(), es, servicename, fqdn, status, blob_recv, &blob_send);
805         } while (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED));
806         data_blob_free(&blob_recv);
807
808         if (NT_STATUS_IS_OK(status)) {
809                 /* Replace the old state, if any. */
810                 if (cli->trans_enc_state) {
811                         common_free_encryption_state(&cli->trans_enc_state);
812                 }
813                 cli->trans_enc_state = es;
814                 cli->trans_enc_state->enc_on = True;
815                 es = NULL;
816         }
817
818   fail:
819
820         common_free_encryption_state(&es);
821         return status;
822 }
823 #else
824 NTSTATUS cli_gss_smb_encryption_start(struct cli_state *cli)
825 {
826         return NT_STATUS_NOT_SUPPORTED;
827 }
828 #endif
829
830 /********************************************************************
831  Ensure a connection is encrypted.
832 ********************************************************************/
833
834 NTSTATUS cli_force_encryption(struct cli_state *c,
835                         const char *username,
836                         const char *password,
837                         const char *domain)
838 {
839         uint16 major, minor;
840         uint32 caplow, caphigh;
841         NTSTATUS status;
842
843         if (!SERVER_HAS_UNIX_CIFS(c)) {
844                 return NT_STATUS_NOT_SUPPORTED;
845         }
846
847         status = cli_unix_extensions_version(c, &major, &minor, &caplow,
848                                              &caphigh);
849         if (!NT_STATUS_IS_OK(status)) {
850                 DEBUG(10, ("cli_force_encryption: cli_unix_extensions_version "
851                            "returned %s\n", nt_errstr(status)));
852                 return NT_STATUS_UNKNOWN_REVISION;
853         }
854
855         if (!(caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP)) {
856                 return NT_STATUS_UNSUPPORTED_COMPRESSION;
857         }
858
859         if (c->use_kerberos) {
860                 return cli_gss_smb_encryption_start(c);
861         }
862         return cli_raw_ntlm_smb_encryption_start(c,
863                                         username,
864                                         password,
865                                         domain);
866 }