r23779: Change from v2 or later to v3 or later.
[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, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 /****************************************************************************
25  Get UNIX extensions version info.
26 ****************************************************************************/
27                                                                                                                    
28 BOOL cli_unix_extensions_version(struct cli_state *cli, uint16 *pmajor, uint16 *pminor,
29                                         uint32 *pcaplow, uint32 *pcaphigh)
30 {
31         BOOL ret = False;
32         uint16 setup;
33         char param[2];
34         char *rparam=NULL, *rdata=NULL;
35         unsigned int rparam_count=0, rdata_count=0;
36
37         setup = TRANSACT2_QFSINFO;
38         
39         SSVAL(param,0,SMB_QUERY_CIFS_UNIX_INFO);
40
41         if (!cli_send_trans(cli, SMBtrans2, 
42                     NULL, 
43                     0, 0,
44                     &setup, 1, 0,
45                     param, 2, 0,
46                     NULL, 0, 560)) {
47                 goto cleanup;
48         }
49         
50         if (!cli_receive_trans(cli, SMBtrans2,
51                               &rparam, &rparam_count,
52                               &rdata, &rdata_count)) {
53                 goto cleanup;
54         }
55
56         if (cli_is_error(cli)) {
57                 ret = False;
58                 goto cleanup;
59         } else {
60                 ret = True;
61         }
62
63         if (rdata_count < 12) {
64                 goto cleanup;
65         }
66
67         *pmajor = SVAL(rdata,0);
68         *pminor = SVAL(rdata,2);
69         cli->posix_capabilities = *pcaplow = IVAL(rdata,4);
70         *pcaphigh = IVAL(rdata,8);
71
72         /* todo: but not yet needed 
73          *       return the other stuff
74          */
75
76 cleanup:
77         SAFE_FREE(rparam);
78         SAFE_FREE(rdata);
79
80         return ret;     
81 }
82
83 /****************************************************************************
84  Set UNIX extensions capabilities.
85 ****************************************************************************/
86                                                                                                                    
87 BOOL cli_set_unix_extensions_capabilities(struct cli_state *cli, uint16 major, uint16 minor,
88                                         uint32 caplow, uint32 caphigh)
89 {
90         BOOL ret = False;
91         uint16 setup;
92         char param[4];
93         char data[12];
94         char *rparam=NULL, *rdata=NULL;
95         unsigned int rparam_count=0, rdata_count=0;
96
97         setup = TRANSACT2_SETFSINFO;
98         
99         SSVAL(param,0,0);
100         SSVAL(param,2,SMB_SET_CIFS_UNIX_INFO);
101
102         SSVAL(data,0,major);
103         SSVAL(data,2,minor);
104         SIVAL(data,4,caplow);
105         SIVAL(data,8,caphigh);
106
107         if (!cli_send_trans(cli, SMBtrans2, 
108                     NULL, 
109                     0, 0,
110                     &setup, 1, 0,
111                     param, 4, 0,
112                     data, 12, 560)) {
113                 goto cleanup;
114         }
115         
116         if (!cli_receive_trans(cli, SMBtrans2,
117                               &rparam, &rparam_count,
118                               &rdata, &rdata_count)) {
119                 goto cleanup;
120         }
121
122         if (cli_is_error(cli)) {
123                 ret = False;
124                 goto cleanup;
125         } else {
126                 ret = True;
127         }
128
129 cleanup:
130         SAFE_FREE(rparam);
131         SAFE_FREE(rdata);
132
133         return ret;     
134 }
135
136 BOOL cli_get_fs_attr_info(struct cli_state *cli, uint32 *fs_attr)
137 {
138         BOOL ret = False;
139         uint16 setup;
140         char param[2];
141         char *rparam=NULL, *rdata=NULL;
142         unsigned int rparam_count=0, rdata_count=0;
143
144         if (!cli||!fs_attr)
145                 smb_panic("cli_get_fs_attr_info() called with NULL Pionter!");
146
147         setup = TRANSACT2_QFSINFO;
148         
149         SSVAL(param,0,SMB_QUERY_FS_ATTRIBUTE_INFO);
150
151         if (!cli_send_trans(cli, SMBtrans2, 
152                     NULL, 
153                     0, 0,
154                     &setup, 1, 0,
155                     param, 2, 0,
156                     NULL, 0, 560)) {
157                 goto cleanup;
158         }
159         
160         if (!cli_receive_trans(cli, SMBtrans2,
161                               &rparam, &rparam_count,
162                               &rdata, &rdata_count)) {
163                 goto cleanup;
164         }
165
166         if (cli_is_error(cli)) {
167                 ret = False;
168                 goto cleanup;
169         } else {
170                 ret = True;
171         }
172
173         if (rdata_count < 12) {
174                 goto cleanup;
175         }
176
177         *fs_attr = IVAL(rdata,0);
178
179         /* todo: but not yet needed 
180          *       return the other stuff
181          */
182
183 cleanup:
184         SAFE_FREE(rparam);
185         SAFE_FREE(rdata);
186
187         return ret;     
188 }
189
190 BOOL cli_get_fs_volume_info_old(struct cli_state *cli, fstring volume_name, uint32 *pserial_number)
191 {
192         BOOL ret = False;
193         uint16 setup;
194         char param[2];
195         char *rparam=NULL, *rdata=NULL;
196         unsigned int rparam_count=0, rdata_count=0;
197         unsigned char nlen;
198
199         setup = TRANSACT2_QFSINFO;
200         
201         SSVAL(param,0,SMB_INFO_VOLUME);
202
203         if (!cli_send_trans(cli, SMBtrans2, 
204                     NULL, 
205                     0, 0,
206                     &setup, 1, 0,
207                     param, 2, 0,
208                     NULL, 0, 560)) {
209                 goto cleanup;
210         }
211         
212         if (!cli_receive_trans(cli, SMBtrans2,
213                               &rparam, &rparam_count,
214                               &rdata, &rdata_count)) {
215                 goto cleanup;
216         }
217
218         if (cli_is_error(cli)) {
219                 ret = False;
220                 goto cleanup;
221         } else {
222                 ret = True;
223         }
224
225         if (rdata_count < 5) {
226                 goto cleanup;
227         }
228
229         if (pserial_number) {
230                 *pserial_number = IVAL(rdata,0);
231         }
232         nlen = CVAL(rdata,l2_vol_cch);
233         clistr_pull(cli, volume_name, rdata + l2_vol_szVolLabel, sizeof(fstring), nlen, STR_NOALIGN);
234
235         /* todo: but not yet needed 
236          *       return the other stuff
237          */
238
239 cleanup:
240         SAFE_FREE(rparam);
241         SAFE_FREE(rdata);
242
243         return ret;     
244 }
245
246 BOOL cli_get_fs_volume_info(struct cli_state *cli, fstring volume_name, uint32 *pserial_number, time_t *pdate)
247 {
248         BOOL ret = False;
249         uint16 setup;
250         char param[2];
251         char *rparam=NULL, *rdata=NULL;
252         unsigned int rparam_count=0, rdata_count=0;
253         unsigned int nlen;
254
255         setup = TRANSACT2_QFSINFO;
256         
257         SSVAL(param,0,SMB_QUERY_FS_VOLUME_INFO);
258
259         if (!cli_send_trans(cli, SMBtrans2, 
260                     NULL, 
261                     0, 0,
262                     &setup, 1, 0,
263                     param, 2, 0,
264                     NULL, 0, 560)) {
265                 goto cleanup;
266         }
267         
268         if (!cli_receive_trans(cli, SMBtrans2,
269                               &rparam, &rparam_count,
270                               &rdata, &rdata_count)) {
271                 goto cleanup;
272         }
273
274         if (cli_is_error(cli)) {
275                 ret = False;
276                 goto cleanup;
277         } else {
278                 ret = True;
279         }
280
281         if (rdata_count < 19) {
282                 goto cleanup;
283         }
284
285         if (pdate) {
286                 struct timespec ts;
287                 ts = interpret_long_date(rdata);
288                 *pdate = ts.tv_sec;
289         }
290         if (pserial_number) {
291                 *pserial_number = IVAL(rdata,8);
292         }
293         nlen = IVAL(rdata,12);
294         clistr_pull(cli, volume_name, rdata + 18, sizeof(fstring), nlen, STR_UNICODE);
295
296         /* todo: but not yet needed 
297          *       return the other stuff
298          */
299
300 cleanup:
301         SAFE_FREE(rparam);
302         SAFE_FREE(rdata);
303
304         return ret;     
305 }
306
307 /******************************************************************************
308  Send/receive the request encryption blob.
309 ******************************************************************************/
310
311 static NTSTATUS enc_blob_send_receive(struct cli_state *cli, DATA_BLOB *in, DATA_BLOB *out, DATA_BLOB *param_out)
312 {
313         uint16 setup;
314         char param[4];
315         char *rparam=NULL, *rdata=NULL;
316         unsigned int rparam_count=0, rdata_count=0;
317         NTSTATUS status = NT_STATUS_OK;
318
319         setup = TRANSACT2_SETFSINFO;
320
321         SSVAL(param,0,0);
322         SSVAL(param,2,SMB_REQUEST_TRANSPORT_ENCRYPTION);
323
324         if (!cli_send_trans(cli, SMBtrans2,
325                                 NULL,
326                                 0, 0,
327                                 &setup, 1, 0,
328                                 param, 4, 0,
329                                 (char *)in->data, in->length, CLI_BUFFER_SIZE)) {
330                 status = cli_nt_error(cli);
331                 goto out;
332         }
333
334         if (!cli_receive_trans(cli, SMBtrans2,
335                                 &rparam, &rparam_count,
336                                 &rdata, &rdata_count)) {
337                 status = cli_nt_error(cli);
338                 goto out;
339         }
340
341         if (cli_is_error(cli)) {
342                 status = cli_nt_error(cli);
343                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
344                         goto out;
345                 }
346         }
347
348         *out = data_blob(rdata, rdata_count);
349         *param_out = data_blob(rparam, rparam_count);
350
351   out:
352
353         SAFE_FREE(rparam);
354         SAFE_FREE(rdata);
355         return status;
356 }
357
358 /******************************************************************************
359  Make a client state struct.
360 ******************************************************************************/
361
362 static struct smb_trans_enc_state *make_cli_enc_state(enum smb_trans_enc_type smb_enc_type)
363 {
364         struct smb_trans_enc_state *es = NULL;
365         es = SMB_MALLOC_P(struct smb_trans_enc_state);
366         if (!es) {
367                 return NULL;
368         }
369         ZERO_STRUCTP(es);
370         es->smb_enc_type = smb_enc_type;
371
372         if (smb_enc_type == SMB_TRANS_ENC_GSS) {
373 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
374                 es->s.gss_state = SMB_MALLOC_P(struct smb_tran_enc_state_gss);
375                 if (!es->s.gss_state) {
376                         SAFE_FREE(es);
377                         return NULL;
378                 }
379                 ZERO_STRUCTP(es->s.gss_state);
380 #else
381                 DEBUG(0,("make_cli_enc_state: no krb5 compiled.\n"));
382                 SAFE_FREE(es);
383                 return NULL;
384 #endif
385         }
386         return es;
387 }
388
389 /******************************************************************************
390  Start a raw ntlmssp encryption.
391 ******************************************************************************/
392
393 NTSTATUS cli_raw_ntlm_smb_encryption_start(struct cli_state *cli, 
394                                 const char *user,
395                                 const char *pass,
396                                 const char *domain)
397 {
398         DATA_BLOB blob_in = data_blob_null;
399         DATA_BLOB blob_out = data_blob_null;
400         DATA_BLOB param_out = data_blob_null;
401         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
402         struct smb_trans_enc_state *es = make_cli_enc_state(SMB_TRANS_ENC_NTLM);
403
404         if (!es) {
405                 return NT_STATUS_NO_MEMORY;
406         }
407         status = ntlmssp_client_start(&es->s.ntlmssp_state);
408         if (!NT_STATUS_IS_OK(status)) {
409                 goto fail;
410         }
411
412         ntlmssp_want_feature(es->s.ntlmssp_state, NTLMSSP_FEATURE_SESSION_KEY);
413         es->s.ntlmssp_state->neg_flags |= (NTLMSSP_NEGOTIATE_SIGN|NTLMSSP_NEGOTIATE_SEAL);
414
415         if (!NT_STATUS_IS_OK(status = ntlmssp_set_username(es->s.ntlmssp_state, user))) {
416                 goto fail;
417         }
418         if (!NT_STATUS_IS_OK(status = ntlmssp_set_domain(es->s.ntlmssp_state, domain))) {
419                 goto fail;
420         }
421         if (!NT_STATUS_IS_OK(status = ntlmssp_set_password(es->s.ntlmssp_state, pass))) {
422                 goto fail;
423         }
424
425         do {
426                 status = ntlmssp_update(es->s.ntlmssp_state, blob_in, &blob_out);
427                 data_blob_free(&blob_in);
428                 data_blob_free(&param_out);
429                 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) || NT_STATUS_IS_OK(status)) {
430                         status = enc_blob_send_receive(cli, &blob_out, &blob_in, &param_out);
431                 }
432                 if (param_out.length == 2) {
433                         es->enc_ctx_num = SVAL(param_out.data, 0);
434                 }
435                 data_blob_free(&blob_out);
436         } while (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED));
437
438         data_blob_free(&blob_in);
439
440         if (NT_STATUS_IS_OK(status)) {
441                 /* Replace the old state, if any. */
442                 if (cli->trans_enc_state) {
443                         common_free_encryption_state(&cli->trans_enc_state);
444                 }
445                 cli->trans_enc_state = es;
446                 cli->trans_enc_state->enc_on = True;
447                 es = NULL;
448         }
449
450   fail:
451
452         common_free_encryption_state(&es);
453         return status;
454 }
455
456 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
457
458 #ifndef SMB_GSS_REQUIRED_FLAGS
459 #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)
460 #endif
461
462 /******************************************************************************
463  Get client gss blob to send to a server.
464 ******************************************************************************/
465
466 static NTSTATUS make_cli_gss_blob(struct smb_trans_enc_state *es,
467                                 const char *service,
468                                 const char *host,
469                                 NTSTATUS status_in,
470                                 DATA_BLOB spnego_blob_in,
471                                 DATA_BLOB *p_blob_out)
472 {
473         const char *krb_mechs[] = {OID_KERBEROS5, NULL};
474         OM_uint32 ret;
475         OM_uint32 min;
476         gss_name_t srv_name;
477         gss_buffer_desc input_name;
478         gss_buffer_desc *p_tok_in;
479         gss_buffer_desc tok_out, tok_in;
480         DATA_BLOB blob_out = data_blob_null;
481         DATA_BLOB blob_in = data_blob_null;
482         char *host_princ_s = NULL;
483         OM_uint32 ret_flags = 0;
484         NTSTATUS status = NT_STATUS_OK;
485
486         gss_OID_desc nt_hostbased_service =
487         {10, CONST_DISCARD(char *,"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04")};
488
489         memset(&tok_out, '\0', sizeof(tok_out));
490
491         /* Get a ticket for the service@host */
492         asprintf(&host_princ_s, "%s@%s", service, host);
493         if (host_princ_s == NULL) {
494                 return NT_STATUS_NO_MEMORY;
495         }
496
497         input_name.value = host_princ_s;
498         input_name.length = strlen(host_princ_s) + 1;
499
500         ret = gss_import_name(&min,
501                                 &input_name,
502                                 &nt_hostbased_service,
503                                 &srv_name);
504
505         if (ret != GSS_S_COMPLETE) {
506                 SAFE_FREE(host_princ_s);
507                 return map_nt_error_from_gss(ret, min);
508         }
509
510         if (spnego_blob_in.length == 0) {
511                 p_tok_in = GSS_C_NO_BUFFER;
512         } else {
513                 /* Remove the SPNEGO wrapper */
514                 if (!spnego_parse_auth_response(spnego_blob_in, status_in, OID_KERBEROS5, &blob_in)) {
515                         status = NT_STATUS_UNSUCCESSFUL;
516                         goto fail;
517                 }
518                 tok_in.value = blob_in.data;
519                 tok_in.length = blob_in.length;
520                 p_tok_in = &tok_in;
521         }
522
523         ret = gss_init_sec_context(&min,
524                                 GSS_C_NO_CREDENTIAL, /* Use our default cred. */
525                                 &es->s.gss_state->gss_ctx,
526                                 srv_name,
527                                 GSS_C_NO_OID, /* default OID. */
528                                 GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG,
529                                 GSS_C_INDEFINITE,       /* requested ticket lifetime. */
530                                 NULL,   /* no channel bindings */
531                                 p_tok_in,
532                                 NULL,   /* ignore mech type */
533                                 &tok_out,
534                                 &ret_flags,
535                                 NULL);  /* ignore time_rec */
536
537         status = map_nt_error_from_gss(ret, min);
538         if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED)) {
539                 ADS_STATUS adss = ADS_ERROR_GSS(ret, min);
540                 DEBUG(10,("make_cli_gss_blob: gss_init_sec_context failed with %s\n",
541                         ads_errstr(adss)));
542                 goto fail;
543         }
544
545         if ((ret_flags & SMB_GSS_REQUIRED_FLAGS) != SMB_GSS_REQUIRED_FLAGS) {
546                 status = NT_STATUS_ACCESS_DENIED;
547         }
548
549         blob_out = data_blob(tok_out.value, tok_out.length);
550
551         /* Wrap in an SPNEGO wrapper */
552         *p_blob_out = gen_negTokenTarg(krb_mechs, blob_out);
553
554   fail:
555
556         data_blob_free(&blob_out);
557         data_blob_free(&blob_in);
558         SAFE_FREE(host_princ_s);
559         gss_release_name(&min, &srv_name);
560         if (tok_out.value) {
561                 gss_release_buffer(&min, &tok_out);
562         }
563         return status;
564 }
565
566 /******************************************************************************
567  Start a SPNEGO gssapi encryption context.
568 ******************************************************************************/
569
570 NTSTATUS cli_gss_smb_encryption_start(struct cli_state *cli)
571 {
572         DATA_BLOB blob_recv = data_blob_null;
573         DATA_BLOB blob_send = data_blob_null;
574         DATA_BLOB param_out = data_blob_null;
575         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
576         fstring fqdn;
577         const char *servicename;
578         struct smb_trans_enc_state *es = make_cli_enc_state(SMB_TRANS_ENC_GSS);
579
580         if (!es) {
581                 return NT_STATUS_NO_MEMORY;
582         }
583
584         name_to_fqdn(fqdn, cli->desthost);
585         strlower_m(fqdn);
586
587         servicename = "cifs";
588         status = make_cli_gss_blob(es, servicename, fqdn, NT_STATUS_OK, blob_recv, &blob_send);
589         if (!NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED)) {
590                 servicename = "host";
591                 status = make_cli_gss_blob(es, servicename, fqdn, NT_STATUS_OK, blob_recv, &blob_send);
592                 if (!NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED)) {
593                         goto fail;
594                 }
595         }
596
597         do {
598                 data_blob_free(&blob_recv);
599                 status = enc_blob_send_receive(cli, &blob_send, &blob_recv, &param_out);
600                 if (param_out.length == 2) {
601                         es->enc_ctx_num = SVAL(param_out.data, 0);
602                 }
603                 data_blob_free(&blob_send);
604                 status = make_cli_gss_blob(es, servicename, fqdn, status, blob_recv, &blob_send);
605         } while (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED));
606         data_blob_free(&blob_recv);
607
608         if (NT_STATUS_IS_OK(status)) {
609                 /* Replace the old state, if any. */
610                 if (cli->trans_enc_state) {
611                         common_free_encryption_state(&cli->trans_enc_state);
612                 }
613                 cli->trans_enc_state = es;
614                 cli->trans_enc_state->enc_on = True;
615                 es = NULL;
616         }
617
618   fail:
619
620         common_free_encryption_state(&es);
621         return status;
622 }
623 #else
624 NTSTATUS cli_gss_smb_encryption_start(struct cli_state *cli)
625 {
626         return NT_STATUS_NOT_SUPPORTED;
627 }
628 #endif