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