2 Unix SMB/Netbios implementation.
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.
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"},
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)
54 if (passlen > sizeof(pword)-1) {
58 /* if in share level security then don't send a password now */
59 if (!(cli->sec_mode & 1)) {
63 if (passlen > 0 && (cli->sec_mode & 2) && passlen != 24) {
64 /* Encrypted mode needed, and non encrypted password supplied. */
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);
92 p += clistr_push(cli, p, user, -1, STR_UPPER|STR_TERMINATE);
93 cli_setup_bcc(cli, p);
96 if (!cli_receive_smb(cli))
101 if (cli_is_error(cli)) {
105 /* use the returned vuid from now on */
106 cli->vuid = SVAL(cli->inbuf,smb_uid);
107 fstrcpy(cli->user_name, user);
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;
139 /****************************************************************************
140 do a NT1 guest session setup
141 ****************************************************************************/
142 static BOOL cli_session_setup_guest(struct cli_state *cli)
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);
167 if (!cli_receive_smb(cli))
170 show_msg(cli->inbuf);
172 if (cli_is_error(cli)) {
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, "");
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);
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);
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);
224 if (!cli_receive_smb(cli))
227 show_msg(cli->inbuf);
229 if (cli_is_error(cli)) {
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);
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,
252 uint32 capabilities = cli_session_setup_capabilities(cli);
253 fstring pword, ntpword;
256 if (passlen > sizeof(pword)-1 || ntpasslen > sizeof(ntpword)-1) {
261 /* non encrypted password supplied. */
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);
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);
298 if (!cli_receive_smb(cli))
301 show_msg(cli->inbuf);
303 if (cli_is_error(cli)) {
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);
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);
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);
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);
356 if (!cli_receive_smb(cli))
359 show_msg(cli->inbuf);
361 if (cli_is_error(cli) && !NT_STATUS_EQUAL(cli_nt_error(cli),
362 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
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));
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);
383 /****************************************************************************
384 do a spnego/kerberos encrypted session setup
385 ****************************************************************************/
386 static BOOL cli_session_setup_kerberos(struct cli_state *cli, char *principle, char *workgroup)
388 DATA_BLOB blob2, negTokenTarg;
390 /* generate the encapsulated kerberos5 ticket */
391 negTokenTarg = spnego_gen_negTokenTarg(cli, principle);
393 if (!negTokenTarg.data) return False;
395 blob2 = cli_session_setup_blob(cli, negTokenTarg);
397 /* we don't need this blob for kerberos */
398 data_blob_free(&blob2);
400 return !cli_is_error(cli);
404 /****************************************************************************
405 do a spnego/NTLMSSP encrypted session setup
406 ****************************************************************************/
407 static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, char *user,
408 char *pass, char *workgroup)
410 const char *mechs[] = {OID_NTLMSSP, NULL};
412 DATA_BLOB blob, chal1, chal2, auth;
414 uint8 nthash[24], lmhash[24], sess_key[16];
417 neg_flags = NTLMSSP_NEGOTIATE_UNICODE |
418 NTLMSSP_NEGOTIATE_LM_KEY |
419 NTLMSSP_NEGOTIATE_NTLM;
421 memset(sess_key, 0, 16);
423 /* generate the ntlmssp negotiate packet */
424 msrpc_gen(&blob, "CddB",
430 /* and wrap it in a SPNEGO wrapper */
431 msg1 = gen_negTokenTarg(mechs, blob);
432 data_blob_free(&blob);
434 /* now send that blob on its way */
435 blob = cli_session_setup_blob(cli, msg1);
437 data_blob_free(&msg1);
439 if (!NT_STATUS_EQUAL(cli_nt_error(cli), NT_STATUS_MORE_PROCESSING_REQUIRED)) {
444 file_save("chal.dat", blob.data, blob.length);
447 /* the server gives us back two challenges */
448 if (!spnego_parse_challenge(blob, &chal1, &chal2)) {
449 DEBUG(3,("Failed to parse challenges\n"));
453 data_blob_free(&blob);
455 /* encrypt the password with the challenge */
456 memcpy(challenge, chal1.data + 24, 8);
457 SMBencrypt(pass, challenge,lmhash);
458 SMBNTencrypt(pass, challenge,nthash);
461 file_save("nthash.dat", nthash, 24);
462 file_save("lmhash.dat", lmhash, 24);
463 file_save("chal1.dat", chal1.data, chal1.length);
466 data_blob_free(&chal1);
467 data_blob_free(&chal2);
469 /* this generates the actual auth packet */
470 msrpc_gen(&blob, "CdBBUUUBd",
481 /* wrap it in SPNEGO */
482 auth = spnego_gen_auth(blob);
484 data_blob_free(&blob);
486 /* now send the auth packet and we should be done */
487 blob = cli_session_setup_blob(cli, auth);
489 data_blob_free(&auth);
490 data_blob_free(&blob);
492 return !cli_is_error(cli);
496 /****************************************************************************
497 do a spnego encrypted session setup
498 ****************************************************************************/
499 static BOOL cli_session_setup_spnego(struct cli_state *cli, char *user,
500 char *pass, char *workgroup)
503 char *OIDs[ASN1_MAX_OIDS];
506 BOOL got_kerberos_mechanism = False;
508 /* the server might not even do spnego */
509 if (cli->secblob.length == 16) {
510 DEBUG(3,("server didn't supply a full spnego negprot\n"));
515 file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
518 /* the server sent us the first part of the SPNEGO exchange in the negprot
520 if (!spnego_parse_negTokenInit(cli->secblob, guid, OIDs, &principle)) {
524 /* make sure the server understands kerberos */
525 for (i=0;OIDs[i];i++) {
526 DEBUG(3,("got OID=%s\n", OIDs[i]));
527 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0) {
528 got_kerberos_mechanism = True;
532 DEBUG(3,("got principle=%s\n", principle));
534 fstrcpy(cli->user_name, user);
537 if (got_kerberos_mechanism && cli->use_kerberos) {
538 return cli_session_setup_kerberos(cli, principle, workgroup);
546 return cli_session_setup_ntlmssp(cli, user, pass, workgroup);
550 /****************************************************************************
551 Send a session setup. The username and workgroup is in UNIX character
552 format and must be converted to DOS codepage format before sending. If the
553 password is in plaintext, the same should be done.
554 ****************************************************************************/
555 BOOL cli_session_setup(struct cli_state *cli,
557 char *pass, int passlen,
558 char *ntpass, int ntpasslen,
564 /* allow for workgroups as part of the username */
565 fstrcpy(user2, user);
566 if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/'))) {
572 if (cli->protocol < PROTOCOL_LANMAN1)
575 /* now work out what sort of session setup we are going to
576 do. I have split this into separate functions to make the
577 flow a bit easier to understand (tridge) */
579 /* if its an older server then we have to use the older request format */
580 if (cli->protocol < PROTOCOL_NT1) {
581 return cli_session_setup_lanman2(cli, user, pass, passlen);
584 /* if no user is supplied then we have to do an anonymous connection.
585 passwords are ignored */
586 if (!user || !*user) {
587 return cli_session_setup_guest(cli);
590 /* if the server is share level then send a plaintext null
591 password at this point. The password is sent in the tree
593 if ((cli->sec_mode & 1) == 0) {
594 return cli_session_setup_plaintext(cli, user, "", workgroup);
597 /* if the server doesn't support encryption then we have to use plaintext. The
598 second password is ignored */
599 if ((cli->sec_mode & 2) == 0) {
600 return cli_session_setup_plaintext(cli, user, pass, workgroup);
603 /* if the server supports extended security then use SPNEGO */
604 if (cli->capabilities & CAP_EXTENDED_SECURITY) {
605 return cli_session_setup_spnego(cli, user, pass, workgroup);
608 /* otherwise do a NT1 style session setup */
609 return cli_session_setup_nt1(cli, user,
610 pass, passlen, ntpass, ntpasslen,
614 /****************************************************************************
616 *****************************************************************************/
618 BOOL cli_ulogoff(struct cli_state *cli)
620 memset(cli->outbuf,'\0',smb_size);
621 set_message(cli->outbuf,2,0,True);
622 CVAL(cli->outbuf,smb_com) = SMBulogoffX;
623 cli_setup_packet(cli);
624 SSVAL(cli->outbuf,smb_vwv0,0xFF);
625 SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
628 if (!cli_receive_smb(cli))
631 return !cli_is_error(cli);
634 /****************************************************************************
636 ****************************************************************************/
637 BOOL cli_send_tconX(struct cli_state *cli,
638 const char *share, const char *dev, const char *pass, int passlen)
640 fstring fullshare, pword, dos_pword;
642 memset(cli->outbuf,'\0',smb_size);
643 memset(cli->inbuf,'\0',smb_size);
645 fstrcpy(cli->share, share);
647 /* in user level security don't send a password now */
648 if (cli->sec_mode & 1) {
653 if ((cli->sec_mode & 2) && *pass && passlen != 24) {
655 * Non-encrypted passwords - convert to DOS codepage before encryption.
658 clistr_push(cli, dos_pword, pass, -1, STR_TERMINATE);
659 SMBencrypt((uchar *)dos_pword,cli->secblob.data,(uchar *)pword);
661 if((cli->sec_mode & 3) == 0) {
663 * Non-encrypted passwords - convert to DOS codepage before using.
665 passlen = clistr_push(cli, pword, pass, -1, STR_TERMINATE);
667 memcpy(pword, pass, passlen);
671 if (cli->port == 445) {
672 slprintf(fullshare, sizeof(fullshare)-1,
675 slprintf(fullshare, sizeof(fullshare)-1,
676 "\\\\%s\\%s", cli->desthost, share);
679 set_message(cli->outbuf,4, 0, True);
680 CVAL(cli->outbuf,smb_com) = SMBtconX;
681 cli_setup_packet(cli);
683 SSVAL(cli->outbuf,smb_vwv0,0xFF);
684 SSVAL(cli->outbuf,smb_vwv3,passlen);
686 p = smb_buf(cli->outbuf);
687 memcpy(p,pword,passlen);
689 p += clistr_push(cli, p, fullshare, -1, STR_TERMINATE |STR_UPPER);
690 fstrcpy(p, dev); p += strlen(dev)+1;
692 cli_setup_bcc(cli, p);
695 if (!cli_receive_smb(cli))
698 if (cli_is_error(cli)) {
702 fstrcpy(cli->dev, "A:");
704 if (cli->protocol >= PROTOCOL_NT1) {
705 clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE);
708 if (strcasecmp(share,"IPC$")==0) {
709 fstrcpy(cli->dev, "IPC");
712 /* only grab the device if we have a recent protocol level */
713 if (cli->protocol >= PROTOCOL_NT1 &&
714 smb_buflen(cli->inbuf) == 3) {
715 /* almost certainly win95 - enable bug fixes */
719 cli->cnum = SVAL(cli->inbuf,smb_tid);
724 /****************************************************************************
725 send a tree disconnect
726 ****************************************************************************/
727 BOOL cli_tdis(struct cli_state *cli)
729 memset(cli->outbuf,'\0',smb_size);
730 set_message(cli->outbuf,0,0,True);
731 CVAL(cli->outbuf,smb_com) = SMBtdis;
732 SSVAL(cli->outbuf,smb_tid,cli->cnum);
733 cli_setup_packet(cli);
736 if (!cli_receive_smb(cli))
739 return !cli_is_error(cli);
743 /****************************************************************************
744 send a negprot command
745 ****************************************************************************/
746 void cli_negprot_send(struct cli_state *cli)
751 memset(cli->outbuf,'\0',smb_size);
753 /* setup the protocol strings */
754 set_message(cli->outbuf,0,0,True);
756 p = smb_buf(cli->outbuf);
758 prots[numprots].name && prots[numprots].prot<=cli->protocol;
761 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
764 CVAL(cli->outbuf,smb_com) = SMBnegprot;
765 cli_setup_bcc(cli, p);
766 cli_setup_packet(cli);
768 CVAL(smb_buf(cli->outbuf),0) = 2;
774 /****************************************************************************
775 send a negprot command
776 ****************************************************************************/
777 BOOL cli_negprot(struct cli_state *cli)
783 memset(cli->outbuf,'\0',smb_size);
785 /* setup the protocol strings */
786 for (plength=0,numprots=0;
787 prots[numprots].name && prots[numprots].prot<=cli->protocol;
789 plength += strlen(prots[numprots].name)+2;
791 set_message(cli->outbuf,0,plength,True);
793 p = smb_buf(cli->outbuf);
795 prots[numprots].name && prots[numprots].prot<=cli->protocol;
798 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
801 CVAL(cli->outbuf,smb_com) = SMBnegprot;
802 cli_setup_packet(cli);
804 CVAL(smb_buf(cli->outbuf),0) = 2;
807 if (!cli_receive_smb(cli))
810 show_msg(cli->inbuf);
812 if (cli_is_error(cli) ||
813 ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
817 cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
819 if (cli->protocol >= PROTOCOL_NT1) {
821 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
822 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
823 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
824 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
825 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1);
826 cli->serverzone *= 60;
827 /* this time arrives in real GMT */
828 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
829 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
830 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
831 if (cli->capabilities & CAP_RAW_MODE) {
832 cli->readbraw_supported = True;
833 cli->writebraw_supported = True;
835 /* work out if they sent us a workgroup */
836 if (smb_buflen(cli->inbuf) > 8) {
837 clistr_pull(cli, cli->server_domain,
838 smb_buf(cli->inbuf)+8, sizeof(cli->server_domain),
839 smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
841 } else if (cli->protocol >= PROTOCOL_LANMAN1) {
842 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
843 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
844 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
845 cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
846 cli->serverzone *= 60;
847 /* this time is converted to GMT by make_unix_date */
848 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
849 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
850 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
851 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
853 /* the old core protocol */
855 cli->serverzone = TimeDiff(time(NULL));
858 cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
860 /* a way to force ascii SMB */
861 if (getenv("CLI_FORCE_ASCII")) {
862 cli->capabilities &= ~CAP_UNICODE;
869 /****************************************************************************
870 send a session request. see rfc1002.txt 4.3 and 4.3.2
871 ****************************************************************************/
872 BOOL cli_session_request(struct cli_state *cli,
873 struct nmb_name *calling, struct nmb_name *called)
877 extern pstring user_socket_options;
879 /* 445 doesn't have session request */
880 if (cli->port == 445) return True;
882 /* send a session request (RFC 1002) */
883 memcpy(&(cli->calling), calling, sizeof(*calling));
884 memcpy(&(cli->called ), called , sizeof(*called ));
886 /* put in the destination name */
888 name_mangle(cli->called .name, p, cli->called .name_type);
893 name_mangle(cli->calling.name, p, cli->calling.name_type);
896 /* setup the packet length */
897 _smb_setlen(cli->outbuf,len);
898 CVAL(cli->outbuf,0) = 0x81;
902 #endif /* WITH_SSL */
905 DEBUG(5,("Sent session request\n"));
907 if (!cli_receive_smb(cli))
910 if (CVAL(cli->inbuf,0) == 0x84) {
911 /* C. Hoch 9/14/95 Start */
912 /* For information, here is the response structure.
913 * We do the byte-twiddling to for portability.
914 struct RetargetResponse{
922 int port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
923 /* SESSION RETARGET */
924 putip((char *)&cli->dest_ip,cli->inbuf+4);
926 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
930 DEBUG(3,("Retargeted\n"));
932 set_socket_options(cli->fd,user_socket_options);
939 DEBUG(0,("Retarget recursion - failing\n"));
943 ret = cli_session_request(cli, calling, called);
947 } /* C. Hoch 9/14/95 End */
950 if (CVAL(cli->inbuf,0) == 0x83 && CVAL(cli->inbuf,4) == 0x8e){ /* use ssl */
951 if (!sslutil_fd_is_ssl(cli->fd)){
952 if (sslutil_connect(cli->fd) == 0)
956 #endif /* WITH_SSL */
958 if (CVAL(cli->inbuf,0) != 0x82) {
959 /* This is the wrong place to put the error... JRA. */
960 cli->rap_error = CVAL(cli->inbuf,4);
966 /****************************************************************************
967 open the client sockets
968 ****************************************************************************/
969 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
971 extern struct in_addr ipzero;
972 extern pstring user_socket_options;
974 fstrcpy(cli->desthost, host);
976 if (!ip || ip_equal(*ip, ipzero)) {
977 if (!resolve_name( cli->desthost, &cli->dest_ip, 0x20)) {
980 if (ip) *ip = cli->dest_ip;
985 if (getenv("LIBSMB_PROG")) {
986 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
988 /* try 445 first, then 139 */
989 int port = cli->port?cli->port:445;
990 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
992 if (cli->fd == -1 && cli->port == 0) {
994 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
997 if (cli->fd != -1) cli->port = port;
1000 DEBUG(1,("Error connecting to %s (%s)\n",
1001 inet_ntoa(*ip),strerror(errno)));
1005 set_socket_options(cli->fd,user_socket_options);
1010 /****************************************************************************
1011 re-establishes a connection
1012 ****************************************************************************/
1013 BOOL cli_reestablish_connection(struct cli_state *cli)
1015 struct nmb_name calling;
1016 struct nmb_name called;
1020 BOOL do_tcon = False;
1021 int oldfd = cli->fd;
1023 if (!cli->initialised || cli->fd == -1)
1025 DEBUG(3,("cli_reestablish_connection: not connected\n"));
1029 /* copy the parameters necessary to re-establish the connection */
1033 fstrcpy(share, cli->share);
1034 fstrcpy(dev , cli->dev);
1038 memcpy(&called , &(cli->called ), sizeof(called ));
1039 memcpy(&calling, &(cli->calling), sizeof(calling));
1040 fstrcpy(dest_host, cli->full_dest_host_name);
1042 DEBUG(5,("cli_reestablish_connection: %s connecting to %s (ip %s) - %s [%s]\n",
1043 nmb_namestr(&calling), nmb_namestr(&called),
1044 inet_ntoa(cli->dest_ip),
1045 cli->user_name, cli->domain));
1049 if (cli_establish_connection(cli,
1050 dest_host, &cli->dest_ip,
1052 share, dev, False, do_tcon)) {
1053 if ((cli->fd != oldfd) && (oldfd != -1)) {
1061 /****************************************************************************
1062 establishes a connection right up to doing tconX, reading in a password.
1063 ****************************************************************************/
1064 BOOL cli_establish_connection(struct cli_state *cli,
1065 char *dest_host, struct in_addr *dest_ip,
1066 struct nmb_name *calling, struct nmb_name *called,
1067 char *service, char *service_type,
1068 BOOL do_shutdown, BOOL do_tcon)
1070 DEBUG(5,("cli_establish_connection: %s connecting to %s (%s) - %s [%s]\n",
1071 nmb_namestr(calling), nmb_namestr(called), inet_ntoa(*dest_ip),
1072 cli->user_name, cli->domain));
1074 /* establish connection */
1076 if ((!cli->initialised))
1083 if (!cli_connect(cli, dest_host, dest_ip))
1085 DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n",
1086 nmb_namestr(called), inet_ntoa(*dest_ip)));
1091 if (!cli_session_request(cli, calling, called))
1093 DEBUG(1,("failed session request\n"));
1099 if (!cli_negprot(cli))
1101 DEBUG(1,("failed negprot\n"));
1107 if (cli->pwd.cleartext || cli->pwd.null_pwd)
1112 if (cli->pwd.null_pwd)
1114 /* attempt null session */
1120 /* attempt clear-text session */
1121 pwd_get_cleartext(&(cli->pwd), passwd);
1122 pass_len = strlen(passwd);
1125 /* attempt clear-text session */
1126 if (!cli_session_setup(cli, cli->user_name,
1131 DEBUG(1,("failed session setup\n"));
1140 if (!cli_send_tconX(cli, service, service_type,
1141 (char*)passwd, strlen(passwd)))
1143 DEBUG(1,("failed tcon_X\n"));
1154 /* attempt encrypted session */
1155 unsigned char nt_sess_pwd[24];
1156 unsigned char lm_sess_pwd[24];
1158 /* creates (storing a copy of) and then obtains a 24 byte password OWF */
1159 pwd_make_lm_nt_owf(&(cli->pwd), cli->secblob.data);
1160 pwd_get_lm_nt_owf(&(cli->pwd), lm_sess_pwd, nt_sess_pwd);
1162 /* attempt encrypted session */
1163 if (!cli_session_setup(cli, cli->user_name,
1164 (char*)lm_sess_pwd, sizeof(lm_sess_pwd),
1165 (char*)nt_sess_pwd, sizeof(nt_sess_pwd),
1168 DEBUG(1,("failed session setup\n"));
1174 DEBUG(1,("session setup ok\n"));
1176 if (*cli->server_domain || *cli->server_os || *cli->server_type)
1178 DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",
1186 if (!cli_send_tconX(cli, service, service_type,
1187 (char*)nt_sess_pwd, sizeof(nt_sess_pwd)))
1189 DEBUG(1,("failed tcon_X\n"));
1204 /****************************************************************************
1205 Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
1206 ****************************************************************************/
1208 BOOL attempt_netbios_session_request(struct cli_state *cli, char *srchost, char *desthost,
1209 struct in_addr *pdest_ip)
1211 struct nmb_name calling, called;
1213 make_nmb_name(&calling, srchost, 0x0);
1216 * If the called name is an IP address
1217 * then use *SMBSERVER immediately.
1220 if(is_ipaddress(desthost))
1221 make_nmb_name(&called, "*SMBSERVER", 0x20);
1223 make_nmb_name(&called, desthost, 0x20);
1225 if (!cli_session_request(cli, &calling, &called)) {
1226 struct nmb_name smbservername;
1228 make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
1231 * If the name wasn't *SMBSERVER then
1232 * try with *SMBSERVER if the first name fails.
1235 if (nmb_name_equal(&called, &smbservername)) {
1238 * The name used was *SMBSERVER, don't bother with another name.
1241 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
1242 with error %s.\n", desthost, cli_errstr(cli) ));
1249 if (!cli_initialise(cli) ||
1250 !cli_connect(cli, desthost, pdest_ip) ||
1251 !cli_session_request(cli, &calling, &smbservername)) {
1252 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
1253 name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) ));