merge from 2.2. Why is STR_CONVERT missing when comparing
[Samba/gbeck.git] / source / libsmb / cliconnect.c
blob2a84b69faa605816d71c0e45a124ae34cc9d091d
1 /*
2 Unix SMB/Netbios implementation.
3 Version 3.0
4 client connect/disconnect routines
5 Copyright (C) Andrew Tridgell 1994-1998
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.
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.
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.
22 #define NO_SYSLOG
24 #include "includes.h"
27 static const struct {
28 int prot;
29 const char *name;
31 prots[] =
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}
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)
51 fstring pword;
52 char *p;
54 if (passlen > sizeof(pword)-1) {
55 return False;
58 /* if in share level security then don't send a password now */
59 if (!(cli->sec_mode & 1)) {
60 passlen = 0;
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);
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);
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);
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);
95 cli_send_smb(cli);
96 if (!cli_receive_smb(cli))
97 return False;
99 show_msg(cli->inbuf);
101 if (cli_is_error(cli)) {
102 return False;
105 /* use the returned vuid from now on */
106 cli->vuid = SVAL(cli->inbuf,smb_uid);
107 fstrcpy(cli->user_name, user);
109 return True;
113 /****************************************************************************
114 work out suitable capabilities to offer the server
115 ****************************************************************************/
116 static uint32 cli_session_setup_capabilities(struct cli_state *cli)
118 uint32 capabilities = CAP_NT_SMBS;
120 /* Set the CLI_FORCE_DOSERR environment variable to test
121 client routines using DOS errors instead of STATUS32
122 ones. This intended only as a temporary hack. */
123 if (!getenv("CLI_FORCE_DOSERR")) {
124 capabilities |= CAP_STATUS32;
127 if (cli->use_level_II_oplocks) {
128 capabilities |= CAP_LEVEL_II_OPLOCKS;
131 if (cli->capabilities & CAP_UNICODE) {
132 capabilities |= CAP_UNICODE;
135 return capabilities;
139 /****************************************************************************
140 do a NT1 guest session setup
141 ****************************************************************************/
142 static BOOL cli_session_setup_guest(struct cli_state *cli)
144 char *p;
145 uint32 capabilities = cli_session_setup_capabilities(cli);
147 set_message(cli->outbuf,13,0,True);
148 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
149 cli_setup_packet(cli);
151 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
152 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
153 SSVAL(cli->outbuf,smb_vwv3,2);
154 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
155 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
156 SSVAL(cli->outbuf,smb_vwv7,0);
157 SSVAL(cli->outbuf,smb_vwv8,0);
158 SIVAL(cli->outbuf,smb_vwv11,capabilities);
159 p = smb_buf(cli->outbuf);
160 p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* username */
161 p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* workgroup */
162 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
163 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
164 cli_setup_bcc(cli, p);
166 cli_send_smb(cli);
167 if (!cli_receive_smb(cli))
168 return False;
170 show_msg(cli->inbuf);
172 if (cli_is_error(cli)) {
173 return False;
176 cli->vuid = SVAL(cli->inbuf,smb_uid);
178 p = smb_buf(cli->inbuf);
179 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
180 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
181 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
183 fstrcpy(cli->user_name, "");
185 return True;
189 /****************************************************************************
190 do a NT1 plaintext session setup
191 ****************************************************************************/
192 static BOOL cli_session_setup_plaintext(struct cli_state *cli, char *user,
193 char *pass, char *workgroup)
195 uint32 capabilities = cli_session_setup_capabilities(cli);
196 fstring pword;
197 int passlen;
198 char *p;
200 passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
202 set_message(cli->outbuf,13,0,True);
203 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
204 cli_setup_packet(cli);
206 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
207 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
208 SSVAL(cli->outbuf,smb_vwv3,2);
209 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
210 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
211 SSVAL(cli->outbuf,smb_vwv7,passlen);
212 SSVAL(cli->outbuf,smb_vwv8,0);
213 SIVAL(cli->outbuf,smb_vwv11,capabilities);
214 p = smb_buf(cli->outbuf);
215 memcpy(p, pword, passlen);
216 p += passlen;
217 p += clistr_push(cli, p, user, -1, STR_TERMINATE); /* username */
218 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE); /* workgroup */
219 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
220 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
221 cli_setup_bcc(cli, p);
223 cli_send_smb(cli);
224 if (!cli_receive_smb(cli))
225 return False;
227 show_msg(cli->inbuf);
229 if (cli_is_error(cli)) {
230 return False;
233 cli->vuid = SVAL(cli->inbuf,smb_uid);
234 p = smb_buf(cli->inbuf);
235 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
236 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
237 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
238 fstrcpy(cli->user_name, user);
240 return True;
244 /****************************************************************************
245 do a NT1 NTLM/LM encrypted session setup
246 ****************************************************************************/
247 static BOOL cli_session_setup_nt1(struct cli_state *cli, char *user,
248 char *pass, int passlen,
249 char *ntpass, int ntpasslen,
250 char *workgroup)
252 uint32 capabilities = cli_session_setup_capabilities(cli);
253 fstring pword, ntpword;
254 char *p;
256 if (passlen > sizeof(pword)-1 || ntpasslen > sizeof(ntpword)-1) {
257 return False;
260 if (passlen != 24) {
261 /* non encrypted password supplied. */
262 passlen = 24;
263 ntpasslen = 24;
264 clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
265 clistr_push(cli, ntpword, ntpass, sizeof(ntpword), STR_TERMINATE);
266 SMBencrypt((uchar *)pword,cli->secblob.data,(uchar *)pword);
267 SMBNTencrypt((uchar *)ntpword,cli->secblob.data,(uchar *)ntpword);
268 } else {
269 memcpy(pword, pass, passlen);
270 memcpy(ntpword, ntpass, ntpasslen);
273 /* send a session setup command */
274 memset(cli->outbuf,'\0',smb_size);
276 set_message(cli->outbuf,13,0,True);
277 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
278 cli_setup_packet(cli);
280 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
281 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
282 SSVAL(cli->outbuf,smb_vwv3,2);
283 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
284 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
285 SSVAL(cli->outbuf,smb_vwv7,passlen);
286 SSVAL(cli->outbuf,smb_vwv8,ntpasslen);
287 SIVAL(cli->outbuf,smb_vwv11,capabilities);
288 p = smb_buf(cli->outbuf);
289 memcpy(p,pword,passlen); p += passlen;
290 memcpy(p,ntpword,ntpasslen); p += ntpasslen;
291 p += clistr_push(cli, p, user, -1, STR_TERMINATE|STR_UPPER);
292 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
293 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
294 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
295 cli_setup_bcc(cli, p);
297 cli_send_smb(cli);
298 if (!cli_receive_smb(cli))
299 return False;
301 show_msg(cli->inbuf);
303 if (cli_is_error(cli)) {
304 return False;
307 /* use the returned vuid from now on */
308 cli->vuid = SVAL(cli->inbuf,smb_uid);
310 p = smb_buf(cli->inbuf);
311 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
312 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
313 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
315 fstrcpy(cli->user_name, user);
317 return True;
321 /****************************************************************************
322 send a extended security session setup blob, returning a reply blob
323 ****************************************************************************/
324 static DATA_BLOB cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob)
326 uint32 capabilities = cli_session_setup_capabilities(cli);
327 char *p;
328 DATA_BLOB blob2;
330 blob2 = data_blob(NULL, 0);
332 capabilities |= CAP_EXTENDED_SECURITY;
334 /* send a session setup command */
335 memset(cli->outbuf,'\0',smb_size);
337 set_message(cli->outbuf,12,0,True);
338 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
339 cli_setup_packet(cli);
341 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
342 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
343 SSVAL(cli->outbuf,smb_vwv3,2);
344 SSVAL(cli->outbuf,smb_vwv4,0);
345 SIVAL(cli->outbuf,smb_vwv5,0);
346 SSVAL(cli->outbuf,smb_vwv7,blob.length);
347 SIVAL(cli->outbuf,smb_vwv10,capabilities);
348 p = smb_buf(cli->outbuf);
349 memcpy(p, blob.data, blob.length);
350 p += blob.length;
351 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
352 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
353 cli_setup_bcc(cli, p);
355 cli_send_smb(cli);
356 if (!cli_receive_smb(cli))
357 return blob2;
359 show_msg(cli->inbuf);
361 if (cli_is_error(cli) && !NT_STATUS_EQUAL(cli_nt_error(cli),
362 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
363 return blob2;
366 /* use the returned vuid from now on */
367 cli->vuid = SVAL(cli->inbuf,smb_uid);
369 p = smb_buf(cli->inbuf);
371 blob2 = data_blob(p, SVAL(cli->inbuf, smb_vwv3));
373 p += blob2.length;
374 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
375 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
376 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
378 return blob2;
382 #if HAVE_KRB5
383 /****************************************************************************
384 do a spnego/kerberos encrypted session setup
385 ****************************************************************************/
386 static BOOL cli_session_setup_kerberos(struct cli_state *cli, char *principal, char *workgroup)
388 DATA_BLOB blob2, negTokenTarg;
390 d_printf("Doing kerberos session setup\n");
392 /* generate the encapsulated kerberos5 ticket */
393 negTokenTarg = spnego_gen_negTokenTarg(cli, principal);
395 if (!negTokenTarg.data) return False;
397 #if 0
398 file_save("negTokenTarg.dat", negTokenTarg.data, negTokenTarg.length);
399 #endif
401 blob2 = cli_session_setup_blob(cli, negTokenTarg);
403 /* we don't need this blob for kerberos */
404 data_blob_free(&blob2);
406 return !cli_is_error(cli);
408 #endif
410 /****************************************************************************
411 do a spnego/NTLMSSP encrypted session setup
412 ****************************************************************************/
413 static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, char *user,
414 char *pass, char *workgroup)
416 const char *mechs[] = {OID_NTLMSSP, NULL};
417 DATA_BLOB msg1;
418 DATA_BLOB blob, chal1, chal2, auth;
419 uint8 challenge[8];
420 uint8 nthash[24], lmhash[24], sess_key[16];
421 uint32 neg_flags;
423 neg_flags = NTLMSSP_NEGOTIATE_UNICODE |
424 NTLMSSP_NEGOTIATE_LM_KEY |
425 NTLMSSP_NEGOTIATE_NTLM;
427 memset(sess_key, 0, 16);
429 /* generate the ntlmssp negotiate packet */
430 msrpc_gen(&blob, "CddB",
431 "NTLMSSP",
432 NTLMSSP_NEGOTIATE,
433 neg_flags,
434 sess_key, 16);
436 /* and wrap it in a SPNEGO wrapper */
437 msg1 = gen_negTokenTarg(mechs, blob);
438 data_blob_free(&blob);
440 /* now send that blob on its way */
441 blob = cli_session_setup_blob(cli, msg1);
443 data_blob_free(&msg1);
445 if (!NT_STATUS_EQUAL(cli_nt_error(cli), NT_STATUS_MORE_PROCESSING_REQUIRED)) {
446 return False;
449 #if 0
450 file_save("chal.dat", blob.data, blob.length);
451 #endif
453 /* the server gives us back two challenges */
454 if (!spnego_parse_challenge(blob, &chal1, &chal2)) {
455 DEBUG(3,("Failed to parse challenges\n"));
456 return False;
459 data_blob_free(&blob);
461 /* encrypt the password with the challenge */
462 memcpy(challenge, chal1.data + 24, 8);
463 SMBencrypt((unsigned char *)pass, challenge,lmhash);
464 SMBNTencrypt((unsigned char *)pass, challenge,nthash);
466 #if 0
467 file_save("nthash.dat", nthash, 24);
468 file_save("lmhash.dat", lmhash, 24);
469 file_save("chal1.dat", chal1.data, chal1.length);
470 #endif
472 data_blob_free(&chal1);
473 data_blob_free(&chal2);
475 /* this generates the actual auth packet */
476 msrpc_gen(&blob, "CdBBUUUBd",
477 "NTLMSSP",
478 NTLMSSP_AUTH,
479 lmhash, 24,
480 nthash, 24,
481 workgroup,
482 user,
483 cli->calling.name,
484 sess_key, 16,
485 neg_flags);
487 /* wrap it in SPNEGO */
488 auth = spnego_gen_auth(blob);
490 data_blob_free(&blob);
492 /* now send the auth packet and we should be done */
493 blob = cli_session_setup_blob(cli, auth);
495 data_blob_free(&auth);
496 data_blob_free(&blob);
498 return !cli_is_error(cli);
502 /****************************************************************************
503 do a spnego encrypted session setup
504 ****************************************************************************/
505 static BOOL cli_session_setup_spnego(struct cli_state *cli, char *user,
506 char *pass, char *workgroup)
508 char *principal;
509 char *OIDs[ASN1_MAX_OIDS];
510 uint8 guid[16];
511 int i;
512 BOOL got_kerberos_mechanism = False;
514 d_printf("Doing spnego session setup\n");
516 /* the server might not even do spnego */
517 if (cli->secblob.length == 16) {
518 DEBUG(3,("server didn't supply a full spnego negprot\n"));
519 goto ntlmssp;
522 #if 0
523 file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
524 #endif
526 /* the server sent us the first part of the SPNEGO exchange in the negprot
527 reply */
528 if (!spnego_parse_negTokenInit(cli->secblob, guid, OIDs, &principal)) {
529 return False;
532 /* make sure the server understands kerberos */
533 for (i=0;OIDs[i];i++) {
534 DEBUG(3,("got OID=%s\n", OIDs[i]));
535 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
536 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
537 got_kerberos_mechanism = True;
539 free(OIDs[i]);
541 DEBUG(3,("got principal=%s\n", principal));
543 fstrcpy(cli->user_name, user);
545 #if HAVE_KRB5
546 if (got_kerberos_mechanism && cli->use_kerberos) {
547 return cli_session_setup_kerberos(cli, principal, workgroup);
549 #endif
551 free(principal);
553 ntlmssp:
555 return cli_session_setup_ntlmssp(cli, user, pass, workgroup);
559 /****************************************************************************
560 Send a session setup. The username and workgroup is in UNIX character
561 format and must be converted to DOS codepage format before sending. If the
562 password is in plaintext, the same should be done.
563 ****************************************************************************/
564 BOOL cli_session_setup(struct cli_state *cli,
565 char *user,
566 char *pass, int passlen,
567 char *ntpass, int ntpasslen,
568 char *workgroup)
570 char *p;
571 fstring user2;
573 /* allow for workgroups as part of the username */
574 fstrcpy(user2, user);
575 if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/'))) {
576 *p = 0;
577 user = p+1;
578 workgroup = user2;
581 if (cli->protocol < PROTOCOL_LANMAN1)
582 return True;
584 /* now work out what sort of session setup we are going to
585 do. I have split this into separate functions to make the
586 flow a bit easier to understand (tridge) */
588 /* if its an older server then we have to use the older request format */
589 if (cli->protocol < PROTOCOL_NT1) {
590 return cli_session_setup_lanman2(cli, user, pass, passlen);
593 /* if no user is supplied then we have to do an anonymous connection.
594 passwords are ignored */
595 if (!user || !*user) {
596 return cli_session_setup_guest(cli);
599 /* if the server is share level then send a plaintext null
600 password at this point. The password is sent in the tree
601 connect */
602 if ((cli->sec_mode & 1) == 0) {
603 return cli_session_setup_plaintext(cli, user, "", workgroup);
606 /* if the server doesn't support encryption then we have to use plaintext. The
607 second password is ignored */
608 if ((cli->sec_mode & 2) == 0) {
609 return cli_session_setup_plaintext(cli, user, pass, workgroup);
612 /* if the server supports extended security then use SPNEGO */
613 if (cli->capabilities & CAP_EXTENDED_SECURITY) {
614 return cli_session_setup_spnego(cli, user, pass, workgroup);
617 /* otherwise do a NT1 style session setup */
618 return cli_session_setup_nt1(cli, user,
619 pass, passlen, ntpass, ntpasslen,
620 workgroup);
623 /****************************************************************************
624 Send a uloggoff.
625 *****************************************************************************/
627 BOOL cli_ulogoff(struct cli_state *cli)
629 memset(cli->outbuf,'\0',smb_size);
630 set_message(cli->outbuf,2,0,True);
631 CVAL(cli->outbuf,smb_com) = SMBulogoffX;
632 cli_setup_packet(cli);
633 SSVAL(cli->outbuf,smb_vwv0,0xFF);
634 SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
636 cli_send_smb(cli);
637 if (!cli_receive_smb(cli))
638 return False;
640 return !cli_is_error(cli);
643 /****************************************************************************
644 send a tconX
645 ****************************************************************************/
646 BOOL cli_send_tconX(struct cli_state *cli,
647 const char *share, const char *dev, const char *pass, int passlen)
649 fstring fullshare, pword, dos_pword;
650 char *p;
651 memset(cli->outbuf,'\0',smb_size);
652 memset(cli->inbuf,'\0',smb_size);
654 fstrcpy(cli->share, share);
656 /* in user level security don't send a password now */
657 if (cli->sec_mode & 1) {
658 passlen = 1;
659 pass = "";
662 if ((cli->sec_mode & 2) && *pass && passlen != 24) {
664 * Non-encrypted passwords - convert to DOS codepage before encryption.
666 passlen = 24;
667 clistr_push(cli, dos_pword, pass, -1, STR_TERMINATE);
668 SMBencrypt((uchar *)dos_pword,cli->secblob.data,(uchar *)pword);
669 } else {
670 if((cli->sec_mode & 3) == 0) {
672 * Non-encrypted passwords - convert to DOS codepage before using.
674 passlen = clistr_push(cli, pword, pass, -1, STR_TERMINATE);
675 } else {
676 memcpy(pword, pass, passlen);
680 if (cli->port == 445) {
681 slprintf(fullshare, sizeof(fullshare)-1,
682 "%s", share);
683 } else {
684 slprintf(fullshare, sizeof(fullshare)-1,
685 "\\\\%s\\%s", cli->desthost, share);
688 set_message(cli->outbuf,4, 0, True);
689 CVAL(cli->outbuf,smb_com) = SMBtconX;
690 cli_setup_packet(cli);
692 SSVAL(cli->outbuf,smb_vwv0,0xFF);
693 SSVAL(cli->outbuf,smb_vwv3,passlen);
695 p = smb_buf(cli->outbuf);
696 memcpy(p,pword,passlen);
697 p += passlen;
698 p += clistr_push(cli, p, fullshare, -1, STR_TERMINATE |STR_UPPER);
699 fstrcpy(p, dev); p += strlen(dev)+1;
701 cli_setup_bcc(cli, p);
703 cli_send_smb(cli);
704 if (!cli_receive_smb(cli))
705 return False;
707 if (cli_is_error(cli)) {
708 return False;
711 fstrcpy(cli->dev, "A:");
713 if (cli->protocol >= PROTOCOL_NT1) {
714 clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE);
717 if (strcasecmp(share,"IPC$")==0) {
718 fstrcpy(cli->dev, "IPC");
721 /* only grab the device if we have a recent protocol level */
722 if (cli->protocol >= PROTOCOL_NT1 &&
723 smb_buflen(cli->inbuf) == 3) {
724 /* almost certainly win95 - enable bug fixes */
725 cli->win95 = True;
728 cli->cnum = SVAL(cli->inbuf,smb_tid);
729 return True;
733 /****************************************************************************
734 send a tree disconnect
735 ****************************************************************************/
736 BOOL cli_tdis(struct cli_state *cli)
738 memset(cli->outbuf,'\0',smb_size);
739 set_message(cli->outbuf,0,0,True);
740 CVAL(cli->outbuf,smb_com) = SMBtdis;
741 SSVAL(cli->outbuf,smb_tid,cli->cnum);
742 cli_setup_packet(cli);
744 cli_send_smb(cli);
745 if (!cli_receive_smb(cli))
746 return False;
748 return !cli_is_error(cli);
752 /****************************************************************************
753 send a negprot command
754 ****************************************************************************/
755 void cli_negprot_send(struct cli_state *cli)
757 char *p;
758 int numprots;
760 memset(cli->outbuf,'\0',smb_size);
762 /* setup the protocol strings */
763 set_message(cli->outbuf,0,0,True);
765 p = smb_buf(cli->outbuf);
766 for (numprots=0;
767 prots[numprots].name && prots[numprots].prot<=cli->protocol;
768 numprots++) {
769 *p++ = 2;
770 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
773 CVAL(cli->outbuf,smb_com) = SMBnegprot;
774 cli_setup_bcc(cli, p);
775 cli_setup_packet(cli);
777 CVAL(smb_buf(cli->outbuf),0) = 2;
779 cli_send_smb(cli);
783 /****************************************************************************
784 send a negprot command
785 ****************************************************************************/
786 BOOL cli_negprot(struct cli_state *cli)
788 char *p;
789 int numprots;
790 int plength;
792 memset(cli->outbuf,'\0',smb_size);
794 /* setup the protocol strings */
795 for (plength=0,numprots=0;
796 prots[numprots].name && prots[numprots].prot<=cli->protocol;
797 numprots++)
798 plength += strlen(prots[numprots].name)+2;
800 set_message(cli->outbuf,0,plength,True);
802 p = smb_buf(cli->outbuf);
803 for (numprots=0;
804 prots[numprots].name && prots[numprots].prot<=cli->protocol;
805 numprots++) {
806 *p++ = 2;
807 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
810 CVAL(cli->outbuf,smb_com) = SMBnegprot;
811 cli_setup_packet(cli);
813 CVAL(smb_buf(cli->outbuf),0) = 2;
815 cli_send_smb(cli);
816 if (!cli_receive_smb(cli))
817 return False;
819 show_msg(cli->inbuf);
821 if (cli_is_error(cli) ||
822 ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
823 return(False);
826 cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
828 if (cli->protocol >= PROTOCOL_NT1) {
829 /* NT protocol */
830 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
831 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
832 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
833 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
834 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1);
835 cli->serverzone *= 60;
836 /* this time arrives in real GMT */
837 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
838 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
839 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
840 if (cli->capabilities & CAP_RAW_MODE) {
841 cli->readbraw_supported = True;
842 cli->writebraw_supported = True;
844 /* work out if they sent us a workgroup */
845 if (smb_buflen(cli->inbuf) > 8) {
846 clistr_pull(cli, cli->server_domain,
847 smb_buf(cli->inbuf)+8, sizeof(cli->server_domain),
848 smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
850 } else if (cli->protocol >= PROTOCOL_LANMAN1) {
851 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
852 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
853 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
854 cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
855 cli->serverzone *= 60;
856 /* this time is converted to GMT by make_unix_date */
857 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
858 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
859 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
860 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
861 } else {
862 /* the old core protocol */
863 cli->sec_mode = 0;
864 cli->serverzone = TimeDiff(time(NULL));
867 cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
869 /* a way to force ascii SMB */
870 if (getenv("CLI_FORCE_ASCII")) {
871 cli->capabilities &= ~CAP_UNICODE;
874 return True;
878 /****************************************************************************
879 send a session request. see rfc1002.txt 4.3 and 4.3.2
880 ****************************************************************************/
881 BOOL cli_session_request(struct cli_state *cli,
882 struct nmb_name *calling, struct nmb_name *called)
884 char *p;
885 int len = 4;
886 extern pstring user_socket_options;
888 /* 445 doesn't have session request */
889 if (cli->port == 445) return True;
891 /* send a session request (RFC 1002) */
892 memcpy(&(cli->calling), calling, sizeof(*calling));
893 memcpy(&(cli->called ), called , sizeof(*called ));
895 /* put in the destination name */
896 p = cli->outbuf+len;
897 name_mangle(cli->called .name, p, cli->called .name_type);
898 len += name_len(p);
900 /* and my name */
901 p = cli->outbuf+len;
902 name_mangle(cli->calling.name, p, cli->calling.name_type);
903 len += name_len(p);
905 /* setup the packet length */
906 _smb_setlen(cli->outbuf,len);
907 CVAL(cli->outbuf,0) = 0x81;
909 #ifdef WITH_SSL
910 retry:
911 #endif /* WITH_SSL */
913 cli_send_smb(cli);
914 DEBUG(5,("Sent session request\n"));
916 if (!cli_receive_smb(cli))
917 return False;
919 if (CVAL(cli->inbuf,0) == 0x84) {
920 /* C. Hoch 9/14/95 Start */
921 /* For information, here is the response structure.
922 * We do the byte-twiddling to for portability.
923 struct RetargetResponse{
924 unsigned char type;
925 unsigned char flags;
926 int16 length;
927 int32 ip_addr;
928 int16 port;
931 int port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
932 /* SESSION RETARGET */
933 putip((char *)&cli->dest_ip,cli->inbuf+4);
935 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
936 if (cli->fd == -1)
937 return False;
939 DEBUG(3,("Retargeted\n"));
941 set_socket_options(cli->fd,user_socket_options);
943 /* Try again */
945 static int depth;
946 BOOL ret;
947 if (depth > 4) {
948 DEBUG(0,("Retarget recursion - failing\n"));
949 return False;
951 depth++;
952 ret = cli_session_request(cli, calling, called);
953 depth--;
954 return ret;
956 } /* C. Hoch 9/14/95 End */
958 #ifdef WITH_SSL
959 if (CVAL(cli->inbuf,0) == 0x83 && CVAL(cli->inbuf,4) == 0x8e){ /* use ssl */
960 if (!sslutil_fd_is_ssl(cli->fd)){
961 if (sslutil_connect(cli->fd) == 0)
962 goto retry;
965 #endif /* WITH_SSL */
967 if (CVAL(cli->inbuf,0) != 0x82) {
968 /* This is the wrong place to put the error... JRA. */
969 cli->rap_error = CVAL(cli->inbuf,4);
970 return False;
972 return(True);
975 /****************************************************************************
976 open the client sockets
977 ****************************************************************************/
978 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
980 extern struct in_addr ipzero;
981 extern pstring user_socket_options;
983 fstrcpy(cli->desthost, host);
985 if (!ip || ip_equal(*ip, ipzero)) {
986 if (!resolve_name( cli->desthost, &cli->dest_ip, 0x20)) {
987 return False;
989 if (ip) *ip = cli->dest_ip;
990 } else {
991 cli->dest_ip = *ip;
994 if (getenv("LIBSMB_PROG")) {
995 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
996 } else {
997 /* try 445 first, then 139 */
998 int port = cli->port?cli->port:445;
999 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
1000 port, cli->timeout);
1001 if (cli->fd == -1 && cli->port == 0) {
1002 port = 139;
1003 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
1004 port, cli->timeout);
1006 if (cli->fd != -1) cli->port = port;
1008 if (cli->fd == -1) {
1009 DEBUG(1,("Error connecting to %s (%s)\n",
1010 inet_ntoa(*ip),strerror(errno)));
1011 return False;
1014 set_socket_options(cli->fd,user_socket_options);
1016 return True;
1019 /****************************************************************************
1020 re-establishes a connection
1021 ****************************************************************************/
1022 BOOL cli_reestablish_connection(struct cli_state *cli)
1024 struct nmb_name calling;
1025 struct nmb_name called;
1026 fstring dest_host;
1027 fstring share;
1028 fstring dev;
1029 BOOL do_tcon = False;
1030 int oldfd = cli->fd;
1032 if (!cli->initialised || cli->fd == -1)
1034 DEBUG(3,("cli_reestablish_connection: not connected\n"));
1035 return False;
1038 /* copy the parameters necessary to re-establish the connection */
1040 if (cli->cnum != 0)
1042 fstrcpy(share, cli->share);
1043 fstrcpy(dev , cli->dev);
1044 do_tcon = True;
1047 memcpy(&called , &(cli->called ), sizeof(called ));
1048 memcpy(&calling, &(cli->calling), sizeof(calling));
1049 fstrcpy(dest_host, cli->full_dest_host_name);
1051 DEBUG(5,("cli_reestablish_connection: %s connecting to %s (ip %s) - %s [%s]\n",
1052 nmb_namestr(&calling), nmb_namestr(&called),
1053 inet_ntoa(cli->dest_ip),
1054 cli->user_name, cli->domain));
1056 cli->fd = -1;
1058 if (cli_establish_connection(cli,
1059 dest_host, &cli->dest_ip,
1060 &calling, &called,
1061 share, dev, False, do_tcon)) {
1062 if ((cli->fd != oldfd) && (oldfd != -1)) {
1063 close( oldfd );
1065 return True;
1067 return False;
1070 /****************************************************************************
1071 establishes a connection right up to doing tconX, reading in a password.
1072 ****************************************************************************/
1073 BOOL cli_establish_connection(struct cli_state *cli,
1074 char *dest_host, struct in_addr *dest_ip,
1075 struct nmb_name *calling, struct nmb_name *called,
1076 char *service, char *service_type,
1077 BOOL do_shutdown, BOOL do_tcon)
1079 DEBUG(5,("cli_establish_connection: %s connecting to %s (%s) - %s [%s]\n",
1080 nmb_namestr(calling), nmb_namestr(called), inet_ntoa(*dest_ip),
1081 cli->user_name, cli->domain));
1083 /* establish connection */
1085 if ((!cli->initialised))
1087 return False;
1090 /* cli_establish_connection() can't handle spnego yet. Once we get rid of
1091 pwd_cache and other horrors we can get rid of this */
1092 cli->use_spnego = False;
1094 if (cli->fd == -1)
1096 if (!cli_connect(cli, dest_host, dest_ip))
1098 DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n",
1099 nmb_namestr(called), inet_ntoa(*dest_ip)));
1100 return False;
1104 if (!cli_session_request(cli, calling, called))
1106 DEBUG(1,("failed session request\n"));
1107 if (do_shutdown)
1108 cli_shutdown(cli);
1109 return False;
1112 if (!cli_negprot(cli))
1114 DEBUG(1,("failed negprot\n"));
1115 if (do_shutdown)
1116 cli_shutdown(cli);
1117 return False;
1120 if (cli->pwd.cleartext || cli->pwd.null_pwd)
1122 fstring passwd;
1123 int pass_len;
1125 if (cli->pwd.null_pwd)
1127 /* attempt null session */
1128 passwd[0] = 0;
1129 pass_len = 1;
1131 else
1133 /* attempt clear-text session */
1134 pwd_get_cleartext(&(cli->pwd), passwd);
1135 pass_len = strlen(passwd);
1138 /* attempt clear-text session */
1139 if (!cli_session_setup(cli, cli->user_name,
1140 passwd, pass_len,
1141 NULL, 0,
1142 cli->domain))
1144 DEBUG(1,("failed session setup\n"));
1145 if (do_shutdown)
1147 cli_shutdown(cli);
1149 return False;
1151 if (do_tcon)
1153 if (!cli_send_tconX(cli, service, service_type,
1154 (char*)passwd, strlen(passwd)))
1156 DEBUG(1,("failed tcon_X\n"));
1157 if (do_shutdown)
1159 cli_shutdown(cli);
1161 return False;
1165 else
1167 /* attempt encrypted session */
1168 unsigned char nt_sess_pwd[24];
1169 unsigned char lm_sess_pwd[24];
1171 /* creates (storing a copy of) and then obtains a 24 byte password OWF */
1172 pwd_make_lm_nt_owf(&(cli->pwd), cli->secblob.data);
1173 pwd_get_lm_nt_owf(&(cli->pwd), lm_sess_pwd, nt_sess_pwd);
1175 /* attempt encrypted session */
1176 if (!cli_session_setup(cli, cli->user_name,
1177 (char*)lm_sess_pwd, sizeof(lm_sess_pwd),
1178 (char*)nt_sess_pwd, sizeof(nt_sess_pwd),
1179 cli->domain))
1181 DEBUG(1,("failed session setup\n"));
1182 if (do_shutdown)
1183 cli_shutdown(cli);
1184 return False;
1187 DEBUG(1,("session setup ok\n"));
1189 if (*cli->server_domain || *cli->server_os || *cli->server_type)
1191 DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",
1192 cli->server_domain,
1193 cli->server_os,
1194 cli->server_type));
1197 if (do_tcon)
1199 if (!cli_send_tconX(cli, service, service_type,
1200 (char*)nt_sess_pwd, sizeof(nt_sess_pwd)))
1202 DEBUG(1,("failed tcon_X\n"));
1203 if (do_shutdown)
1204 cli_shutdown(cli);
1205 return False;
1210 if (do_shutdown)
1211 cli_shutdown(cli);
1213 return True;
1217 /****************************************************************************
1218 Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
1219 ****************************************************************************/
1221 BOOL attempt_netbios_session_request(struct cli_state *cli, char *srchost, char *desthost,
1222 struct in_addr *pdest_ip)
1224 struct nmb_name calling, called;
1226 make_nmb_name(&calling, srchost, 0x0);
1229 * If the called name is an IP address
1230 * then use *SMBSERVER immediately.
1233 if(is_ipaddress(desthost))
1234 make_nmb_name(&called, "*SMBSERVER", 0x20);
1235 else
1236 make_nmb_name(&called, desthost, 0x20);
1238 if (!cli_session_request(cli, &calling, &called)) {
1239 struct nmb_name smbservername;
1241 make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
1244 * If the name wasn't *SMBSERVER then
1245 * try with *SMBSERVER if the first name fails.
1248 if (nmb_name_equal(&called, &smbservername)) {
1251 * The name used was *SMBSERVER, don't bother with another name.
1254 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
1255 with error %s.\n", desthost, cli_errstr(cli) ));
1256 cli_shutdown(cli);
1257 return False;
1260 cli_shutdown(cli);
1262 if (!cli_initialise(cli) ||
1263 !cli_connect(cli, desthost, pdest_ip) ||
1264 !cli_session_request(cli, &calling, &smbservername)) {
1265 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
1266 name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) ));
1267 cli_shutdown(cli);
1268 return False;
1272 return True;