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