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