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