r6225: get rid of warnings from my compiler about nested externs
[obnox/samba/samba-obnox.git] / source / libsmb / cliconnect.c
1 /* 
2    Unix SMB/CIFS implementation.
3    client connect/disconnect routines
4    Copyright (C) Andrew Tridgell 1994-1998
5    Copyright (C) Andrew Bartlett 2001-2003
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 2 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 #define NO_SYSLOG
23
24 #include "includes.h"
25
26 extern pstring user_socket_options;
27
28 static const struct {
29         int prot;
30         const char *name;
31 } prots[] = {
32         {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"},
33         {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
34         {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
35         {PROTOCOL_LANMAN1,"LANMAN1.0"},
36         {PROTOCOL_LANMAN2,"LM1.2X002"},
37         {PROTOCOL_LANMAN2,"DOS LANMAN2.1"},
38         {PROTOCOL_LANMAN2,"Samba"},
39         {PROTOCOL_NT1,"NT LANMAN 1.0"},
40         {PROTOCOL_NT1,"NT LM 0.12"},
41         {-1,NULL}
42 };
43
44 /**
45  * Set the user session key for a connection
46  * @param cli The cli structure to add it too
47  * @param session_key The session key used.  (A copy of this is taken for the cli struct)
48  *
49  */
50
51 static void cli_set_session_key (struct cli_state *cli, const DATA_BLOB session_key) 
52 {
53         cli->user_session_key = data_blob(session_key.data, session_key.length);
54 }
55
56 /****************************************************************************
57  Do an old lanman2 style session setup.
58 ****************************************************************************/
59
60 static BOOL cli_session_setup_lanman2(struct cli_state *cli, const char *user, 
61                                       const char *pass, size_t passlen, const char *workgroup)
62 {
63         DATA_BLOB session_key = data_blob(NULL, 0);
64         DATA_BLOB lm_response = data_blob(NULL, 0);
65         fstring pword;
66         char *p;
67
68         if (passlen > sizeof(pword)-1)
69                 return False;
70
71         /* LANMAN servers predate NT status codes and Unicode and ignore those 
72            smb flags so we must disable the corresponding default capabilities  
73            that would otherwise cause the Unicode and NT Status flags to be
74            set (and even returned by the server) */
75
76         cli->capabilities &= ~(CAP_UNICODE | CAP_STATUS32);
77
78         /* if in share level security then don't send a password now */
79         if (!(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL))
80                 passlen = 0;
81
82         if (passlen > 0 && (cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen != 24) {
83                 /* Encrypted mode needed, and non encrypted password supplied. */
84                 lm_response = data_blob(NULL, 24);
85                 if (!SMBencrypt(pass, cli->secblob.data,(uchar *)lm_response.data)) {
86                         DEBUG(1, ("Password is > 14 chars in length, and is therefore incompatible with Lanman authentication\n"));
87                         return False;
88                 }
89         } else if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen == 24) {
90                 /* Encrypted mode needed, and encrypted password supplied. */
91                 lm_response = data_blob(pass, passlen);
92         } else if (passlen > 0) {
93                 /* Plaintext mode needed, assume plaintext supplied. */
94                 passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
95                 lm_response = data_blob(pass, passlen);
96         }
97
98         /* send a session setup command */
99         memset(cli->outbuf,'\0',smb_size);
100         set_message(cli->outbuf,10, 0, True);
101         SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
102         cli_setup_packet(cli);
103         
104         SCVAL(cli->outbuf,smb_vwv0,0xFF);
105         SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
106         SSVAL(cli->outbuf,smb_vwv3,2);
107         SSVAL(cli->outbuf,smb_vwv4,1);
108         SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
109         SSVAL(cli->outbuf,smb_vwv7,lm_response.length);
110
111         p = smb_buf(cli->outbuf);
112         memcpy(p,lm_response.data,lm_response.length);
113         p += lm_response.length;
114         p += clistr_push(cli, p, user, -1, STR_TERMINATE|STR_UPPER);
115         p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
116         p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
117         p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
118         cli_setup_bcc(cli, p);
119
120         cli_send_smb(cli);
121         if (!cli_receive_smb(cli))
122                 return False;
123
124         show_msg(cli->inbuf);
125
126         if (cli_is_error(cli))
127                 return False;
128         
129         /* use the returned vuid from now on */
130         cli->vuid = SVAL(cli->inbuf,smb_uid);   
131         fstrcpy(cli->user_name, user);
132
133         if (session_key.data) {
134                 /* Have plaintext orginal */
135                 cli_set_session_key(cli, session_key);
136         }
137
138         return True;
139 }
140
141 /****************************************************************************
142  Work out suitable capabilities to offer the server.
143 ****************************************************************************/
144
145 static uint32 cli_session_setup_capabilities(struct cli_state *cli)
146 {
147         uint32 capabilities = CAP_NT_SMBS;
148
149         if (!cli->force_dos_errors)
150                 capabilities |= CAP_STATUS32;
151
152         if (cli->use_level_II_oplocks)
153                 capabilities |= CAP_LEVEL_II_OPLOCKS;
154
155         capabilities |= (cli->capabilities & (CAP_UNICODE|CAP_LARGE_FILES|CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_DFS));
156         return capabilities;
157 }
158
159 /****************************************************************************
160  Do a NT1 guest session setup.
161 ****************************************************************************/
162
163 static BOOL cli_session_setup_guest(struct cli_state *cli)
164 {
165         char *p;
166         uint32 capabilities = cli_session_setup_capabilities(cli);
167
168         set_message(cli->outbuf,13,0,True);
169         SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
170         cli_setup_packet(cli);
171                         
172         SCVAL(cli->outbuf,smb_vwv0,0xFF);
173         SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
174         SSVAL(cli->outbuf,smb_vwv3,2);
175         SSVAL(cli->outbuf,smb_vwv4,cli->pid);
176         SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
177         SSVAL(cli->outbuf,smb_vwv7,0);
178         SSVAL(cli->outbuf,smb_vwv8,0);
179         SIVAL(cli->outbuf,smb_vwv11,capabilities); 
180         p = smb_buf(cli->outbuf);
181         p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* username */
182         p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* workgroup */
183         p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
184         p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
185         cli_setup_bcc(cli, p);
186
187         cli_send_smb(cli);
188         if (!cli_receive_smb(cli))
189               return False;
190         
191         show_msg(cli->inbuf);
192         
193         if (cli_is_error(cli))
194                 return False;
195
196         cli->vuid = SVAL(cli->inbuf,smb_uid);
197
198         p = smb_buf(cli->inbuf);
199         p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
200         p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
201         p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
202
203         fstrcpy(cli->user_name, "");
204
205         return True;
206 }
207
208 /****************************************************************************
209  Do a NT1 plaintext session setup.
210 ****************************************************************************/
211
212 static BOOL cli_session_setup_plaintext(struct cli_state *cli, const char *user, 
213                                         const char *pass, const char *workgroup)
214 {
215         uint32 capabilities = cli_session_setup_capabilities(cli);
216         char *p;
217         fstring lanman;
218         
219         fstr_sprintf( lanman, "Samba %s", SAMBA_VERSION_STRING);
220
221         set_message(cli->outbuf,13,0,True);
222         SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
223         cli_setup_packet(cli);
224                         
225         SCVAL(cli->outbuf,smb_vwv0,0xFF);
226         SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
227         SSVAL(cli->outbuf,smb_vwv3,2);
228         SSVAL(cli->outbuf,smb_vwv4,cli->pid);
229         SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
230         SSVAL(cli->outbuf,smb_vwv8,0);
231         SIVAL(cli->outbuf,smb_vwv11,capabilities); 
232         p = smb_buf(cli->outbuf);
233         
234         /* check wether to send the ASCII or UNICODE version of the password */
235         
236         if ( (capabilities & CAP_UNICODE) == 0 ) {
237                 p += clistr_push(cli, p, pass, -1, STR_TERMINATE); /* password */
238                 SSVAL(cli->outbuf,smb_vwv7,PTR_DIFF(p, smb_buf(cli->outbuf)));
239         }
240         else { 
241                 p += clistr_push(cli, p, pass, -1, STR_UNICODE|STR_TERMINATE); /* unicode password */
242                 SSVAL(cli->outbuf,smb_vwv8,PTR_DIFF(p, smb_buf(cli->outbuf)));  
243         }
244         
245         p += clistr_push(cli, p, user, -1, STR_TERMINATE); /* username */
246         p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE); /* workgroup */
247         p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
248         p += clistr_push(cli, p, lanman, -1, STR_TERMINATE);
249         cli_setup_bcc(cli, p);
250
251         cli_send_smb(cli);
252         if (!cli_receive_smb(cli))
253               return False;
254         
255         show_msg(cli->inbuf);
256         
257         if (cli_is_error(cli))
258                 return False;
259
260         cli->vuid = SVAL(cli->inbuf,smb_uid);
261         p = smb_buf(cli->inbuf);
262         p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
263         p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
264         p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
265         fstrcpy(cli->user_name, user);
266
267         return True;
268 }
269
270 /****************************************************************************
271    do a NT1 NTLM/LM encrypted session setup - for when extended security
272    is not negotiated.
273    @param cli client state to create do session setup on
274    @param user username
275    @param pass *either* cleartext password (passlen !=24) or LM response.
276    @param ntpass NT response, implies ntpasslen >=24, implies pass is not clear
277    @param workgroup The user's domain.
278 ****************************************************************************/
279
280 static BOOL cli_session_setup_nt1(struct cli_state *cli, const char *user, 
281                                   const char *pass, size_t passlen,
282                                   const char *ntpass, size_t ntpasslen,
283                                   const char *workgroup)
284 {
285         uint32 capabilities = cli_session_setup_capabilities(cli);
286         DATA_BLOB lm_response = data_blob(NULL, 0);
287         DATA_BLOB nt_response = data_blob(NULL, 0);
288         DATA_BLOB session_key = data_blob(NULL, 0);
289         BOOL ret = False;
290         char *p;
291
292         if (passlen == 0) {
293                 /* do nothing - guest login */
294         } else if (passlen != 24) {
295                 if (lp_client_ntlmv2_auth()) {
296                         DATA_BLOB server_chal;
297                         DATA_BLOB names_blob;
298                         server_chal = data_blob(cli->secblob.data, MIN(cli->secblob.length, 8)); 
299
300                         /* note that the 'workgroup' here is a best guess - we don't know
301                            the server's domain at this point.  The 'server name' is also
302                            dodgy... 
303                         */
304                         names_blob = NTLMv2_generate_names_blob(cli->called.name, workgroup);
305
306                         if (!SMBNTLMv2encrypt(user, workgroup, pass, &server_chal, 
307                                               &names_blob,
308                                               &lm_response, &nt_response, &session_key)) {
309                                 data_blob_free(&names_blob);
310                                 data_blob_free(&server_chal);
311                                 return False;
312                         }
313                         data_blob_free(&names_blob);
314                         data_blob_free(&server_chal);
315
316                 } else {
317                         uchar nt_hash[16];
318                         E_md4hash(pass, nt_hash);
319
320 #ifdef LANMAN_ONLY
321                         nt_response = data_blob(NULL, 0);
322 #else
323                         nt_response = data_blob(NULL, 24);
324                         SMBNTencrypt(pass,cli->secblob.data,nt_response.data);
325 #endif
326                         /* non encrypted password supplied. Ignore ntpass. */
327                         if (lp_client_lanman_auth()) {
328                                 lm_response = data_blob(NULL, 24);
329                                 if (!SMBencrypt(pass,cli->secblob.data, lm_response.data)) {
330                                         /* Oops, the LM response is invalid, just put 
331                                            the NT response there instead */
332                                         data_blob_free(&lm_response);
333                                         lm_response = data_blob(nt_response.data, nt_response.length);
334                                 }
335                         } else {
336                                 /* LM disabled, place NT# in LM field instead */
337                                 lm_response = data_blob(nt_response.data, nt_response.length);
338                         }
339
340                         session_key = data_blob(NULL, 16);
341 #ifdef LANMAN_ONLY
342                         E_deshash(pass, session_key.data);
343                         memset(&session_key.data[8], '\0', 8);
344 #else
345                         SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data);
346 #endif
347                 }
348 #ifdef LANMAN_ONLY
349                 cli_simple_set_signing(cli, session_key, lm_response); 
350 #else
351                 cli_simple_set_signing(cli, session_key, nt_response); 
352 #endif
353         } else {
354                 /* pre-encrypted password supplied.  Only used for 
355                    security=server, can't do
356                    signing because we don't have original key */
357
358                 lm_response = data_blob(pass, passlen);
359                 nt_response = data_blob(ntpass, ntpasslen);
360         }
361
362         /* send a session setup command */
363         memset(cli->outbuf,'\0',smb_size);
364
365         set_message(cli->outbuf,13,0,True);
366         SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
367         cli_setup_packet(cli);
368                         
369         SCVAL(cli->outbuf,smb_vwv0,0xFF);
370         SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
371         SSVAL(cli->outbuf,smb_vwv3,2);
372         SSVAL(cli->outbuf,smb_vwv4,cli->pid);
373         SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
374         SSVAL(cli->outbuf,smb_vwv7,lm_response.length);
375         SSVAL(cli->outbuf,smb_vwv8,nt_response.length);
376         SIVAL(cli->outbuf,smb_vwv11,capabilities); 
377         p = smb_buf(cli->outbuf);
378         if (lm_response.length) {
379                 memcpy(p,lm_response.data, lm_response.length); p += lm_response.length;
380         }
381         if (nt_response.length) {
382                 memcpy(p,nt_response.data, nt_response.length); p += nt_response.length;
383         }
384         p += clistr_push(cli, p, user, -1, STR_TERMINATE);
385
386         /* Upper case here might help some NTLMv2 implementations */
387         p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
388         p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
389         p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
390         cli_setup_bcc(cli, p);
391
392         if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
393                 ret = False;
394                 goto end;
395         }
396
397         /* show_msg(cli->inbuf); */
398
399         if (cli_is_error(cli)) {
400                 ret = False;
401                 goto end;
402         }
403
404         /* use the returned vuid from now on */
405         cli->vuid = SVAL(cli->inbuf,smb_uid);
406         
407         p = smb_buf(cli->inbuf);
408         p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
409         p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
410         p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
411
412         fstrcpy(cli->user_name, user);
413
414         if (session_key.data) {
415                 /* Have plaintext orginal */
416                 cli_set_session_key(cli, session_key);
417         }
418
419         ret = True;
420 end:    
421         data_blob_free(&lm_response);
422         data_blob_free(&nt_response);
423         data_blob_free(&session_key);
424         return ret;
425 }
426
427 /****************************************************************************
428  Send a extended security session setup blob
429 ****************************************************************************/
430
431 static BOOL cli_session_setup_blob_send(struct cli_state *cli, DATA_BLOB blob)
432 {
433         uint32 capabilities = cli_session_setup_capabilities(cli);
434         char *p;
435
436         capabilities |= CAP_EXTENDED_SECURITY;
437
438         /* send a session setup command */
439         memset(cli->outbuf,'\0',smb_size);
440
441         set_message(cli->outbuf,12,0,True);
442         SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
443
444         cli_setup_packet(cli);
445                         
446         SCVAL(cli->outbuf,smb_vwv0,0xFF);
447         SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
448         SSVAL(cli->outbuf,smb_vwv3,2);
449         SSVAL(cli->outbuf,smb_vwv4,1);
450         SIVAL(cli->outbuf,smb_vwv5,0);
451         SSVAL(cli->outbuf,smb_vwv7,blob.length);
452         SIVAL(cli->outbuf,smb_vwv10,capabilities); 
453         p = smb_buf(cli->outbuf);
454         memcpy(p, blob.data, blob.length);
455         p += blob.length;
456         p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
457         p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
458         cli_setup_bcc(cli, p);
459         return cli_send_smb(cli);
460 }
461
462 /****************************************************************************
463  Send a extended security session setup blob, returning a reply blob.
464 ****************************************************************************/
465
466 static DATA_BLOB cli_session_setup_blob_receive(struct cli_state *cli)
467 {
468         DATA_BLOB blob2 = data_blob(NULL, 0);
469         char *p;
470         size_t len;
471
472         if (!cli_receive_smb(cli))
473                 return blob2;
474
475         show_msg(cli->inbuf);
476
477         if (cli_is_error(cli) && !NT_STATUS_EQUAL(cli_nt_error(cli),
478                                                   NT_STATUS_MORE_PROCESSING_REQUIRED)) {
479                 return blob2;
480         }
481         
482         /* use the returned vuid from now on */
483         cli->vuid = SVAL(cli->inbuf,smb_uid);
484         
485         p = smb_buf(cli->inbuf);
486
487         blob2 = data_blob(p, SVAL(cli->inbuf, smb_vwv3));
488
489         p += blob2.length;
490         p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
491
492         /* w2k with kerberos doesn't properly null terminate this field */
493         len = smb_buflen(cli->inbuf) - PTR_DIFF(p, smb_buf(cli->inbuf));
494         p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), len, 0);
495
496         return blob2;
497 }
498
499 #ifdef HAVE_KRB5
500
501 /****************************************************************************
502  Send a extended security session setup blob, returning a reply blob.
503 ****************************************************************************/
504
505 static DATA_BLOB cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob)
506 {
507         DATA_BLOB blob2 = data_blob(NULL, 0);
508         if (!cli_session_setup_blob_send(cli, blob)) {
509                 return blob2;
510         }
511                 
512         return cli_session_setup_blob_receive(cli);
513 }
514
515 /****************************************************************************
516  Use in-memory credentials cache
517 ****************************************************************************/
518
519 static void use_in_memory_ccache(void) {
520         setenv(KRB5_ENV_CCNAME, "MEMORY:cliconnect", 1);
521 }
522
523 /****************************************************************************
524  Do a spnego/kerberos encrypted session setup.
525 ****************************************************************************/
526
527 static ADS_STATUS cli_session_setup_kerberos(struct cli_state *cli, const char *principal, const char *workgroup)
528 {
529         DATA_BLOB blob2, negTokenTarg;
530         DATA_BLOB session_key_krb5;
531         DATA_BLOB null_blob = data_blob(NULL, 0);
532         int rc;
533
534         DEBUG(2,("Doing kerberos session setup\n"));
535
536         /* generate the encapsulated kerberos5 ticket */
537         rc = spnego_gen_negTokenTarg(principal, 0, &negTokenTarg, &session_key_krb5);
538
539         if (rc) {
540                 DEBUG(1, ("spnego_gen_negTokenTarg failed: %s\n", error_message(rc)));
541                 return ADS_ERROR_KRB5(rc);
542         }
543
544 #if 0
545         file_save("negTokenTarg.dat", negTokenTarg.data, negTokenTarg.length);
546 #endif
547
548         cli_simple_set_signing(cli, session_key_krb5, null_blob); 
549                         
550         blob2 = cli_session_setup_blob(cli, negTokenTarg);
551
552         /* we don't need this blob for kerberos */
553         data_blob_free(&blob2);
554
555         cli_set_session_key(cli, session_key_krb5);
556
557         data_blob_free(&negTokenTarg);
558         data_blob_free(&session_key_krb5);
559
560         if (cli_is_error(cli)) {
561                 if (NT_STATUS_IS_OK(cli_nt_error(cli))) {
562                         return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
563                 }
564         } 
565         return ADS_ERROR_NT(cli_nt_error(cli));
566 }
567 #endif  /* HAVE_KRB5 */
568
569
570 /****************************************************************************
571  Do a spnego/NTLMSSP encrypted session setup.
572 ****************************************************************************/
573
574 static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, const char *user, 
575                                           const char *pass, const char *domain)
576 {
577         struct ntlmssp_state *ntlmssp_state;
578         NTSTATUS nt_status;
579         int turn = 1;
580         DATA_BLOB msg1;
581         DATA_BLOB blob = data_blob(NULL, 0);
582         DATA_BLOB blob_in = data_blob(NULL, 0);
583         DATA_BLOB blob_out = data_blob(NULL, 0);
584
585         cli_temp_set_signing(cli);
586
587         if (!NT_STATUS_IS_OK(nt_status = ntlmssp_client_start(&ntlmssp_state))) {
588                 return nt_status;
589         }
590
591         if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, user))) {
592                 return nt_status;
593         }
594         if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, domain))) {
595                 return nt_status;
596         }
597         if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_password(ntlmssp_state, pass))) {
598                 return nt_status;
599         }
600
601         do {
602                 nt_status = ntlmssp_update(ntlmssp_state, 
603                                                   blob_in, &blob_out);
604                 data_blob_free(&blob_in);
605                 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
606                         if (turn == 1) {
607                                 /* and wrap it in a SPNEGO wrapper */
608                                 msg1 = gen_negTokenInit(OID_NTLMSSP, blob_out);
609                         } else {
610                                 /* wrap it in SPNEGO */
611                                 msg1 = spnego_gen_auth(blob_out);
612                         }
613                 
614                         /* now send that blob on its way */
615                         if (!cli_session_setup_blob_send(cli, msg1)) {
616                                 DEBUG(3, ("Failed to send NTLMSSP/SPNEGO blob to server!\n"));
617                                 nt_status = NT_STATUS_UNSUCCESSFUL;
618                         } else {
619                                 data_blob_free(&msg1);
620                                 
621                                 blob = cli_session_setup_blob_receive(cli);
622                                 
623                                 nt_status = cli_nt_error(cli);
624                                 if (cli_is_error(cli) && NT_STATUS_IS_OK(nt_status)) {
625                                         if (cli->smb_rw_error == READ_BAD_SIG) {
626                                                 nt_status = NT_STATUS_ACCESS_DENIED;
627                                         } else {
628                                                 nt_status = NT_STATUS_UNSUCCESSFUL;
629                                         }
630                                 }
631                         }
632                 }
633                 
634                 if (!blob.length) {
635                         if (NT_STATUS_IS_OK(nt_status)) {
636                                 nt_status = NT_STATUS_UNSUCCESSFUL;
637                         }
638                 } else if ((turn == 1) && 
639                            NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
640                         DATA_BLOB tmp_blob = data_blob(NULL, 0);
641                         /* the server might give us back two challenges */
642                         if (!spnego_parse_challenge(blob, &blob_in, 
643                                                     &tmp_blob)) {
644                                 DEBUG(3,("Failed to parse challenges\n"));
645                                 nt_status = NT_STATUS_INVALID_PARAMETER;
646                         }
647                         data_blob_free(&tmp_blob);
648                 } else {
649                         if (!spnego_parse_auth_response(blob, nt_status, 
650                                                         &blob_in)) {
651                                 DEBUG(3,("Failed to parse auth response\n"));
652                                 if (NT_STATUS_IS_OK(nt_status) 
653                                     || NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) 
654                                         nt_status = NT_STATUS_INVALID_PARAMETER;
655                         }
656                 }
657                 data_blob_free(&blob);
658                 data_blob_free(&blob_out);
659                 turn++;
660         } while (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED));
661
662         if (NT_STATUS_IS_OK(nt_status)) {
663
664                 DATA_BLOB key = data_blob(ntlmssp_state->session_key.data,
665                                           ntlmssp_state->session_key.length);
666                 DATA_BLOB null_blob = data_blob(NULL, 0);
667                 BOOL res;
668
669                 fstrcpy(cli->server_domain, ntlmssp_state->server_domain);
670                 cli_set_session_key(cli, ntlmssp_state->session_key);
671
672                 res = cli_simple_set_signing(cli, key, null_blob);
673
674                 data_blob_free(&key);
675
676                 if (res) {
677                         
678                         /* 'resign' the last message, so we get the right sequence numbers
679                            for checking the first reply from the server */
680                         cli_calculate_sign_mac(cli);
681                         
682                         if (!cli_check_sign_mac(cli)) {
683                                 nt_status = NT_STATUS_ACCESS_DENIED;
684                         }
685                 }
686         }
687
688         /* we have a reference conter on ntlmssp_state, if we are signing
689            then the state will be kept by the signing engine */
690
691         ntlmssp_end(&ntlmssp_state);
692
693         return nt_status;
694 }
695
696 /****************************************************************************
697  Do a spnego encrypted session setup.
698 ****************************************************************************/
699
700 ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, const char *user, 
701                               const char *pass, const char *domain)
702 {
703         char *principal;
704         char *OIDs[ASN1_MAX_OIDS];
705         int i;
706 #ifdef HAVE_KRB5
707         BOOL got_kerberos_mechanism = False;
708 #endif
709         DATA_BLOB blob;
710
711         DEBUG(3,("Doing spnego session setup (blob length=%lu)\n", (unsigned long)cli->secblob.length));
712
713         /* the server might not even do spnego */
714         if (cli->secblob.length <= 16) {
715                 DEBUG(3,("server didn't supply a full spnego negprot\n"));
716                 goto ntlmssp;
717         }
718
719 #if 0
720         file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
721 #endif
722
723         /* there is 16 bytes of GUID before the real spnego packet starts */
724         blob = data_blob(cli->secblob.data+16, cli->secblob.length-16);
725
726         /* the server sent us the first part of the SPNEGO exchange in the negprot 
727            reply */
728         if (!spnego_parse_negTokenInit(blob, OIDs, &principal)) {
729                 data_blob_free(&blob);
730                 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
731         }
732         data_blob_free(&blob);
733
734         /* make sure the server understands kerberos */
735         for (i=0;OIDs[i];i++) {
736                 DEBUG(3,("got OID=%s\n", OIDs[i]));
737 #ifdef HAVE_KRB5
738                 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
739                     strcmp(OIDs[i], OID_KERBEROS5) == 0) {
740                         got_kerberos_mechanism = True;
741                 }
742 #endif
743                 free(OIDs[i]);
744         }
745         DEBUG(3,("got principal=%s\n", principal));
746
747         fstrcpy(cli->user_name, user);
748
749 #ifdef HAVE_KRB5
750         /* If password is set we reauthenticate to kerberos server
751          * and do not store results */
752
753         if (got_kerberos_mechanism && cli->use_kerberos) {
754                 ADS_STATUS rc;
755
756                 if (pass && *pass) {
757                         int ret;
758                         
759                         use_in_memory_ccache();
760                         ret = kerberos_kinit_password(user, pass, 0 /* no time correction for now */, NULL, NULL);
761                         
762                         if (ret){
763                                 SAFE_FREE(principal);
764                                 DEBUG(0, ("Kinit failed: %s\n", error_message(ret)));
765                                 if (cli->fallback_after_kerberos)
766                                         goto ntlmssp;
767                                 return ADS_ERROR_KRB5(ret);
768                         }
769                 }
770                 
771                 rc = cli_session_setup_kerberos(cli, principal, domain);
772                 if (ADS_ERR_OK(rc) || !cli->fallback_after_kerberos) {
773                         SAFE_FREE(principal);
774                         return rc;
775                 }
776         }
777 #endif
778
779         SAFE_FREE(principal);
780
781 ntlmssp:
782
783         return ADS_ERROR_NT(cli_session_setup_ntlmssp(cli, user, pass, domain));
784 }
785
786 /****************************************************************************
787  Send a session setup. The username and workgroup is in UNIX character
788  format and must be converted to DOS codepage format before sending. If the
789  password is in plaintext, the same should be done.
790 ****************************************************************************/
791
792 BOOL cli_session_setup(struct cli_state *cli, 
793                        const char *user, 
794                        const char *pass, int passlen,
795                        const char *ntpass, int ntpasslen,
796                        const char *workgroup)
797 {
798         char *p;
799         fstring user2;
800
801         /* allow for workgroups as part of the username */
802         fstrcpy(user2, user);
803         if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/')) ||
804             (p=strchr_m(user2,*lp_winbind_separator()))) {
805                 *p = 0;
806                 user = p+1;
807                 workgroup = user2;
808         }
809
810         if (cli->protocol < PROTOCOL_LANMAN1)
811                 return True;
812
813         /* now work out what sort of session setup we are going to
814            do. I have split this into separate functions to make the
815            flow a bit easier to understand (tridge) */
816
817         /* if its an older server then we have to use the older request format */
818
819         if (cli->protocol < PROTOCOL_NT1) {
820                 if (!lp_client_lanman_auth() && passlen != 24 && (*pass)) {
821                         DEBUG(1, ("Server requested LM password but 'client lanman auth'"
822                                   " is disabled\n"));
823                         return False;
824                 }
825
826                 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0 &&
827                     !lp_client_plaintext_auth() && (*pass)) {
828                         DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'"
829                                   " is disabled\n"));
830                         return False;
831                 }
832
833                 return cli_session_setup_lanman2(cli, user, pass, passlen, workgroup);
834         }
835
836         /* if no user is supplied then we have to do an anonymous connection.
837            passwords are ignored */
838
839         if (!user || !*user)
840                 return cli_session_setup_guest(cli);
841
842         /* if the server is share level then send a plaintext null
843            password at this point. The password is sent in the tree
844            connect */
845
846         if ((cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) == 0) 
847                 return cli_session_setup_plaintext(cli, user, "", workgroup);
848
849         /* if the server doesn't support encryption then we have to use 
850            plaintext. The second password is ignored */
851
852         if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) {
853                 if (!lp_client_plaintext_auth() && (*pass)) {
854                         DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'"
855                                   " is disabled\n"));
856                         return False;
857                 }
858                 return cli_session_setup_plaintext(cli, user, pass, workgroup);
859         }
860
861         /* if the server supports extended security then use SPNEGO */
862
863         if (cli->capabilities & CAP_EXTENDED_SECURITY) {
864                 ADS_STATUS status = cli_session_setup_spnego(cli, user, pass, workgroup);
865                 if (!ADS_ERR_OK(status)) {
866                         DEBUG(3, ("SPNEGO login failed: %s\n", ads_errstr(status)));
867                         return False;
868                 }
869                 return True;
870         }
871
872         /* otherwise do a NT1 style session setup */
873
874         return cli_session_setup_nt1(cli, user, 
875                                      pass, passlen, ntpass, ntpasslen,
876                                      workgroup);        
877 }
878
879 /****************************************************************************
880  Send a uloggoff.
881 *****************************************************************************/
882
883 BOOL cli_ulogoff(struct cli_state *cli)
884 {
885         memset(cli->outbuf,'\0',smb_size);
886         set_message(cli->outbuf,2,0,True);
887         SCVAL(cli->outbuf,smb_com,SMBulogoffX);
888         cli_setup_packet(cli);
889         SSVAL(cli->outbuf,smb_vwv0,0xFF);
890         SSVAL(cli->outbuf,smb_vwv2,0);  /* no additional info */
891
892         cli_send_smb(cli);
893         if (!cli_receive_smb(cli))
894                 return False;
895
896         if (cli_is_error(cli)) {
897                 return False;
898         }
899
900         cli->cnum = -1;
901         return True;
902 }
903
904 /****************************************************************************
905  Send a tconX.
906 ****************************************************************************/
907 BOOL cli_send_tconX(struct cli_state *cli, 
908                     const char *share, const char *dev, const char *pass, int passlen)
909 {
910         fstring fullshare, pword;
911         char *p;
912         memset(cli->outbuf,'\0',smb_size);
913         memset(cli->inbuf,'\0',smb_size);
914
915         fstrcpy(cli->share, share);
916
917         /* in user level security don't send a password now */
918         if (cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) {
919                 passlen = 1;
920                 pass = "";
921         }
922
923         if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && *pass && passlen != 24) {
924                 if (!lp_client_lanman_auth()) {
925                         DEBUG(1, ("Server requested LANMAN password (share-level security) but 'client use lanman auth'"
926                                   " is disabled\n"));
927                         return False;
928                 }
929
930                 /*
931                  * Non-encrypted passwords - convert to DOS codepage before encryption.
932                  */
933                 passlen = 24;
934                 SMBencrypt(pass,cli->secblob.data,(uchar *)pword);
935         } else {
936                 if((cli->sec_mode & (NEGOTIATE_SECURITY_USER_LEVEL|NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)) == 0) {
937                         if (!lp_client_plaintext_auth() && (*pass)) {
938                                 DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'"
939                                           " is disabled\n"));
940                                 return False;
941                         }
942
943                         /*
944                          * Non-encrypted passwords - convert to DOS codepage before using.
945                          */
946                         passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
947                         
948                 } else {
949                         memcpy(pword, pass, passlen);
950                 }
951         }
952
953         slprintf(fullshare, sizeof(fullshare)-1,
954                  "\\\\%s\\%s", cli->desthost, share);
955
956         set_message(cli->outbuf,4, 0, True);
957         SCVAL(cli->outbuf,smb_com,SMBtconX);
958         cli_setup_packet(cli);
959
960         SSVAL(cli->outbuf,smb_vwv0,0xFF);
961         SSVAL(cli->outbuf,smb_vwv3,passlen);
962
963         p = smb_buf(cli->outbuf);
964         memcpy(p,pword,passlen);
965         p += passlen;
966         p += clistr_push(cli, p, fullshare, -1, STR_TERMINATE |STR_UPPER);
967         p += clistr_push(cli, p, dev, -1, STR_TERMINATE |STR_UPPER | STR_ASCII);
968
969         cli_setup_bcc(cli, p);
970
971         cli_send_smb(cli);
972         if (!cli_receive_smb(cli))
973                 return False;
974
975         if (cli_is_error(cli))
976                 return False;
977
978         clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE|STR_ASCII);
979
980         if (cli->protocol >= PROTOCOL_NT1 &&
981             smb_buflen(cli->inbuf) == 3) {
982                 /* almost certainly win95 - enable bug fixes */
983                 cli->win95 = True;
984         }
985         
986         /* Make sure that we have the optional support 16-bit field.  WCT > 2 */
987         /* Avoids issues when connecting to Win9x boxes sharing files */
988
989         cli->dfsroot = False;
990         if ( (CVAL(cli->inbuf, smb_wct))>2 && cli->protocol >= PROTOCOL_LANMAN2 )
991                 cli->dfsroot = (SVAL( cli->inbuf, smb_vwv2 ) & SMB_SHARE_IN_DFS) ? True : False;
992
993         cli->cnum = SVAL(cli->inbuf,smb_tid);
994         return True;
995 }
996
997 /****************************************************************************
998  Send a tree disconnect.
999 ****************************************************************************/
1000
1001 BOOL cli_tdis(struct cli_state *cli)
1002 {
1003         memset(cli->outbuf,'\0',smb_size);
1004         set_message(cli->outbuf,0,0,True);
1005         SCVAL(cli->outbuf,smb_com,SMBtdis);
1006         SSVAL(cli->outbuf,smb_tid,cli->cnum);
1007         cli_setup_packet(cli);
1008         
1009         cli_send_smb(cli);
1010         if (!cli_receive_smb(cli))
1011                 return False;
1012         
1013         if (cli_is_error(cli)) {
1014                 return False;
1015         }
1016
1017         cli->cnum = -1;
1018         return True;
1019 }
1020
1021 /****************************************************************************
1022  Send a negprot command.
1023 ****************************************************************************/
1024
1025 void cli_negprot_send(struct cli_state *cli)
1026 {
1027         char *p;
1028         int numprots;
1029
1030         if (cli->protocol < PROTOCOL_NT1)
1031                 cli->use_spnego = False;
1032
1033         memset(cli->outbuf,'\0',smb_size);
1034
1035         /* setup the protocol strings */
1036         set_message(cli->outbuf,0,0,True);
1037
1038         p = smb_buf(cli->outbuf);
1039         for (numprots=0;
1040              prots[numprots].name && prots[numprots].prot<=cli->protocol;
1041              numprots++) {
1042                 *p++ = 2;
1043                 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
1044         }
1045
1046         SCVAL(cli->outbuf,smb_com,SMBnegprot);
1047         cli_setup_bcc(cli, p);
1048         cli_setup_packet(cli);
1049
1050         SCVAL(smb_buf(cli->outbuf),0,2);
1051
1052         cli_send_smb(cli);
1053 }
1054
1055 /****************************************************************************
1056  Send a negprot command.
1057 ****************************************************************************/
1058
1059 BOOL cli_negprot(struct cli_state *cli)
1060 {
1061         char *p;
1062         int numprots;
1063         int plength;
1064
1065         if (cli->protocol < PROTOCOL_NT1)
1066                 cli->use_spnego = False;
1067
1068         memset(cli->outbuf,'\0',smb_size);
1069
1070         /* setup the protocol strings */
1071         for (plength=0,numprots=0;
1072              prots[numprots].name && prots[numprots].prot<=cli->protocol;
1073              numprots++)
1074                 plength += strlen(prots[numprots].name)+2;
1075     
1076         set_message(cli->outbuf,0,plength,True);
1077
1078         p = smb_buf(cli->outbuf);
1079         for (numprots=0;
1080              prots[numprots].name && prots[numprots].prot<=cli->protocol;
1081              numprots++) {
1082                 *p++ = 2;
1083                 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
1084         }
1085
1086         SCVAL(cli->outbuf,smb_com,SMBnegprot);
1087         cli_setup_packet(cli);
1088
1089         SCVAL(smb_buf(cli->outbuf),0,2);
1090
1091         cli_send_smb(cli);
1092         if (!cli_receive_smb(cli))
1093                 return False;
1094
1095         show_msg(cli->inbuf);
1096
1097         if (cli_is_error(cli) ||
1098             ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
1099                 return(False);
1100         }
1101
1102         cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;  
1103
1104         if ((cli->protocol < PROTOCOL_NT1) && cli->sign_info.mandatory_signing) {
1105                 DEBUG(0,("cli_negprot: SMB signing is mandatory and the selected protocol level doesn't support it.\n"));
1106                 return False;
1107         }
1108
1109         if (cli->protocol >= PROTOCOL_NT1) {    
1110                 /* NT protocol */
1111                 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
1112                 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
1113                 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
1114                 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
1115                 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1);
1116                 cli->serverzone *= 60;
1117                 /* this time arrives in real GMT */
1118                 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
1119                 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
1120                 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
1121                 if (cli->capabilities & CAP_RAW_MODE) {
1122                         cli->readbraw_supported = True;
1123                         cli->writebraw_supported = True;      
1124                 }
1125                 /* work out if they sent us a workgroup */
1126                 if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
1127                     smb_buflen(cli->inbuf) > 8) {
1128                         clistr_pull(cli, cli->server_domain, 
1129                                     smb_buf(cli->inbuf)+8, sizeof(cli->server_domain),
1130                                     smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
1131                 }
1132
1133                 /*
1134                  * As signing is slow we only turn it on if either the client or
1135                  * the server require it. JRA.
1136                  */
1137
1138                 if (cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED) {
1139                         /* Fail if server says signing is mandatory and we don't want to support it. */
1140                         if (!cli->sign_info.allow_smb_signing) {
1141                                 DEBUG(0,("cli_negprot: SMB signing is mandatory and we have disabled it.\n"));
1142                                 return False;
1143                         }
1144                         cli->sign_info.negotiated_smb_signing = True;
1145                         cli->sign_info.mandatory_signing = True;
1146                 } else if (cli->sign_info.mandatory_signing && cli->sign_info.allow_smb_signing) {
1147                         /* Fail if client says signing is mandatory and the server doesn't support it. */
1148                         if (!(cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED)) {
1149                                 DEBUG(1,("cli_negprot: SMB signing is mandatory and the server doesn't support it.\n"));
1150                                 return False;
1151                         }
1152                         cli->sign_info.negotiated_smb_signing = True;
1153                         cli->sign_info.mandatory_signing = True;
1154                 } else if (cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) {
1155                         cli->sign_info.negotiated_smb_signing = True;
1156                 }
1157
1158                 if (cli->capabilities & (CAP_LARGE_READX|CAP_LARGE_WRITEX)) {
1159                         SAFE_FREE(cli->outbuf);
1160                         SAFE_FREE(cli->inbuf);
1161                         cli->outbuf = (char *)SMB_MALLOC(CLI_MAX_LARGE_READX_SIZE+SAFETY_MARGIN);
1162                         cli->inbuf = (char *)SMB_MALLOC(CLI_MAX_LARGE_READX_SIZE+SAFETY_MARGIN);
1163                         cli->bufsize = CLI_MAX_LARGE_READX_SIZE;
1164                 }
1165
1166         } else if (cli->protocol >= PROTOCOL_LANMAN1) {
1167                 cli->use_spnego = False;
1168                 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
1169                 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
1170                 cli->max_mux = SVAL(cli->inbuf, smb_vwv3); 
1171                 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
1172                 cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
1173                 cli->serverzone *= 60;
1174                 /* this time is converted to GMT by make_unix_date */
1175                 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
1176                 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
1177                 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
1178                 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
1179         } else {
1180                 /* the old core protocol */
1181                 cli->use_spnego = False;
1182                 cli->sec_mode = 0;
1183                 cli->serverzone = TimeDiff(time(NULL));
1184         }
1185
1186         cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
1187
1188         /* a way to force ascii SMB */
1189         if (getenv("CLI_FORCE_ASCII"))
1190                 cli->capabilities &= ~CAP_UNICODE;
1191
1192         return True;
1193 }
1194
1195 /****************************************************************************
1196  Send a session request. See rfc1002.txt 4.3 and 4.3.2.
1197 ****************************************************************************/
1198
1199 BOOL cli_session_request(struct cli_state *cli,
1200                          struct nmb_name *calling, struct nmb_name *called)
1201 {
1202         char *p;
1203         int len = 4;
1204
1205         memcpy(&(cli->calling), calling, sizeof(*calling));
1206         memcpy(&(cli->called ), called , sizeof(*called ));
1207   
1208         /* put in the destination name */
1209         p = cli->outbuf+len;
1210         name_mangle(cli->called .name, p, cli->called .name_type);
1211         len += name_len(p);
1212
1213         /* and my name */
1214         p = cli->outbuf+len;
1215         name_mangle(cli->calling.name, p, cli->calling.name_type);
1216         len += name_len(p);
1217
1218         /* 445 doesn't have session request */
1219         if (cli->port == 445)
1220                 return True;
1221
1222         /* send a session request (RFC 1002) */
1223         /* setup the packet length
1224          * Remove four bytes from the length count, since the length
1225          * field in the NBT Session Service header counts the number
1226          * of bytes which follow.  The cli_send_smb() function knows
1227          * about this and accounts for those four bytes.
1228          * CRH.
1229          */
1230         len -= 4;
1231         _smb_setlen(cli->outbuf,len);
1232         SCVAL(cli->outbuf,0,0x81);
1233
1234         cli_send_smb(cli);
1235         DEBUG(5,("Sent session request\n"));
1236
1237         if (!cli_receive_smb(cli))
1238                 return False;
1239
1240         if (CVAL(cli->inbuf,0) == 0x84) {
1241                 /* C. Hoch  9/14/95 Start */
1242                 /* For information, here is the response structure.
1243                  * We do the byte-twiddling to for portability.
1244                 struct RetargetResponse{
1245                 unsigned char type;
1246                 unsigned char flags;
1247                 int16 length;
1248                 int32 ip_addr;
1249                 int16 port;
1250                 };
1251                 */
1252                 int port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
1253                 /* SESSION RETARGET */
1254                 putip((char *)&cli->dest_ip,cli->inbuf+4);
1255
1256                 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
1257                 if (cli->fd == -1)
1258                         return False;
1259
1260                 DEBUG(3,("Retargeted\n"));
1261
1262                 set_socket_options(cli->fd,user_socket_options);
1263
1264                 /* Try again */
1265                 {
1266                         static int depth;
1267                         BOOL ret;
1268                         if (depth > 4) {
1269                                 DEBUG(0,("Retarget recursion - failing\n"));
1270                                 return False;
1271                         }
1272                         depth++;
1273                         ret = cli_session_request(cli, calling, called);
1274                         depth--;
1275                         return ret;
1276                 }
1277         } /* C. Hoch 9/14/95 End */
1278
1279         if (CVAL(cli->inbuf,0) != 0x82) {
1280                 /* This is the wrong place to put the error... JRA. */
1281                 cli->rap_error = CVAL(cli->inbuf,4);
1282                 return False;
1283         }
1284         return(True);
1285 }
1286
1287 /****************************************************************************
1288  Open the client sockets.
1289 ****************************************************************************/
1290
1291 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
1292 {
1293         int name_type = 0x20;
1294         char *p;
1295
1296         /* reasonable default hostname */
1297         if (!host) host = "*SMBSERVER";
1298
1299         fstrcpy(cli->desthost, host);
1300
1301         /* allow hostnames of the form NAME#xx and do a netbios lookup */
1302         if ((p = strchr(cli->desthost, '#'))) {
1303                 name_type = strtol(p+1, NULL, 16);              
1304                 *p = 0;
1305         }
1306         
1307         if (!ip || is_zero_ip(*ip)) {
1308                 if (!resolve_name(cli->desthost, &cli->dest_ip, name_type)) {
1309                         return False;
1310                 }
1311                 if (ip) *ip = cli->dest_ip;
1312         } else {
1313                 cli->dest_ip = *ip;
1314         }
1315
1316         if (getenv("LIBSMB_PROG")) {
1317                 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
1318         } else {
1319                 /* try 445 first, then 139 */
1320                 int port = cli->port?cli->port:445;
1321                 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, 
1322                                           port, cli->timeout);
1323                 if (cli->fd == -1 && cli->port == 0) {
1324                         port = 139;
1325                         cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, 
1326                                                   port, cli->timeout);
1327                 }
1328                 if (cli->fd != -1)
1329                         cli->port = port;
1330         }
1331         if (cli->fd == -1) {
1332                 DEBUG(1,("Error connecting to %s (%s)\n",
1333                          ip?inet_ntoa(*ip):host,strerror(errno)));
1334                 return False;
1335         }
1336
1337         set_socket_options(cli->fd,user_socket_options);
1338
1339         return True;
1340 }
1341
1342 /****************************************************************************
1343  Initialise client credentials for authenticated pipe access.
1344 ****************************************************************************/
1345
1346 void init_creds(struct ntuser_creds *creds, const char* username,
1347                        const char* domain, const char* password)
1348 {
1349         ZERO_STRUCTP(creds);
1350
1351         pwd_set_cleartext(&creds->pwd, password);
1352
1353         fstrcpy(creds->user_name, username);
1354         fstrcpy(creds->domain, domain);
1355
1356         if (!*username) {
1357                 creds->pwd.null_pwd = True;
1358         }
1359 }
1360
1361 /**
1362    establishes a connection to after the negprot. 
1363    @param output_cli A fully initialised cli structure, non-null only on success
1364    @param dest_host The netbios name of the remote host
1365    @param dest_ip (optional) The the destination IP, NULL for name based lookup
1366    @param port (optional) The destination port (0 for default)
1367    @param retry BOOL. Did this connection fail with a retryable error ?
1368
1369 */
1370 NTSTATUS cli_start_connection(struct cli_state **output_cli, 
1371                               const char *my_name, 
1372                               const char *dest_host, 
1373                               struct in_addr *dest_ip, int port,
1374                               int signing_state, int flags,
1375                               BOOL *retry) 
1376 {
1377         NTSTATUS nt_status;
1378         struct nmb_name calling;
1379         struct nmb_name called;
1380         struct cli_state *cli;
1381         struct in_addr ip;
1382
1383         if (retry)
1384                 *retry = False;
1385
1386         if (!my_name) 
1387                 my_name = global_myname();
1388         
1389         if (!(cli = cli_initialise(NULL)))
1390                 return NT_STATUS_NO_MEMORY;
1391         
1392         make_nmb_name(&calling, my_name, 0x0);
1393         make_nmb_name(&called , dest_host, 0x20);
1394
1395         if (cli_set_port(cli, port) != port) {
1396                 cli_shutdown(cli);
1397                 return NT_STATUS_UNSUCCESSFUL;
1398         }
1399
1400         cli_set_timeout(cli, 10000); /* 10 seconds. */
1401
1402         if (dest_ip)
1403                 ip = *dest_ip;
1404         else
1405                 ZERO_STRUCT(ip);
1406
1407 again:
1408
1409         DEBUG(3,("Connecting to host=%s\n", dest_host));
1410         
1411         if (!cli_connect(cli, dest_host, &ip)) {
1412                 DEBUG(1,("cli_full_connection: failed to connect to %s (%s)\n",
1413                          nmb_namestr(&called), inet_ntoa(ip)));
1414                 cli_shutdown(cli);
1415                 return NT_STATUS_UNSUCCESSFUL;
1416         }
1417
1418         if (retry)
1419                 *retry = True;
1420
1421         if (!cli_session_request(cli, &calling, &called)) {
1422                 char *p;
1423                 DEBUG(1,("session request to %s failed (%s)\n", 
1424                          called.name, cli_errstr(cli)));
1425                 if ((p=strchr(called.name, '.')) && !is_ipaddress(called.name)) {
1426                         *p = 0;
1427                         goto again;
1428                 }
1429                 if (strcmp(called.name, "*SMBSERVER")) {
1430                         make_nmb_name(&called , "*SMBSERVER", 0x20);
1431                         goto again;
1432                 }
1433                 return NT_STATUS_UNSUCCESSFUL;
1434         }
1435
1436         cli_setup_signing_state(cli, signing_state);
1437
1438         if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO)
1439                 cli->use_spnego = False;
1440         else if (flags & CLI_FULL_CONNECTION_USE_KERBEROS)
1441                 cli->use_kerberos = True;
1442
1443         if (!cli_negprot(cli)) {
1444                 DEBUG(1,("failed negprot\n"));
1445                 nt_status = NT_STATUS_UNSUCCESSFUL;
1446                 cli_shutdown(cli);
1447                 return nt_status;
1448         }
1449
1450         *output_cli = cli;
1451         return NT_STATUS_OK;
1452 }
1453
1454
1455 /**
1456    establishes a connection right up to doing tconX, password specified.
1457    @param output_cli A fully initialised cli structure, non-null only on success
1458    @param dest_host The netbios name of the remote host
1459    @param dest_ip (optional) The the destination IP, NULL for name based lookup
1460    @param port (optional) The destination port (0 for default)
1461    @param service (optional) The share to make the connection to.  Should be 'unqualified' in any way.
1462    @param service_type The 'type' of serivice. 
1463    @param user Username, unix string
1464    @param domain User's domain
1465    @param password User's password, unencrypted unix string.
1466    @param retry BOOL. Did this connection fail with a retryable error ?
1467 */
1468
1469 NTSTATUS cli_full_connection(struct cli_state **output_cli, 
1470                              const char *my_name, 
1471                              const char *dest_host, 
1472                              struct in_addr *dest_ip, int port,
1473                              const char *service, const char *service_type,
1474                              const char *user, const char *domain, 
1475                              const char *password, int flags,
1476                              int signing_state,
1477                              BOOL *retry) 
1478 {
1479         struct ntuser_creds creds;
1480         NTSTATUS nt_status;
1481         struct cli_state *cli = NULL;
1482
1483         nt_status = cli_start_connection(&cli, my_name, dest_host, 
1484                                          dest_ip, port, signing_state, flags, retry);
1485         
1486         if (!NT_STATUS_IS_OK(nt_status)) {
1487                 return nt_status;
1488         }
1489
1490         if (!cli_session_setup(cli, user, password, strlen(password)+1, 
1491                                password, strlen(password)+1, 
1492                                domain)) {
1493                 if ((flags & CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK)
1494                     && cli_session_setup(cli, "", "", 0, "", 0, domain)) {
1495                 } else {
1496                         nt_status = cli_nt_error(cli);
1497                         DEBUG(1,("failed session setup with %s\n", nt_errstr(nt_status)));
1498                         cli_shutdown(cli);
1499                         if (NT_STATUS_IS_OK(nt_status)) 
1500                                 nt_status = NT_STATUS_UNSUCCESSFUL;
1501                         return nt_status;
1502                 }
1503         } 
1504
1505         if (service) {
1506                 if (!cli_send_tconX(cli, service, service_type,
1507                                     password, strlen(password)+1)) {
1508                         nt_status = cli_nt_error(cli);
1509                         DEBUG(1,("failed tcon_X with %s\n", nt_errstr(nt_status)));
1510                         cli_shutdown(cli);
1511                         if (NT_STATUS_IS_OK(nt_status)) {
1512                                 nt_status = NT_STATUS_UNSUCCESSFUL;
1513                         }
1514                         return nt_status;
1515                 }
1516         }
1517
1518         init_creds(&creds, user, domain, password);
1519         cli_init_creds(cli, &creds);
1520
1521         *output_cli = cli;
1522         return NT_STATUS_OK;
1523 }
1524
1525 /****************************************************************************
1526  Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
1527 ****************************************************************************/
1528
1529 BOOL attempt_netbios_session_request(struct cli_state *cli, const char *srchost, const char *desthost,
1530                                      struct in_addr *pdest_ip)
1531 {
1532         struct nmb_name calling, called;
1533
1534         make_nmb_name(&calling, srchost, 0x0);
1535
1536         /*
1537          * If the called name is an IP address
1538          * then use *SMBSERVER immediately.
1539          */
1540
1541         if(is_ipaddress(desthost))
1542                 make_nmb_name(&called, "*SMBSERVER", 0x20);
1543         else
1544                 make_nmb_name(&called, desthost, 0x20);
1545
1546         if (!cli_session_request(cli, &calling, &called)) {
1547                 struct nmb_name smbservername;
1548
1549                 make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
1550
1551                 /*
1552                  * If the name wasn't *SMBSERVER then
1553                  * try with *SMBSERVER if the first name fails.
1554                  */
1555
1556                 if (nmb_name_equal(&called, &smbservername)) {
1557
1558                         /*
1559                          * The name used was *SMBSERVER, don't bother with another name.
1560                          */
1561
1562                         DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
1563 with error %s.\n", desthost, cli_errstr(cli) ));
1564                         return False;
1565                 }
1566
1567                 /*
1568                  * We need to close the connection here but can't call cli_shutdown as
1569                  * will free an allocated cli struct. cli_close_connection was invented
1570                  * for this purpose. JRA. Based on work by "Kim R. Pedersen" <krp@filanet.dk>.
1571                  */
1572
1573                 cli_close_connection(cli);
1574
1575                 if (!cli_initialise(cli) ||
1576                                 !cli_connect(cli, desthost, pdest_ip) ||
1577                                 !cli_session_request(cli, &calling, &smbservername)) {
1578                         DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
1579 name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) ));
1580                         return False;
1581                 }
1582         }
1583
1584         return True;
1585 }
1586
1587
1588
1589
1590
1591 /****************************************************************************
1592  Send an old style tcon.
1593 ****************************************************************************/
1594 NTSTATUS cli_raw_tcon(struct cli_state *cli, 
1595                       const char *service, const char *pass, const char *dev,
1596                       uint16 *max_xmit, uint16 *tid)
1597 {
1598         char *p;
1599
1600         if (!lp_client_plaintext_auth() && (*pass)) {
1601                 DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'"
1602                           " is disabled\n"));
1603                 return NT_STATUS_ACCESS_DENIED;
1604         }
1605
1606         memset(cli->outbuf,'\0',smb_size);
1607         memset(cli->inbuf,'\0',smb_size);
1608
1609         set_message(cli->outbuf, 0, 0, True);
1610         SCVAL(cli->outbuf,smb_com,SMBtcon);
1611         cli_setup_packet(cli);
1612
1613         p = smb_buf(cli->outbuf);
1614         *p++ = 4; p += clistr_push(cli, p, service, -1, STR_TERMINATE | STR_NOALIGN);
1615         *p++ = 4; p += clistr_push(cli, p, pass, -1, STR_TERMINATE | STR_NOALIGN);
1616         *p++ = 4; p += clistr_push(cli, p, dev, -1, STR_TERMINATE | STR_NOALIGN);
1617
1618         cli_setup_bcc(cli, p);
1619
1620         cli_send_smb(cli);
1621         if (!cli_receive_smb(cli)) {
1622                 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1623         }
1624
1625         if (cli_is_error(cli)) {
1626                 return cli_nt_error(cli);
1627         }
1628
1629         *max_xmit = SVAL(cli->inbuf, smb_vwv0);
1630         *tid = SVAL(cli->inbuf, smb_vwv1);
1631
1632         return NT_STATUS_OK;
1633 }
1634
1635 /* Return a cli_state pointing at the IPC$ share for the given server */
1636
1637 struct cli_state *get_ipc_connect(char *server, struct in_addr *server_ip,
1638                                          struct user_auth_info *user_info)
1639 {
1640         struct cli_state *cli;
1641         pstring myname;
1642         NTSTATUS nt_status;
1643
1644         get_myname(myname);
1645         
1646         nt_status = cli_full_connection(&cli, myname, server, server_ip, 0, "IPC$", "IPC", 
1647                                         user_info->username, lp_workgroup(), user_info->password, 
1648                                         CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK, Undefined, NULL);
1649
1650         if (NT_STATUS_IS_OK(nt_status)) {
1651                 return cli;
1652         } else if (is_ipaddress(server)) {
1653             /* windows 9* needs a correct NMB name for connections */
1654             fstring remote_name;
1655
1656             if (name_status_find("*", 0, 0, *server_ip, remote_name)) {
1657                 cli = get_ipc_connect(remote_name, server_ip, user_info);
1658                 if (cli)
1659                     return cli;
1660             }
1661         }
1662         return NULL;
1663 }
1664
1665 /*
1666  * Given the IP address of a master browser on the network, return its
1667  * workgroup and connect to it.
1668  *
1669  * This function is provided to allow additional processing beyond what
1670  * get_ipc_connect_master_ip_bcast() does, e.g. to retrieve the list of master
1671  * browsers and obtain each master browsers' list of domains (in case the
1672  * first master browser is recently on the network and has not yet
1673  * synchronized with other master browsers and therefore does not yet have the
1674  * entire network browse list)
1675  */
1676
1677 struct cli_state *get_ipc_connect_master_ip(struct ip_service * mb_ip, pstring workgroup, struct user_auth_info *user_info)
1678 {
1679         static fstring name;
1680         struct cli_state *cli;
1681         struct in_addr server_ip; 
1682
1683         DEBUG(99, ("Looking up name of master browser %s\n",
1684                    inet_ntoa(mb_ip->ip)));
1685
1686         /*
1687          * Do a name status query to find out the name of the master browser.
1688          * We use <01><02>__MSBROWSE__<02>#01 if *#00 fails because a domain
1689          * master browser will not respond to a wildcard query (or, at least,
1690          * an NT4 server acting as the domain master browser will not).
1691          *
1692          * We might be able to use ONLY the query on MSBROWSE, but that's not
1693          * yet been tested with all Windows versions, so until it is, leave
1694          * the original wildcard query as the first choice and fall back to
1695          * MSBROWSE if the wildcard query fails.
1696          */
1697         if (!name_status_find("*", 0, 0x1d, mb_ip->ip, name) &&
1698             !name_status_find(MSBROWSE, 1, 0x1d, mb_ip->ip, name)) {
1699
1700                 DEBUG(99, ("Could not retrieve name status for %s\n",
1701                            inet_ntoa(mb_ip->ip)));
1702                 return NULL;
1703         }
1704
1705         if (!find_master_ip(name, &server_ip)) {
1706                 DEBUG(99, ("Could not find master ip for %s\n", name));
1707                 return NULL;
1708         }
1709
1710                 pstrcpy(workgroup, name);
1711
1712                 DEBUG(4, ("found master browser %s, %s\n", 
1713                   name, inet_ntoa(mb_ip->ip)));
1714
1715                 cli = get_ipc_connect(inet_ntoa(server_ip), &server_ip, user_info);
1716
1717                 return cli;
1718     
1719 }
1720
1721 /*
1722  * Return the IP address and workgroup of a master browser on the network, and
1723  * connect to it.
1724  */
1725
1726 struct cli_state *get_ipc_connect_master_ip_bcast(pstring workgroup, struct user_auth_info *user_info)
1727 {
1728         struct ip_service *ip_list;
1729         struct cli_state *cli;
1730         int i, count;
1731
1732         DEBUG(99, ("Do broadcast lookup for workgroups on local network\n"));
1733
1734         /* Go looking for workgroups by broadcasting on the local network */ 
1735
1736         if (!name_resolve_bcast(MSBROWSE, 1, &ip_list, &count)) {
1737                 DEBUG(99, ("No master browsers responded\n"));
1738                 return False;
1739         }
1740
1741         for (i = 0; i < count; i++) {
1742             DEBUG(99, ("Found master browser %s\n", inet_ntoa(ip_list[i].ip)));
1743
1744             cli = get_ipc_connect_master_ip(&ip_list[i], workgroup, user_info);
1745             if (cli)
1746                     return(cli);
1747         }
1748
1749         return NULL;
1750 }