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_LANMAN1,"LANMAN1.0"},
35 {PROTOCOL_LANMAN1,"Windows for Workgroups 3.1a"},
36 {PROTOCOL_LANMAN2,"LM1.2X002"},
37 {PROTOCOL_NT1,"Samba"},
38 {PROTOCOL_NT1,"LANMAN2.1"},
39 {PROTOCOL_NT1,"NT LM 0.12"},
44 /****************************************************************************
45 do an old lanman2 style session setup
46 ****************************************************************************/
47 static BOOL cli_session_setup_lanman2(struct cli_state *cli, char *user,
48 char *pass, int passlen)
53 if (passlen > sizeof(pword)-1) {
57 /* if in share level security then don't send a password now */
58 if (!(cli->sec_mode & 1)) {
62 if (passlen > 0 && (cli->sec_mode & 2) && passlen != 24) {
63 /* Encrypted mode needed, and non encrypted password supplied. */
65 clistr_push(cli, pword, pass, -1, STR_TERMINATE);
66 SMBencrypt((uchar *)pword,cli->secblob.data,(uchar *)pword);
67 } else if ((cli->sec_mode & 2) && passlen == 24) {
68 /* Encrypted mode needed, and encrypted password supplied. */
69 memcpy(pword, pass, passlen);
70 } else if (passlen > 0) {
71 /* Plaintext mode needed, assume plaintext supplied. */
72 passlen = clistr_push(cli, pword, pass, -1, STR_TERMINATE);
75 /* send a session setup command */
76 memset(cli->outbuf,'\0',smb_size);
77 set_message(cli->outbuf,10, 0, True);
78 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
79 cli_setup_packet(cli);
81 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
82 SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
83 SSVAL(cli->outbuf,smb_vwv3,2);
84 SSVAL(cli->outbuf,smb_vwv4,1);
85 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
86 SSVAL(cli->outbuf,smb_vwv7,passlen);
88 p = smb_buf(cli->outbuf);
89 memcpy(p,pword,passlen);
91 p += clistr_push(cli, p, user, -1, STR_UPPER|STR_TERMINATE);
92 cli_setup_bcc(cli, p);
95 if (!cli_receive_smb(cli))
100 if (cli_is_error(cli)) {
104 /* use the returned vuid from now on */
105 cli->vuid = SVAL(cli->inbuf,smb_uid);
106 fstrcpy(cli->user_name, user);
112 /****************************************************************************
113 work out suitable capabilities to offer the server
114 ****************************************************************************/
115 static uint32 cli_session_setup_capabilities(struct cli_state *cli)
117 uint32 capabilities = CAP_NT_SMBS;
119 /* Set the CLI_FORCE_DOSERR environment variable to test
120 client routines using DOS errors instead of STATUS32
121 ones. This intended only as a temporary hack. */
122 if (!getenv("CLI_FORCE_DOSERR")) {
123 capabilities |= CAP_STATUS32;
126 if (cli->use_level_II_oplocks) {
127 capabilities |= CAP_LEVEL_II_OPLOCKS;
130 if (cli->capabilities & CAP_UNICODE) {
131 capabilities |= CAP_UNICODE;
138 /****************************************************************************
139 do a NT1 guest session setup
140 ****************************************************************************/
141 static BOOL cli_session_setup_guest(struct cli_state *cli)
144 uint32 capabilities = cli_session_setup_capabilities(cli);
146 set_message(cli->outbuf,13,0,True);
147 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
148 cli_setup_packet(cli);
150 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
151 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
152 SSVAL(cli->outbuf,smb_vwv3,2);
153 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
154 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
155 SSVAL(cli->outbuf,smb_vwv7,0);
156 SSVAL(cli->outbuf,smb_vwv8,0);
157 SIVAL(cli->outbuf,smb_vwv11,capabilities);
158 p = smb_buf(cli->outbuf);
159 p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* username */
160 p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* workgroup */
161 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
162 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
163 cli_setup_bcc(cli, p);
166 if (!cli_receive_smb(cli))
169 show_msg(cli->inbuf);
171 if (cli_is_error(cli)) {
175 cli->vuid = SVAL(cli->inbuf,smb_uid);
177 p = smb_buf(cli->inbuf);
178 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
179 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
180 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
182 fstrcpy(cli->user_name, "");
188 /****************************************************************************
189 do a NT1 plaintext session setup
190 ****************************************************************************/
191 static BOOL cli_session_setup_plaintext(struct cli_state *cli, char *user,
192 char *pass, char *workgroup)
194 uint32 capabilities = cli_session_setup_capabilities(cli);
199 passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
201 set_message(cli->outbuf,13,0,True);
202 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
203 cli_setup_packet(cli);
205 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
206 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
207 SSVAL(cli->outbuf,smb_vwv3,2);
208 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
209 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
210 SSVAL(cli->outbuf,smb_vwv7,passlen);
211 SSVAL(cli->outbuf,smb_vwv8,0);
212 SIVAL(cli->outbuf,smb_vwv11,capabilities);
213 p = smb_buf(cli->outbuf);
214 memcpy(p, pword, passlen);
216 p += clistr_push(cli, p, user, -1, STR_TERMINATE); /* username */
217 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE); /* workgroup */
218 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
219 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
220 cli_setup_bcc(cli, p);
223 if (!cli_receive_smb(cli))
226 show_msg(cli->inbuf);
228 if (cli_is_error(cli)) {
232 cli->vuid = SVAL(cli->inbuf,smb_uid);
233 p = smb_buf(cli->inbuf);
234 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
235 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
236 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
237 fstrcpy(cli->user_name, user);
243 /****************************************************************************
244 do a NT1 NTLM/LM encrypted session setup
245 ****************************************************************************/
246 static BOOL cli_session_setup_nt1(struct cli_state *cli, char *user,
247 char *pass, int passlen,
248 char *ntpass, int ntpasslen,
251 uint32 capabilities = cli_session_setup_capabilities(cli);
252 fstring pword, ntpword;
255 if (passlen > sizeof(pword)-1 || ntpasslen > sizeof(ntpword)-1) {
260 /* non encrypted password supplied. */
263 clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
264 clistr_push(cli, ntpword, ntpass, sizeof(ntpword), STR_TERMINATE);
265 SMBencrypt((uchar *)pword,cli->secblob.data,(uchar *)pword);
266 SMBNTencrypt((uchar *)ntpword,cli->secblob.data,(uchar *)ntpword);
268 memcpy(pword, pass, passlen);
269 memcpy(ntpword, ntpass, ntpasslen);
272 /* send a session setup command */
273 memset(cli->outbuf,'\0',smb_size);
275 set_message(cli->outbuf,13,0,True);
276 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
277 cli_setup_packet(cli);
279 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
280 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
281 SSVAL(cli->outbuf,smb_vwv3,2);
282 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
283 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
284 SSVAL(cli->outbuf,smb_vwv7,passlen);
285 SSVAL(cli->outbuf,smb_vwv8,ntpasslen);
286 SIVAL(cli->outbuf,smb_vwv11,capabilities);
287 p = smb_buf(cli->outbuf);
288 memcpy(p,pword,passlen); p += passlen;
289 memcpy(p,ntpword,ntpasslen); p += ntpasslen;
290 p += clistr_push(cli, p, user, -1, STR_TERMINATE|STR_UPPER);
291 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
292 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
293 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
294 cli_setup_bcc(cli, p);
297 if (!cli_receive_smb(cli))
300 show_msg(cli->inbuf);
302 if (cli_is_error(cli)) {
306 /* use the returned vuid from now on */
307 cli->vuid = SVAL(cli->inbuf,smb_uid);
309 p = smb_buf(cli->inbuf);
310 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
311 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
312 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
314 fstrcpy(cli->user_name, user);
320 /****************************************************************************
321 send a extended security session setup blob, returning a reply blob
322 ****************************************************************************/
323 static DATA_BLOB cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob)
325 uint32 capabilities = cli_session_setup_capabilities(cli);
329 blob2 = data_blob(NULL, 0);
331 capabilities |= CAP_EXTENDED_SECURITY;
333 /* send a session setup command */
334 memset(cli->outbuf,'\0',smb_size);
336 set_message(cli->outbuf,12,0,True);
337 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
338 cli_setup_packet(cli);
340 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
341 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
342 SSVAL(cli->outbuf,smb_vwv3,2);
343 SSVAL(cli->outbuf,smb_vwv4,0);
344 SIVAL(cli->outbuf,smb_vwv5,0);
345 SSVAL(cli->outbuf,smb_vwv7,blob.length);
346 SIVAL(cli->outbuf,smb_vwv10,capabilities);
347 p = smb_buf(cli->outbuf);
348 memcpy(p, blob.data, blob.length);
350 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
351 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
352 cli_setup_bcc(cli, p);
355 if (!cli_receive_smb(cli))
358 show_msg(cli->inbuf);
360 if (cli_is_error(cli) && !NT_STATUS_EQUAL(cli_nt_error(cli),
361 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
365 /* use the returned vuid from now on */
366 cli->vuid = SVAL(cli->inbuf,smb_uid);
368 p = smb_buf(cli->inbuf);
370 blob2 = data_blob(p, SVAL(cli->inbuf, smb_vwv3));
373 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
374 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
375 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
382 /****************************************************************************
383 do a spnego/kerberos encrypted session setup
384 ****************************************************************************/
385 static BOOL cli_session_setup_kerberos(struct cli_state *cli, char *principle, char *workgroup)
387 DATA_BLOB blob2, negTokenTarg;
389 /* generate the encapsulated kerberos5 ticket */
390 negTokenTarg = spnego_gen_negTokenTarg(cli, principle);
392 if (!negTokenTarg.data) return False;
394 blob2 = cli_session_setup_blob(cli, negTokenTarg);
396 /* we don't need this blob for kerberos */
397 data_blob_free(blob2);
399 return !cli_is_error(cli);
403 /****************************************************************************
404 do a spnego/NTLMSSP encrypted session setup
405 ****************************************************************************/
406 static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, char *user,
407 char *pass, char *workgroup)
409 const char *mechs[] = {OID_NTLMSSP, NULL};
411 DATA_BLOB blob, chal1, chal2, auth;
413 uint8 nthash[24], lmhash[24], sess_key[16];
416 neg_flags = NTLMSSP_NEGOTIATE_UNICODE |
417 NTLMSSP_NEGOTIATE_LM_KEY |
418 NTLMSSP_NEGOTIATE_NTLM;
420 memset(sess_key, 0, 16);
422 /* generate the ntlmssp negotiate packet */
423 msrpc_gen(&blob, "CddB",
429 /* and wrap it in a SPNEGO wrapper */
430 msg1 = gen_negTokenTarg(mechs, blob);
431 data_blob_free(blob);
433 /* now send that blob on its way */
434 blob = cli_session_setup_blob(cli, msg1);
436 data_blob_free(msg1);
438 if (!NT_STATUS_EQUAL(cli_nt_error(cli), NT_STATUS_MORE_PROCESSING_REQUIRED)) {
443 file_save("chal.dat", blob.data, blob.length);
446 /* the server gives us back two challenges */
447 if (!spnego_parse_challenge(blob, &chal1, &chal2)) {
451 data_blob_free(blob);
453 /* encrypt the password with the challenge */
454 memcpy(challenge, chal1.data + 24, 8);
455 SMBencrypt(pass, challenge,lmhash);
456 SMBNTencrypt(pass, challenge,nthash);
458 data_blob_free(chal1);
459 data_blob_free(chal2);
461 /* this generates the actual auth packet */
462 msrpc_gen(&blob, "CdBBUUUBd",
473 /* wrap it in SPNEGO */
474 auth = spnego_gen_auth(blob);
476 data_blob_free(blob);
478 /* now send the auth packet and we should be done */
479 blob = cli_session_setup_blob(cli, auth);
481 data_blob_free(auth);
482 data_blob_free(blob);
484 return !cli_is_error(cli);
488 /****************************************************************************
489 do a spnego encrypted session setup
490 ****************************************************************************/
491 static BOOL cli_session_setup_spnego(struct cli_state *cli, char *user,
492 char *pass, char *workgroup)
495 char *OIDs[ASN1_MAX_OIDS];
498 BOOL got_kerberos_mechanism = False;
500 /* the server might not even do spnego */
501 if (cli->secblob.length == 16) {
502 DEBUG(3,("server didn't supply a full spnego negprot\n"));
507 file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
510 /* the server sent us the first part of the SPNEGO exchange in the negprot
512 if (!spnego_parse_negTokenInit(cli->secblob, guid, OIDs, &principle)) {
516 /* make sure the server understands kerberos */
517 for (i=0;OIDs[i];i++) {
518 DEBUG(3,("got OID=%s\n", OIDs[i]));
519 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0) {
520 got_kerberos_mechanism = True;
524 DEBUG(3,("got principle=%s\n", principle));
526 fstrcpy(cli->user_name, user);
529 if (got_kerberos_mechanism && cli->use_kerberos) {
530 return cli_session_setup_kerberos(cli, principle, workgroup);
538 return cli_session_setup_ntlmssp(cli, user, pass, workgroup);
542 /****************************************************************************
543 Send a session setup. The username and workgroup is in UNIX character
544 format and must be converted to DOS codepage format before sending. If the
545 password is in plaintext, the same should be done.
546 ****************************************************************************/
547 BOOL cli_session_setup(struct cli_state *cli,
549 char *pass, int passlen,
550 char *ntpass, int ntpasslen,
556 /* allow for workgroups as part of the username */
557 fstrcpy(user2, user);
558 if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/'))) {
564 if (cli->protocol < PROTOCOL_LANMAN1)
567 /* now work out what sort of session setup we are going to
568 do. I have split this into separate functions to make the
569 flow a bit easier to understand (tridge) */
571 /* if its an older server then we have to use the older request format */
572 if (cli->protocol < PROTOCOL_NT1) {
573 return cli_session_setup_lanman2(cli, user, pass, passlen);
576 /* if no user is supplied then we have to do an anonymous connection.
577 passwords are ignored */
578 if (!user || !*user) {
579 return cli_session_setup_guest(cli);
582 /* if the server is share level then send a plaintext null
583 password at this point. The password is sent in the tree
585 if ((cli->sec_mode & 1) == 0) {
586 return cli_session_setup_plaintext(cli, user, "", workgroup);
589 /* if the server doesn't support encryption then we have to use plaintext. The
590 second password is ignored */
591 if ((cli->sec_mode & 2) == 0) {
592 return cli_session_setup_plaintext(cli, user, pass, workgroup);
595 /* if the server supports extended security then use SPNEGO */
596 if (cli->capabilities & CAP_EXTENDED_SECURITY) {
597 return cli_session_setup_spnego(cli, user, pass, workgroup);
600 /* otherwise do a NT1 style session setup */
601 return cli_session_setup_nt1(cli, user,
602 pass, passlen, ntpass, ntpasslen,
606 /****************************************************************************
608 *****************************************************************************/
610 BOOL cli_ulogoff(struct cli_state *cli)
612 memset(cli->outbuf,'\0',smb_size);
613 set_message(cli->outbuf,2,0,True);
614 CVAL(cli->outbuf,smb_com) = SMBulogoffX;
615 cli_setup_packet(cli);
616 SSVAL(cli->outbuf,smb_vwv0,0xFF);
617 SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
620 if (!cli_receive_smb(cli))
623 return !cli_is_error(cli);
626 /****************************************************************************
628 ****************************************************************************/
629 BOOL cli_send_tconX(struct cli_state *cli,
630 const char *share, const char *dev, const char *pass, int passlen)
632 fstring fullshare, pword, dos_pword;
634 memset(cli->outbuf,'\0',smb_size);
635 memset(cli->inbuf,'\0',smb_size);
637 fstrcpy(cli->share, share);
639 /* in user level security don't send a password now */
640 if (cli->sec_mode & 1) {
645 if ((cli->sec_mode & 2) && *pass && passlen != 24) {
647 * Non-encrypted passwords - convert to DOS codepage before encryption.
650 clistr_push(cli, dos_pword, pass, -1, STR_TERMINATE);
651 SMBencrypt((uchar *)dos_pword,cli->secblob.data,(uchar *)pword);
653 if((cli->sec_mode & 3) == 0) {
655 * Non-encrypted passwords - convert to DOS codepage before using.
657 passlen = clistr_push(cli, pword, pass, -1, STR_TERMINATE);
659 memcpy(pword, pass, passlen);
663 if (cli->port == 445) {
664 slprintf(fullshare, sizeof(fullshare)-1,
667 slprintf(fullshare, sizeof(fullshare)-1,
668 "\\\\%s\\%s", cli->desthost, share);
671 set_message(cli->outbuf,4, 0, True);
672 CVAL(cli->outbuf,smb_com) = SMBtconX;
673 cli_setup_packet(cli);
675 SSVAL(cli->outbuf,smb_vwv0,0xFF);
676 SSVAL(cli->outbuf,smb_vwv3,passlen);
678 p = smb_buf(cli->outbuf);
679 memcpy(p,pword,passlen);
681 p += clistr_push(cli, p, fullshare, -1, STR_TERMINATE |STR_UPPER);
682 fstrcpy(p, dev); p += strlen(dev)+1;
684 cli_setup_bcc(cli, p);
687 if (!cli_receive_smb(cli))
690 if (cli_is_error(cli)) {
694 fstrcpy(cli->dev, "A:");
696 if (cli->protocol >= PROTOCOL_NT1) {
697 clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE);
700 if (strcasecmp(share,"IPC$")==0) {
701 fstrcpy(cli->dev, "IPC");
704 /* only grab the device if we have a recent protocol level */
705 if (cli->protocol >= PROTOCOL_NT1 &&
706 smb_buflen(cli->inbuf) == 3) {
707 /* almost certainly win95 - enable bug fixes */
711 cli->cnum = SVAL(cli->inbuf,smb_tid);
716 /****************************************************************************
717 send a tree disconnect
718 ****************************************************************************/
719 BOOL cli_tdis(struct cli_state *cli)
721 memset(cli->outbuf,'\0',smb_size);
722 set_message(cli->outbuf,0,0,True);
723 CVAL(cli->outbuf,smb_com) = SMBtdis;
724 SSVAL(cli->outbuf,smb_tid,cli->cnum);
725 cli_setup_packet(cli);
728 if (!cli_receive_smb(cli))
731 return !cli_is_error(cli);
735 /****************************************************************************
736 send a negprot command
737 ****************************************************************************/
738 void cli_negprot_send(struct cli_state *cli)
743 memset(cli->outbuf,'\0',smb_size);
745 /* setup the protocol strings */
746 set_message(cli->outbuf,0,0,True);
748 p = smb_buf(cli->outbuf);
750 prots[numprots].name && prots[numprots].prot<=cli->protocol;
753 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
756 CVAL(cli->outbuf,smb_com) = SMBnegprot;
757 cli_setup_bcc(cli, p);
758 cli_setup_packet(cli);
760 CVAL(smb_buf(cli->outbuf),0) = 2;
766 /****************************************************************************
767 send a negprot command
768 ****************************************************************************/
769 BOOL cli_negprot(struct cli_state *cli)
775 memset(cli->outbuf,'\0',smb_size);
777 /* setup the protocol strings */
778 for (plength=0,numprots=0;
779 prots[numprots].name && prots[numprots].prot<=cli->protocol;
781 plength += strlen(prots[numprots].name)+2;
783 set_message(cli->outbuf,0,plength,True);
785 p = smb_buf(cli->outbuf);
787 prots[numprots].name && prots[numprots].prot<=cli->protocol;
790 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
793 CVAL(cli->outbuf,smb_com) = SMBnegprot;
794 cli_setup_packet(cli);
796 CVAL(smb_buf(cli->outbuf),0) = 2;
799 if (!cli_receive_smb(cli))
802 show_msg(cli->inbuf);
804 if (cli_is_error(cli) ||
805 ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
809 cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
811 if (cli->protocol >= PROTOCOL_NT1) {
813 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
814 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
815 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
816 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
817 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1);
818 cli->serverzone *= 60;
819 /* this time arrives in real GMT */
820 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
821 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
822 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
823 if (cli->capabilities & CAP_RAW_MODE) {
824 cli->readbraw_supported = True;
825 cli->writebraw_supported = True;
827 /* work out if they sent us a workgroup */
828 if (smb_buflen(cli->inbuf) > 8) {
829 clistr_pull(cli, cli->server_domain,
830 smb_buf(cli->inbuf)+8, sizeof(cli->server_domain),
831 smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
833 } else if (cli->protocol >= PROTOCOL_LANMAN1) {
834 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
835 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
836 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
837 cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
838 cli->serverzone *= 60;
839 /* this time is converted to GMT by make_unix_date */
840 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
841 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
842 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
843 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
845 /* the old core protocol */
847 cli->serverzone = TimeDiff(time(NULL));
850 cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
852 /* a way to force ascii SMB */
853 if (getenv("CLI_FORCE_ASCII")) {
854 cli->capabilities &= ~CAP_UNICODE;
861 /****************************************************************************
862 send a session request. see rfc1002.txt 4.3 and 4.3.2
863 ****************************************************************************/
864 BOOL cli_session_request(struct cli_state *cli,
865 struct nmb_name *calling, struct nmb_name *called)
869 extern pstring user_socket_options;
871 /* 445 doesn't have session request */
872 if (cli->port == 445) return True;
874 /* send a session request (RFC 1002) */
875 memcpy(&(cli->calling), calling, sizeof(*calling));
876 memcpy(&(cli->called ), called , sizeof(*called ));
878 /* put in the destination name */
880 name_mangle(cli->called .name, p, cli->called .name_type);
885 name_mangle(cli->calling.name, p, cli->calling.name_type);
888 /* setup the packet length */
889 _smb_setlen(cli->outbuf,len);
890 CVAL(cli->outbuf,0) = 0x81;
894 #endif /* WITH_SSL */
897 DEBUG(5,("Sent session request\n"));
899 if (!cli_receive_smb(cli))
902 if (CVAL(cli->inbuf,0) == 0x84) {
903 /* C. Hoch 9/14/95 Start */
904 /* For information, here is the response structure.
905 * We do the byte-twiddling to for portability.
906 struct RetargetResponse{
914 int port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
915 /* SESSION RETARGET */
916 putip((char *)&cli->dest_ip,cli->inbuf+4);
918 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
922 DEBUG(3,("Retargeted\n"));
924 set_socket_options(cli->fd,user_socket_options);
931 DEBUG(0,("Retarget recursion - failing\n"));
935 ret = cli_session_request(cli, calling, called);
939 } /* C. Hoch 9/14/95 End */
942 if (CVAL(cli->inbuf,0) == 0x83 && CVAL(cli->inbuf,4) == 0x8e){ /* use ssl */
943 if (!sslutil_fd_is_ssl(cli->fd)){
944 if (sslutil_connect(cli->fd) == 0)
948 #endif /* WITH_SSL */
950 if (CVAL(cli->inbuf,0) != 0x82) {
951 /* This is the wrong place to put the error... JRA. */
952 cli->rap_error = CVAL(cli->inbuf,4);
958 /****************************************************************************
959 open the client sockets
960 ****************************************************************************/
961 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
963 extern struct in_addr ipzero;
964 extern pstring user_socket_options;
966 fstrcpy(cli->desthost, host);
968 if (!ip || ip_equal(*ip, ipzero)) {
969 if (!resolve_name( cli->desthost, &cli->dest_ip, 0x20)) {
972 if (ip) *ip = cli->dest_ip;
977 if (getenv("LIBSMB_PROG")) {
978 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
980 /* try 445 first, then 139 */
981 int port = cli->port?cli->port:445;
982 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
984 if (cli->fd == -1 && cli->port == 0) {
986 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
989 if (cli->fd != -1) cli->port = port;
992 DEBUG(1,("Error connecting to %s (%s)\n",
993 inet_ntoa(*ip),strerror(errno)));
997 set_socket_options(cli->fd,user_socket_options);
1002 /****************************************************************************
1003 re-establishes a connection
1004 ****************************************************************************/
1005 BOOL cli_reestablish_connection(struct cli_state *cli)
1007 struct nmb_name calling;
1008 struct nmb_name called;
1012 BOOL do_tcon = False;
1013 int oldfd = cli->fd;
1015 if (!cli->initialised || cli->fd == -1)
1017 DEBUG(3,("cli_reestablish_connection: not connected\n"));
1021 /* copy the parameters necessary to re-establish the connection */
1025 fstrcpy(share, cli->share);
1026 fstrcpy(dev , cli->dev);
1030 memcpy(&called , &(cli->called ), sizeof(called ));
1031 memcpy(&calling, &(cli->calling), sizeof(calling));
1032 fstrcpy(dest_host, cli->full_dest_host_name);
1034 DEBUG(5,("cli_reestablish_connection: %s connecting to %s (ip %s) - %s [%s]\n",
1035 nmb_namestr(&calling), nmb_namestr(&called),
1036 inet_ntoa(cli->dest_ip),
1037 cli->user_name, cli->domain));
1041 if (cli_establish_connection(cli,
1042 dest_host, &cli->dest_ip,
1044 share, dev, False, do_tcon)) {
1045 if ((cli->fd != oldfd) && (oldfd != -1)) {
1053 /****************************************************************************
1054 establishes a connection right up to doing tconX, reading in a password.
1055 ****************************************************************************/
1056 BOOL cli_establish_connection(struct cli_state *cli,
1057 char *dest_host, struct in_addr *dest_ip,
1058 struct nmb_name *calling, struct nmb_name *called,
1059 char *service, char *service_type,
1060 BOOL do_shutdown, BOOL do_tcon)
1062 DEBUG(5,("cli_establish_connection: %s connecting to %s (%s) - %s [%s]\n",
1063 nmb_namestr(calling), nmb_namestr(called), inet_ntoa(*dest_ip),
1064 cli->user_name, cli->domain));
1066 /* establish connection */
1068 if ((!cli->initialised))
1075 if (!cli_connect(cli, dest_host, dest_ip))
1077 DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n",
1078 nmb_namestr(called), inet_ntoa(*dest_ip)));
1083 if (!cli_session_request(cli, calling, called))
1085 DEBUG(1,("failed session request\n"));
1091 if (!cli_negprot(cli))
1093 DEBUG(1,("failed negprot\n"));
1099 if (cli->pwd.cleartext || cli->pwd.null_pwd)
1104 if (cli->pwd.null_pwd)
1106 /* attempt null session */
1112 /* attempt clear-text session */
1113 pwd_get_cleartext(&(cli->pwd), passwd);
1114 pass_len = strlen(passwd);
1117 /* attempt clear-text session */
1118 if (!cli_session_setup(cli, cli->user_name,
1123 DEBUG(1,("failed session setup\n"));
1132 if (!cli_send_tconX(cli, service, service_type,
1133 (char*)passwd, strlen(passwd)))
1135 DEBUG(1,("failed tcon_X\n"));
1146 /* attempt encrypted session */
1147 unsigned char nt_sess_pwd[24];
1148 unsigned char lm_sess_pwd[24];
1150 /* creates (storing a copy of) and then obtains a 24 byte password OWF */
1151 pwd_make_lm_nt_owf(&(cli->pwd), cli->secblob.data);
1152 pwd_get_lm_nt_owf(&(cli->pwd), lm_sess_pwd, nt_sess_pwd);
1154 /* attempt encrypted session */
1155 if (!cli_session_setup(cli, cli->user_name,
1156 (char*)lm_sess_pwd, sizeof(lm_sess_pwd),
1157 (char*)nt_sess_pwd, sizeof(nt_sess_pwd),
1160 DEBUG(1,("failed session setup\n"));
1166 DEBUG(1,("session setup ok\n"));
1168 if (*cli->server_domain || *cli->server_os || *cli->server_type)
1170 DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",
1178 if (!cli_send_tconX(cli, service, service_type,
1179 (char*)nt_sess_pwd, sizeof(nt_sess_pwd)))
1181 DEBUG(1,("failed tcon_X\n"));
1196 /****************************************************************************
1197 Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
1198 ****************************************************************************/
1200 BOOL attempt_netbios_session_request(struct cli_state *cli, char *srchost, char *desthost,
1201 struct in_addr *pdest_ip)
1203 struct nmb_name calling, called;
1205 make_nmb_name(&calling, srchost, 0x0);
1208 * If the called name is an IP address
1209 * then use *SMBSERVER immediately.
1212 if(is_ipaddress(desthost))
1213 make_nmb_name(&called, "*SMBSERVER", 0x20);
1215 make_nmb_name(&called, desthost, 0x20);
1217 if (!cli_session_request(cli, &calling, &called)) {
1218 struct nmb_name smbservername;
1220 make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
1223 * If the name wasn't *SMBSERVER then
1224 * try with *SMBSERVER if the first name fails.
1227 if (nmb_name_equal(&called, &smbservername)) {
1230 * The name used was *SMBSERVER, don't bother with another name.
1233 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
1234 with error %s.\n", desthost, cli_errstr(cli) ));
1241 if (!cli_initialise(cli) ||
1242 !cli_connect(cli, desthost, pdest_ip) ||
1243 !cli_session_request(cli, &calling, &smbservername)) {
1244 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
1245 name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) ));