when using non-encrypted password ignore the ntpass variable to
[kai/samba.git] / source3 / libsmb / cliconnect.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 3.0
4    client connect/disconnect routines
5    Copyright (C) Andrew Tridgell 1994-1998
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
27 static const struct {
28     int prot;
29     const char *name;
30   }
31 prots[] = 
32     {
33       {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"},
34       {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
35       {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
36       {PROTOCOL_LANMAN1,"LANMAN1.0"},
37       {PROTOCOL_LANMAN2,"LM1.2X002"},
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 /****************************************************************************
46 do an old lanman2 style session setup
47 ****************************************************************************/
48 static BOOL cli_session_setup_lanman2(struct cli_state *cli, char *user, 
49                                       char *pass, int passlen)
50 {
51         fstring pword;
52         char *p;
53
54         if (passlen > sizeof(pword)-1) {
55                 return False;
56         }
57
58         /* if in share level security then don't send a password now */
59         if (!(cli->sec_mode & 1)) {
60                 passlen = 0;
61         }
62
63         if (passlen > 0 && (cli->sec_mode & 2) && passlen != 24) {
64                 /* Encrypted mode needed, and non encrypted password supplied. */
65                 passlen = 24;
66                 clistr_push(cli, pword, pass, -1, STR_TERMINATE);
67                 SMBencrypt((uchar *)pword,cli->secblob.data,(uchar *)pword);
68         } else if ((cli->sec_mode & 2) && passlen == 24) {
69                 /* Encrypted mode needed, and encrypted password supplied. */
70                 memcpy(pword, pass, passlen);
71         } else if (passlen > 0) {
72                 /* Plaintext mode needed, assume plaintext supplied. */
73                 passlen = clistr_push(cli, pword, pass, -1, STR_TERMINATE);
74         }
75
76         /* send a session setup command */
77         memset(cli->outbuf,'\0',smb_size);
78         set_message(cli->outbuf,10, 0, True);
79         CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
80         cli_setup_packet(cli);
81         
82         CVAL(cli->outbuf,smb_vwv0) = 0xFF;
83         SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
84         SSVAL(cli->outbuf,smb_vwv3,2);
85         SSVAL(cli->outbuf,smb_vwv4,1);
86         SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
87         SSVAL(cli->outbuf,smb_vwv7,passlen);
88
89         p = smb_buf(cli->outbuf);
90         memcpy(p,pword,passlen);
91         p += passlen;
92         p += clistr_push(cli, p, user, -1, STR_TERMINATE);
93         cli_setup_bcc(cli, p);
94
95         cli_send_smb(cli);
96         if (!cli_receive_smb(cli))
97                 return False;
98
99         show_msg(cli->inbuf);
100
101         if (cli_is_error(cli)) {
102                 return False;
103         }
104         
105         /* use the returned vuid from now on */
106         cli->vuid = SVAL(cli->inbuf,smb_uid);   
107         fstrcpy(cli->user_name, user);
108
109         return True;
110 }
111
112
113 /****************************************************************************
114 work out suitable capabilities to offer the server
115 ****************************************************************************/
116 static uint32 cli_session_setup_capabilities(struct cli_state *cli)
117 {
118         uint32 capabilities = CAP_NT_SMBS;
119
120         if (!cli->force_dos_errors) {
121                 capabilities |= CAP_STATUS32;
122         }
123
124         if (cli->use_level_II_oplocks) {
125                 capabilities |= CAP_LEVEL_II_OPLOCKS;
126         }
127
128         if (cli->capabilities & CAP_UNICODE) {
129                 capabilities |= CAP_UNICODE;
130         }
131
132         return capabilities;
133 }
134
135
136 /****************************************************************************
137 do a NT1 guest session setup
138 ****************************************************************************/
139 static BOOL cli_session_setup_guest(struct cli_state *cli)
140 {
141         char *p;
142         uint32 capabilities = cli_session_setup_capabilities(cli);
143
144         set_message(cli->outbuf,13,0,True);
145         CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
146         cli_setup_packet(cli);
147                         
148         CVAL(cli->outbuf,smb_vwv0) = 0xFF;
149         SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
150         SSVAL(cli->outbuf,smb_vwv3,2);
151         SSVAL(cli->outbuf,smb_vwv4,cli->pid);
152         SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
153         SSVAL(cli->outbuf,smb_vwv7,0);
154         SSVAL(cli->outbuf,smb_vwv8,0);
155         SIVAL(cli->outbuf,smb_vwv11,capabilities); 
156         p = smb_buf(cli->outbuf);
157         p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* username */
158         p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* workgroup */
159         p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
160         p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
161         cli_setup_bcc(cli, p);
162
163         cli_send_smb(cli);
164         if (!cli_receive_smb(cli))
165               return False;
166         
167         show_msg(cli->inbuf);
168         
169         if (cli_is_error(cli)) {
170                 return False;
171         }
172
173         cli->vuid = SVAL(cli->inbuf,smb_uid);
174
175         p = smb_buf(cli->inbuf);
176         p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
177         p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
178         p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
179
180         fstrcpy(cli->user_name, "");
181
182         return True;
183 }
184
185
186 /****************************************************************************
187 do a NT1 plaintext session setup
188 ****************************************************************************/
189 static BOOL cli_session_setup_plaintext(struct cli_state *cli, char *user, 
190                                         char *pass, char *workgroup)
191 {
192         uint32 capabilities = cli_session_setup_capabilities(cli);
193         fstring pword;
194         int passlen;
195         char *p;
196
197         passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE|STR_ASCII);
198
199         set_message(cli->outbuf,13,0,True);
200         CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
201         cli_setup_packet(cli);
202                         
203         CVAL(cli->outbuf,smb_vwv0) = 0xFF;
204         SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
205         SSVAL(cli->outbuf,smb_vwv3,2);
206         SSVAL(cli->outbuf,smb_vwv4,cli->pid);
207         SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
208         SSVAL(cli->outbuf,smb_vwv7,passlen);
209         SSVAL(cli->outbuf,smb_vwv8,0);
210         SIVAL(cli->outbuf,smb_vwv11,capabilities); 
211         p = smb_buf(cli->outbuf);
212         memcpy(p, pword, passlen);
213         p += passlen;
214         p += clistr_push(cli, p, user, -1, STR_TERMINATE); /* username */
215         p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE); /* workgroup */
216         p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
217         p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
218         cli_setup_bcc(cli, p);
219
220         cli_send_smb(cli);
221         if (!cli_receive_smb(cli))
222               return False;
223         
224         show_msg(cli->inbuf);
225         
226         if (cli_is_error(cli)) {
227                 return False;
228         }
229
230         cli->vuid = SVAL(cli->inbuf,smb_uid);
231         p = smb_buf(cli->inbuf);
232         p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
233         p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
234         p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
235         fstrcpy(cli->user_name, user);
236
237         return True;
238 }
239
240
241 /****************************************************************************
242 do a NT1 NTLM/LM encrypted session setup
243 ****************************************************************************/
244 static BOOL cli_session_setup_nt1(struct cli_state *cli, char *user, 
245                                   char *pass, int passlen,
246                                   char *ntpass, int ntpasslen,
247                                   char *workgroup)
248 {
249         uint32 capabilities = cli_session_setup_capabilities(cli);
250         fstring pword, ntpword;
251         char *p;
252
253         if (passlen > sizeof(pword)-1 || ntpasslen > sizeof(ntpword)-1) {
254                 return False;
255         }
256
257         if (passlen != 24) {
258                 /* non encrypted password supplied. Ignore ntpass. */
259                 passlen = 24;
260                 ntpasslen = 24;
261                 clistr_push(cli, pword, 
262                             pass?pass:"", sizeof(pword), STR_TERMINATE|STR_ASCII);
263                 clistr_push(cli, ntpword, 
264                             pass?pass:"", sizeof(ntpword), STR_TERMINATE|STR_ASCII);
265                 SMBencrypt((uchar *)pword,cli->secblob.data,(uchar *)pword);
266                 SMBNTencrypt((uchar *)ntpword,cli->secblob.data,(uchar *)ntpword);
267         } else {
268                 memcpy(pword, pass, passlen);
269                 memcpy(ntpword, ntpass, ntpasslen);
270         }
271
272         /* send a session setup command */
273         memset(cli->outbuf,'\0',smb_size);
274
275         set_message(cli->outbuf,13,0,True);
276         CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
277         cli_setup_packet(cli);
278                         
279         CVAL(cli->outbuf,smb_vwv0) = 0xFF;
280         SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
281         SSVAL(cli->outbuf,smb_vwv3,2);
282         SSVAL(cli->outbuf,smb_vwv4,cli->pid);
283         SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
284         SSVAL(cli->outbuf,smb_vwv7,passlen);
285         SSVAL(cli->outbuf,smb_vwv8,ntpasslen);
286         SIVAL(cli->outbuf,smb_vwv11,capabilities); 
287         p = smb_buf(cli->outbuf);
288         memcpy(p,pword,passlen); p += passlen;
289         memcpy(p,ntpword,ntpasslen); p += ntpasslen;
290         p += clistr_push(cli, p, user, -1, STR_TERMINATE|STR_UPPER);
291         p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
292         p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
293         p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
294         cli_setup_bcc(cli, p);
295
296         cli_send_smb(cli);
297         if (!cli_receive_smb(cli))
298                 return False;
299
300         show_msg(cli->inbuf);
301
302         if (cli_is_error(cli)) {
303                 return False;
304         }
305         
306         /* use the returned vuid from now on */
307         cli->vuid = SVAL(cli->inbuf,smb_uid);
308         
309         p = smb_buf(cli->inbuf);
310         p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
311         p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
312         p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
313
314         fstrcpy(cli->user_name, user);
315
316         return True;
317 }
318
319
320 /****************************************************************************
321 send a extended security session setup blob, returning a reply blob
322 ****************************************************************************/
323 static DATA_BLOB cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob)
324 {
325         uint32 capabilities = cli_session_setup_capabilities(cli);
326         char *p;
327         DATA_BLOB blob2;
328
329         blob2 = data_blob(NULL, 0);
330
331         capabilities |= CAP_EXTENDED_SECURITY;
332
333         /* send a session setup command */
334         memset(cli->outbuf,'\0',smb_size);
335
336         set_message(cli->outbuf,12,0,True);
337         CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
338         cli_setup_packet(cli);
339                         
340         CVAL(cli->outbuf,smb_vwv0) = 0xFF;
341         SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
342         SSVAL(cli->outbuf,smb_vwv3,2);
343         SSVAL(cli->outbuf,smb_vwv4,1);
344         SIVAL(cli->outbuf,smb_vwv5,0);
345         SSVAL(cli->outbuf,smb_vwv7,blob.length);
346         SIVAL(cli->outbuf,smb_vwv10,capabilities); 
347         p = smb_buf(cli->outbuf);
348         memcpy(p, blob.data, blob.length);
349         p += blob.length;
350         p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
351         p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
352         cli_setup_bcc(cli, p);
353
354         cli_send_smb(cli);
355         if (!cli_receive_smb(cli))
356                 return blob2;
357
358         show_msg(cli->inbuf);
359
360         if (cli_is_error(cli) && !NT_STATUS_EQUAL(cli_nt_error(cli),
361                                                   NT_STATUS_MORE_PROCESSING_REQUIRED)) {
362                 return blob2;
363         }
364         
365         /* use the returned vuid from now on */
366         cli->vuid = SVAL(cli->inbuf,smb_uid);
367         
368         p = smb_buf(cli->inbuf);
369
370         blob2 = data_blob(p, SVAL(cli->inbuf, smb_vwv3));
371
372         p += blob2.length;
373         p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
374         p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
375         p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
376
377         return blob2;
378 }
379
380
381 #ifdef HAVE_KRB5
382 /****************************************************************************
383 do a spnego/kerberos encrypted session setup
384 ****************************************************************************/
385 static BOOL cli_session_setup_kerberos(struct cli_state *cli, char *principal, char *workgroup)
386 {
387         DATA_BLOB blob2, negTokenTarg;
388
389         DEBUG(2,("Doing kerberos session setup\n"));
390
391         /* generate the encapsulated kerberos5 ticket */
392         negTokenTarg = spnego_gen_negTokenTarg(cli, principal);
393
394         if (!negTokenTarg.data) return False;
395
396 #if 0
397         file_save("negTokenTarg.dat", negTokenTarg.data, negTokenTarg.length);
398 #endif
399
400         blob2 = cli_session_setup_blob(cli, negTokenTarg);
401
402         /* we don't need this blob for kerberos */
403         data_blob_free(&blob2);
404
405         data_blob_free(&negTokenTarg);
406
407         return !cli_is_error(cli);
408 }
409 #endif
410
411 /****************************************************************************
412 do a spnego/NTLMSSP encrypted session setup
413 ****************************************************************************/
414 static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, char *user, 
415                                       char *pass, char *workgroup)
416 {
417         const char *mechs[] = {OID_NTLMSSP, NULL};
418         DATA_BLOB msg1;
419         DATA_BLOB blob, chal1, chal2, auth;
420         uint8 challenge[8];
421         uint8 nthash[24], lmhash[24], sess_key[16];
422         uint32 neg_flags;
423
424         neg_flags = NTLMSSP_NEGOTIATE_UNICODE | 
425                 NTLMSSP_NEGOTIATE_LM_KEY | 
426                 NTLMSSP_NEGOTIATE_NTLM;
427
428         memset(sess_key, 0, 16);
429
430         /* generate the ntlmssp negotiate packet */
431         msrpc_gen(&blob, "CddB",
432                   "NTLMSSP",
433                   NTLMSSP_NEGOTIATE,
434                   neg_flags,
435                   sess_key, 16);
436
437         /* and wrap it in a SPNEGO wrapper */
438         msg1 = gen_negTokenTarg(mechs, blob);
439         data_blob_free(&blob);
440
441         /* now send that blob on its way */
442         blob = cli_session_setup_blob(cli, msg1);
443
444         data_blob_free(&msg1);
445
446         if (!NT_STATUS_EQUAL(cli_nt_error(cli), NT_STATUS_MORE_PROCESSING_REQUIRED)) {
447                 return False;
448         }
449
450 #if 0
451         file_save("chal.dat", blob.data, blob.length);
452 #endif
453
454         /* the server gives us back two challenges */
455         if (!spnego_parse_challenge(blob, &chal1, &chal2)) {
456                 DEBUG(3,("Failed to parse challenges\n"));
457                 return False;
458         }
459
460         data_blob_free(&blob);
461
462         /* encrypt the password with the challenge */
463         memcpy(challenge, chal1.data + 24, 8);
464         SMBencrypt((unsigned char *)pass, challenge,lmhash);
465         SMBNTencrypt((unsigned char *)pass, challenge,nthash);
466
467 #if 0
468         file_save("nthash.dat", nthash, 24);
469         file_save("lmhash.dat", lmhash, 24);
470         file_save("chal1.dat", chal1.data, chal1.length);
471 #endif
472
473         data_blob_free(&chal1);
474         data_blob_free(&chal2);
475
476         /* this generates the actual auth packet */
477         msrpc_gen(&blob, "CdBBUUUBd", 
478                   "NTLMSSP", 
479                   NTLMSSP_AUTH, 
480                   lmhash, 24,
481                   nthash, 24,
482                   workgroup, 
483                   user, 
484                   cli->calling.name,
485                   sess_key, 16,
486                   neg_flags);
487
488         /* wrap it in SPNEGO */
489         auth = spnego_gen_auth(blob);
490
491         data_blob_free(&blob);
492
493         /* now send the auth packet and we should be done */
494         blob = cli_session_setup_blob(cli, auth);
495
496         data_blob_free(&auth);
497         data_blob_free(&blob);
498
499         return !cli_is_error(cli);
500 }
501
502
503 /****************************************************************************
504 do a spnego encrypted session setup
505 ****************************************************************************/
506 static BOOL cli_session_setup_spnego(struct cli_state *cli, char *user, 
507                                      char *pass, char *workgroup)
508 {
509         char *principal;
510         char *OIDs[ASN1_MAX_OIDS];
511         uint8 guid[16];
512         int i;
513         BOOL got_kerberos_mechanism = False;
514
515         DEBUG(2,("Doing spnego session setup (blob length=%d)\n", cli->secblob.length));
516
517         /* the server might not even do spnego */
518         if (cli->secblob.length == 16) {
519                 DEBUG(3,("server didn't supply a full spnego negprot\n"));
520                 goto ntlmssp;
521         }
522
523 #if 0
524         file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
525 #endif
526
527         /* the server sent us the first part of the SPNEGO exchange in the negprot 
528            reply */
529         if (!spnego_parse_negTokenInit(cli->secblob, guid, OIDs, &principal)) {
530                 return False;
531         }
532
533         /* make sure the server understands kerberos */
534         for (i=0;OIDs[i];i++) {
535                 DEBUG(3,("got OID=%s\n", OIDs[i]));
536                 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
537                     strcmp(OIDs[i], OID_KERBEROS5) == 0) {
538                         got_kerberos_mechanism = True;
539                 }
540                 free(OIDs[i]);
541         }
542         DEBUG(3,("got principal=%s\n", principal));
543
544         fstrcpy(cli->user_name, user);
545
546 #ifdef HAVE_KRB5
547         if (got_kerberos_mechanism && cli->use_kerberos) {
548                 return cli_session_setup_kerberos(cli, principal, workgroup);
549         }
550 #endif
551
552         free(principal);
553
554 ntlmssp:
555
556         return cli_session_setup_ntlmssp(cli, user, pass, workgroup);
557 }
558
559
560 /****************************************************************************
561  Send a session setup. The username and workgroup is in UNIX character
562  format and must be converted to DOS codepage format before sending. If the
563  password is in plaintext, the same should be done.
564 ****************************************************************************/
565 BOOL cli_session_setup(struct cli_state *cli, 
566                        char *user, 
567                        char *pass, int passlen,
568                        char *ntpass, int ntpasslen,
569                        char *workgroup)
570 {
571         char *p;
572         fstring user2;
573
574         /* allow for workgroups as part of the username */
575         fstrcpy(user2, user);
576         if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/'))) {
577                 *p = 0;
578                 user = p+1;
579                 workgroup = user2;
580         }
581
582         if (cli->protocol < PROTOCOL_LANMAN1)
583                 return True;
584
585         /* now work out what sort of session setup we are going to
586            do. I have split this into separate functions to make the
587            flow a bit easier to understand (tridge) */
588
589         /* if its an older server then we have to use the older request format */
590         if (cli->protocol < PROTOCOL_NT1) {
591                 return cli_session_setup_lanman2(cli, user, pass, passlen);
592         }
593
594         /* if no user is supplied then we have to do an anonymous connection.
595            passwords are ignored */
596         if (!user || !*user) {
597                 return cli_session_setup_guest(cli);
598         }
599
600         /* if the server is share level then send a plaintext null
601            password at this point. The password is sent in the tree
602            connect */
603         if ((cli->sec_mode & 1) == 0) {
604                 return cli_session_setup_plaintext(cli, user, "", workgroup);
605         }
606
607         /* if the server doesn't support encryption then we have to use plaintext. The 
608            second password is ignored */
609         if ((cli->sec_mode & 2) == 0) {
610                 return cli_session_setup_plaintext(cli, user, pass, workgroup);
611         }
612
613         /* if the server supports extended security then use SPNEGO */
614         if (cli->capabilities & CAP_EXTENDED_SECURITY) {
615                 return cli_session_setup_spnego(cli, user, pass, workgroup);
616         }
617
618         /* otherwise do a NT1 style session setup */
619         return cli_session_setup_nt1(cli, user, 
620                                      pass, passlen, ntpass, ntpasslen,
621                                      workgroup);        
622 }
623
624 /****************************************************************************
625  Send a uloggoff.
626 *****************************************************************************/
627
628 BOOL cli_ulogoff(struct cli_state *cli)
629 {
630         memset(cli->outbuf,'\0',smb_size);
631         set_message(cli->outbuf,2,0,True);
632         CVAL(cli->outbuf,smb_com) = SMBulogoffX;
633         cli_setup_packet(cli);
634         SSVAL(cli->outbuf,smb_vwv0,0xFF);
635         SSVAL(cli->outbuf,smb_vwv2,0);  /* no additional info */
636
637         cli_send_smb(cli);
638         if (!cli_receive_smb(cli))
639                 return False;
640
641         return !cli_is_error(cli);
642 }
643
644 /****************************************************************************
645 send a tconX
646 ****************************************************************************/
647 BOOL cli_send_tconX(struct cli_state *cli, 
648                     const char *share, const char *dev, const char *pass, int passlen)
649 {
650         fstring fullshare, pword, dos_pword;
651         char *p;
652         memset(cli->outbuf,'\0',smb_size);
653         memset(cli->inbuf,'\0',smb_size);
654
655         fstrcpy(cli->share, share);
656
657         /* in user level security don't send a password now */
658         if (cli->sec_mode & 1) {
659                 passlen = 1;
660                 pass = "";
661         }
662
663         if ((cli->sec_mode & 2) && *pass && passlen != 24) {
664                 /*
665                  * Non-encrypted passwords - convert to DOS codepage before encryption.
666                  */
667                 passlen = 24;
668                 clistr_push(cli, dos_pword, pass, -1, STR_TERMINATE);
669                 SMBencrypt((uchar *)dos_pword,cli->secblob.data,(uchar *)pword);
670         } else {
671                 if((cli->sec_mode & 3) == 0) {
672                         /*
673                          * Non-encrypted passwords - convert to DOS codepage before using.
674                          */
675                         passlen = clistr_push(cli, pword, pass, -1, STR_TERMINATE);
676                 } else {
677                         memcpy(pword, pass, passlen);
678                 }
679         }
680
681         if (cli->port == 445) {
682                 slprintf(fullshare, sizeof(fullshare)-1,
683                          "%s", share);
684         } else {
685                 slprintf(fullshare, sizeof(fullshare)-1,
686                          "\\\\%s\\%s", cli->desthost, share);
687         }
688
689         set_message(cli->outbuf,4, 0, True);
690         CVAL(cli->outbuf,smb_com) = SMBtconX;
691         cli_setup_packet(cli);
692
693         SSVAL(cli->outbuf,smb_vwv0,0xFF);
694         SSVAL(cli->outbuf,smb_vwv3,passlen);
695
696         p = smb_buf(cli->outbuf);
697         memcpy(p,pword,passlen);
698         p += passlen;
699         p += clistr_push(cli, p, fullshare, -1, STR_TERMINATE |STR_UPPER);
700         fstrcpy(p, dev); p += strlen(dev)+1;
701
702         cli_setup_bcc(cli, p);
703
704         cli_send_smb(cli);
705         if (!cli_receive_smb(cli))
706                 return False;
707
708         if (cli_is_error(cli)) {
709                 return False;
710         }
711
712         clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE|STR_ASCII);
713
714         if (strcasecmp(share,"IPC$")==0) {
715                 fstrcpy(cli->dev, "IPC");
716         }
717
718         if (cli->protocol >= PROTOCOL_NT1 &&
719             smb_buflen(cli->inbuf) == 3) {
720                 /* almost certainly win95 - enable bug fixes */
721                 cli->win95 = True;
722         }
723
724         cli->cnum = SVAL(cli->inbuf,smb_tid);
725         return True;
726 }
727
728
729 /****************************************************************************
730 send a tree disconnect
731 ****************************************************************************/
732 BOOL cli_tdis(struct cli_state *cli)
733 {
734         memset(cli->outbuf,'\0',smb_size);
735         set_message(cli->outbuf,0,0,True);
736         CVAL(cli->outbuf,smb_com) = SMBtdis;
737         SSVAL(cli->outbuf,smb_tid,cli->cnum);
738         cli_setup_packet(cli);
739         
740         cli_send_smb(cli);
741         if (!cli_receive_smb(cli))
742                 return False;
743         
744         return !cli_is_error(cli);
745 }
746
747
748 /****************************************************************************
749 send a negprot command
750 ****************************************************************************/
751 void cli_negprot_send(struct cli_state *cli)
752 {
753         char *p;
754         int numprots;
755
756         memset(cli->outbuf,'\0',smb_size);
757
758         /* setup the protocol strings */
759         set_message(cli->outbuf,0,0,True);
760
761         p = smb_buf(cli->outbuf);
762         for (numprots=0;
763              prots[numprots].name && prots[numprots].prot<=cli->protocol;
764              numprots++) {
765                 *p++ = 2;
766                 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
767         }
768
769         CVAL(cli->outbuf,smb_com) = SMBnegprot;
770         cli_setup_bcc(cli, p);
771         cli_setup_packet(cli);
772
773         CVAL(smb_buf(cli->outbuf),0) = 2;
774
775         cli_send_smb(cli);
776 }
777
778
779 /****************************************************************************
780 send a negprot command
781 ****************************************************************************/
782 BOOL cli_negprot(struct cli_state *cli)
783 {
784         char *p;
785         int numprots;
786         int plength;
787
788         memset(cli->outbuf,'\0',smb_size);
789
790         /* setup the protocol strings */
791         for (plength=0,numprots=0;
792              prots[numprots].name && prots[numprots].prot<=cli->protocol;
793              numprots++)
794                 plength += strlen(prots[numprots].name)+2;
795     
796         set_message(cli->outbuf,0,plength,True);
797
798         p = smb_buf(cli->outbuf);
799         for (numprots=0;
800              prots[numprots].name && prots[numprots].prot<=cli->protocol;
801              numprots++) {
802                 *p++ = 2;
803                 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
804         }
805
806         CVAL(cli->outbuf,smb_com) = SMBnegprot;
807         cli_setup_packet(cli);
808
809         CVAL(smb_buf(cli->outbuf),0) = 2;
810
811         cli_send_smb(cli);
812         if (!cli_receive_smb(cli))
813                 return False;
814
815         show_msg(cli->inbuf);
816
817         if (cli_is_error(cli) ||
818             ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
819                 return(False);
820         }
821
822         cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
823
824         if (cli->protocol >= PROTOCOL_NT1) {    
825                 /* NT protocol */
826                 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
827                 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
828                 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
829                 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
830                 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1);
831                 cli->serverzone *= 60;
832                 /* this time arrives in real GMT */
833                 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
834                 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
835                 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
836                 if (cli->capabilities & CAP_RAW_MODE) {
837                         cli->readbraw_supported = True;
838                         cli->writebraw_supported = True;      
839                 }
840                 /* work out if they sent us a workgroup */
841                 if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
842                     smb_buflen(cli->inbuf) > 8) {
843                         clistr_pull(cli, cli->server_domain, 
844                                     smb_buf(cli->inbuf)+8, sizeof(cli->server_domain),
845                                     smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
846                 }
847         } else if (cli->protocol >= PROTOCOL_LANMAN1) {
848                 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
849                 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
850                 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
851                 cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
852                 cli->serverzone *= 60;
853                 /* this time is converted to GMT by make_unix_date */
854                 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
855                 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
856                 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
857                 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
858         } else {
859                 /* the old core protocol */
860                 cli->sec_mode = 0;
861                 cli->serverzone = TimeDiff(time(NULL));
862         }
863
864         cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
865
866         /* a way to force ascii SMB */
867         if (getenv("CLI_FORCE_ASCII")) {
868                 cli->capabilities &= ~CAP_UNICODE;
869         }
870
871         return True;
872 }
873
874
875 /****************************************************************************
876   send a session request.  see rfc1002.txt 4.3 and 4.3.2
877 ****************************************************************************/
878 BOOL cli_session_request(struct cli_state *cli,
879                          struct nmb_name *calling, struct nmb_name *called)
880 {
881         char *p;
882         int len = 4;
883         extern pstring user_socket_options;
884
885         /* 445 doesn't have session request */
886         if (cli->port == 445) return True;
887
888         /* send a session request (RFC 1002) */
889         memcpy(&(cli->calling), calling, sizeof(*calling));
890         memcpy(&(cli->called ), called , sizeof(*called ));
891   
892         /* put in the destination name */
893         p = cli->outbuf+len;
894         name_mangle(cli->called .name, p, cli->called .name_type);
895         len += name_len(p);
896
897         /* and my name */
898         p = cli->outbuf+len;
899         name_mangle(cli->calling.name, p, cli->calling.name_type);
900         len += name_len(p);
901
902         /* setup the packet length */
903         _smb_setlen(cli->outbuf,len);
904         CVAL(cli->outbuf,0) = 0x81;
905
906 #ifdef WITH_SSL
907 retry:
908 #endif /* WITH_SSL */
909
910         cli_send_smb(cli);
911         DEBUG(5,("Sent session request\n"));
912
913         if (!cli_receive_smb(cli))
914                 return False;
915
916         if (CVAL(cli->inbuf,0) == 0x84) {
917                 /* C. Hoch  9/14/95 Start */
918                 /* For information, here is the response structure.
919                  * We do the byte-twiddling to for portability.
920                 struct RetargetResponse{
921                 unsigned char type;
922                 unsigned char flags;
923                 int16 length;
924                 int32 ip_addr;
925                 int16 port;
926                 };
927                 */
928                 int port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
929                 /* SESSION RETARGET */
930                 putip((char *)&cli->dest_ip,cli->inbuf+4);
931
932                 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
933                 if (cli->fd == -1)
934                         return False;
935
936                 DEBUG(3,("Retargeted\n"));
937
938                 set_socket_options(cli->fd,user_socket_options);
939
940                 /* Try again */
941                 {
942                         static int depth;
943                         BOOL ret;
944                         if (depth > 4) {
945                                 DEBUG(0,("Retarget recursion - failing\n"));
946                                 return False;
947                         }
948                         depth++;
949                         ret = cli_session_request(cli, calling, called);
950                         depth--;
951                         return ret;
952                 }
953         } /* C. Hoch 9/14/95 End */
954
955 #ifdef WITH_SSL
956     if (CVAL(cli->inbuf,0) == 0x83 && CVAL(cli->inbuf,4) == 0x8e){ /* use ssl */
957         if (!sslutil_fd_is_ssl(cli->fd)){
958             if (sslutil_connect(cli->fd) == 0)
959                 goto retry;
960         }
961     }
962 #endif /* WITH_SSL */
963
964         if (CVAL(cli->inbuf,0) != 0x82) {
965                 /* This is the wrong place to put the error... JRA. */
966                 cli->rap_error = CVAL(cli->inbuf,4);
967                 return False;
968         }
969         return(True);
970 }
971
972 /****************************************************************************
973 open the client sockets
974 ****************************************************************************/
975 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
976 {
977         extern pstring user_socket_options;
978
979         fstrcpy(cli->desthost, host);
980         
981         if (!ip || is_zero_ip(*ip)) {
982                 if (!resolve_name( cli->desthost, &cli->dest_ip, 0x20)) {
983                         return False;
984                 }
985                 if (ip) *ip = cli->dest_ip;
986         } else {
987                 cli->dest_ip = *ip;
988         }
989
990         if (getenv("LIBSMB_PROG")) {
991                 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
992         } else {
993                 /* try 445 first, then 139 */
994                 int port = cli->port?cli->port:445;
995                 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, 
996                                           port, cli->timeout);
997                 if (cli->fd == -1 && cli->port == 0) {
998                         port = 139;
999                         cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, 
1000                                                   port, cli->timeout);
1001                 }
1002                 if (cli->fd != -1) cli->port = port;
1003         }
1004         if (cli->fd == -1) {
1005                 DEBUG(1,("Error connecting to %s (%s)\n",
1006                          inet_ntoa(*ip),strerror(errno)));
1007                 return False;
1008         }
1009
1010         set_socket_options(cli->fd,user_socket_options);
1011
1012         return True;
1013 }
1014
1015 /****************************************************************************
1016 establishes a connection right up to doing tconX, password in cache.
1017 ****************************************************************************/
1018 BOOL cli_establish_connection(struct cli_state *cli, 
1019                                 char *dest_host, struct in_addr *dest_ip,
1020                                 struct nmb_name *calling, struct nmb_name *called,
1021                                 char *service, char *service_type,
1022                                 BOOL do_shutdown, BOOL do_tcon)
1023 {
1024         DEBUG(5,("cli_establish_connection: %s connecting to %s (%s) - %s [%s]\n",
1025                           nmb_namestr(calling), nmb_namestr(called), inet_ntoa(*dest_ip),
1026                       cli->user_name, cli->domain));
1027
1028         /* establish connection */
1029
1030         if ((!cli->initialised))
1031         {
1032                 return False;
1033         }
1034
1035         /* cli_establish_connection() can't handle spnego yet. Once we get rid of
1036            pwd_cache and other horrors we can get rid of this */
1037         cli->use_spnego = False;
1038
1039         if (cli->fd == -1)
1040         {
1041                 if (!cli_connect(cli, dest_host, dest_ip))
1042                 {
1043                         DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n",
1044                                           nmb_namestr(called), inet_ntoa(*dest_ip)));
1045                         return False;
1046                 }
1047         }
1048
1049         if (!cli_session_request(cli, calling, called))
1050         {
1051                 DEBUG(1,("failed session request\n"));
1052                 if (do_shutdown)
1053                         cli_shutdown(cli);
1054                 return False;
1055         }
1056
1057         if (!cli_negprot(cli))
1058         {
1059                 DEBUG(1,("failed negprot\n"));
1060                 if (do_shutdown)
1061                         cli_shutdown(cli);
1062                 return False;
1063         }
1064
1065         if (cli->pwd.cleartext || cli->pwd.null_pwd)
1066         {
1067                 fstring passwd;
1068                 int pass_len;
1069
1070                 if (cli->pwd.null_pwd)
1071                 {
1072                         /* attempt null session */
1073                         passwd[0] = 0;
1074                         pass_len = 1;
1075                 }
1076                 else
1077                 {
1078                         /* attempt clear-text session */
1079                         pwd_get_cleartext(&(cli->pwd), passwd);
1080                         pass_len = strlen(passwd);
1081                 }
1082
1083                 /* attempt clear-text session */
1084                 if (!cli_session_setup(cli, cli->user_name,
1085                                passwd, pass_len,
1086                                NULL, 0,
1087                                cli->domain))
1088                 {
1089                         DEBUG(1,("failed session setup\n"));
1090                         if (do_shutdown)
1091                         {
1092                                 cli_shutdown(cli);
1093                         }
1094                         return False;
1095                 }
1096                 if (do_tcon)
1097                 {
1098                         if (!cli_send_tconX(cli, service, service_type,
1099                                             (char*)passwd, strlen(passwd)))
1100                         {
1101                                 DEBUG(1,("failed tcon_X\n"));
1102                                 if (do_shutdown)
1103                                 {
1104                                         cli_shutdown(cli);
1105                                 }
1106                                 return False;
1107                         }
1108                 }
1109         }
1110         else
1111         {
1112                 /* attempt encrypted session */
1113                 unsigned char nt_sess_pwd[24];
1114                 unsigned char lm_sess_pwd[24];
1115
1116                 /* creates (storing a copy of) and then obtains a 24 byte password OWF */
1117                 pwd_make_lm_nt_owf(&(cli->pwd), cli->secblob.data);
1118                 pwd_get_lm_nt_owf(&(cli->pwd), lm_sess_pwd, nt_sess_pwd);
1119
1120                 /* attempt encrypted session */
1121                 if (!cli_session_setup(cli, cli->user_name,
1122                                (char*)lm_sess_pwd, sizeof(lm_sess_pwd),
1123                                (char*)nt_sess_pwd, sizeof(nt_sess_pwd),
1124                                cli->domain))
1125                 {
1126                         DEBUG(1,("failed session setup\n"));
1127                         if (do_shutdown)
1128                               cli_shutdown(cli);
1129                         return False;
1130                 }
1131
1132                 DEBUG(1,("session setup ok\n"));
1133     
1134                 if (*cli->server_domain || *cli->server_os || *cli->server_type)
1135                 {
1136                         DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",
1137                                  cli->server_domain,
1138                                  cli->server_os,
1139                                  cli->server_type));
1140                 }
1141                 
1142                 if (do_tcon)
1143                 {
1144                         if (!cli_send_tconX(cli, service, service_type,
1145                                             (char*)nt_sess_pwd, sizeof(nt_sess_pwd)))
1146                         {
1147                                 DEBUG(1,("failed tcon_X\n"));
1148                                 if (do_shutdown)
1149                                         cli_shutdown(cli);
1150                                 return False;
1151                         }
1152                 }
1153         }
1154
1155         if (do_shutdown)
1156                 cli_shutdown(cli);
1157
1158         return True;
1159 }
1160
1161 /* Initialise client credentials for authenticated pipe access */
1162
1163 static void init_creds(struct ntuser_creds *creds, char* username,
1164                        char* domain, char* password, int pass_len)
1165 {
1166         ZERO_STRUCTP(creds);
1167
1168         pwd_set_cleartext(&creds->pwd, password);
1169
1170         fstrcpy(creds->user_name, username);
1171         fstrcpy(creds->domain, domain);
1172
1173         if (!*username) {
1174                 creds->pwd.null_pwd = True;
1175         }
1176 }
1177
1178 /****************************************************************************
1179 establishes a connection right up to doing tconX, password specified.
1180 ****************************************************************************/
1181 NTSTATUS cli_full_connection(struct cli_state **output_cli, 
1182                              const char *my_name, const char *dest_host, 
1183                              struct in_addr *dest_ip, int port,
1184                              char *service, char *service_type,
1185                              char *user, char *domain, 
1186                              char *password, int pass_len) 
1187 {
1188         struct ntuser_creds creds;
1189         NTSTATUS nt_status;
1190         struct nmb_name calling;
1191         struct nmb_name called;
1192         struct cli_state *cli;
1193         struct in_addr ip;
1194          
1195         make_nmb_name(&calling, my_name, 0x0);
1196         make_nmb_name(&called , dest_host, 0x20);
1197
1198 again:
1199
1200         if (!(cli = cli_initialise(NULL))) {
1201                 return NT_STATUS_NO_MEMORY;
1202         }
1203         
1204         if (cli_set_port(cli, port) != port) {
1205                 return NT_STATUS_UNSUCCESSFUL;
1206         }
1207
1208         ip = *dest_ip;
1209         
1210         DEBUG(3,("Connecting to host=%s share=%s\n\n", 
1211                  dest_host, service));
1212         
1213         if (!cli_connect(cli, dest_host, &ip))
1214         {
1215                 DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n",
1216                          nmb_namestr(&called), inet_ntoa(*dest_ip)));
1217                 return NT_STATUS_UNSUCCESSFUL;
1218         }
1219
1220         if (!cli_session_request(cli, &calling, &called)) {
1221                 char *p;
1222                 DEBUG(1,("session request to %s failed (%s)\n", 
1223                          called.name, cli_errstr(cli)));
1224                 cli_shutdown(cli);
1225                 if ((p=strchr(called.name, '.'))) {
1226                         *p = 0;
1227                         goto again;
1228                 }
1229                 if (strcmp(called.name, "*SMBSERVER")) {
1230                         make_nmb_name(&called , "*SMBSERVER", 0x20);
1231                         goto again;
1232                 }
1233                 return NT_STATUS_UNSUCCESSFUL;
1234         }
1235
1236         if (!cli_negprot(cli))
1237         {
1238                 DEBUG(1,("failed negprot\n"));
1239                 nt_status = cli_nt_error(cli);
1240                 cli_shutdown(cli);
1241                 return nt_status;
1242         }
1243
1244         if (!cli_session_setup(cli, user,
1245                                password, pass_len,
1246                                NULL, 0,
1247                                domain))
1248         {
1249                 DEBUG(1,("failed session setup\n"));
1250                 nt_status = cli_nt_error(cli);
1251                 cli_shutdown(cli);
1252                 return nt_status;
1253         } 
1254
1255         if (service)
1256         {
1257                 if (!cli_send_tconX(cli, service, service_type,
1258                                     (char*)password, pass_len))
1259                 {
1260                         DEBUG(1,("failed tcon_X\n"));
1261                         nt_status = cli_nt_error(cli);
1262                         cli_shutdown(cli);
1263                         return nt_status;
1264                 }
1265         }
1266
1267         init_creds(&creds, user, domain, password, pass_len);
1268         cli_init_creds(cli, &creds);
1269
1270         *output_cli = cli;
1271         return NT_STATUS_OK;
1272 }
1273
1274 /****************************************************************************
1275  Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
1276 ****************************************************************************/
1277
1278 BOOL attempt_netbios_session_request(struct cli_state *cli, char *srchost, char *desthost,
1279                                      struct in_addr *pdest_ip)
1280 {
1281   struct nmb_name calling, called;
1282
1283   make_nmb_name(&calling, srchost, 0x0);
1284
1285   /*
1286    * If the called name is an IP address
1287    * then use *SMBSERVER immediately.
1288    */
1289
1290   if(is_ipaddress(desthost))
1291     make_nmb_name(&called, "*SMBSERVER", 0x20);
1292   else
1293     make_nmb_name(&called, desthost, 0x20);
1294
1295   if (!cli_session_request(cli, &calling, &called)) {
1296     struct nmb_name smbservername;
1297
1298     make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
1299
1300     /*
1301      * If the name wasn't *SMBSERVER then
1302      * try with *SMBSERVER if the first name fails.
1303      */
1304
1305     if (nmb_name_equal(&called, &smbservername)) {
1306
1307         /*
1308          * The name used was *SMBSERVER, don't bother with another name.
1309          */
1310
1311         DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
1312 with error %s.\n", desthost, cli_errstr(cli) ));
1313         cli_shutdown(cli);
1314         return False;
1315     }
1316
1317     cli_shutdown(cli);
1318
1319     if (!cli_initialise(cli) ||
1320         !cli_connect(cli, desthost, pdest_ip) ||
1321         !cli_session_request(cli, &calling, &smbservername)) {
1322           DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
1323 name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) ));
1324           cli_shutdown(cli);
1325           return False;
1326     }
1327   }
1328
1329   return True;
1330 }