2 Unix SMB/CIFS implementation.
3 client connect/disconnect routines
4 Copyright (C) Andrew Tridgell 1994-1998
5 Copyright (C) Andrew Barteltt 2001-2002
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.
31 {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"},
32 {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
33 {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
34 {PROTOCOL_LANMAN1,"LANMAN1.0"},
35 {PROTOCOL_LANMAN2,"LM1.2X002"},
36 {PROTOCOL_LANMAN2,"DOS LANMAN2.1"},
37 {PROTOCOL_LANMAN2,"Samba"},
38 {PROTOCOL_NT1,"NT LANMAN 1.0"},
39 {PROTOCOL_NT1,"NT LM 0.12"},
43 /****************************************************************************
44 Do an old lanman2 style session setup.
45 ****************************************************************************/
47 static BOOL cli_session_setup_lanman2(struct cli_state *cli, char *user,
48 char *pass, int passlen, const char *workgroup)
53 if (passlen > sizeof(pword)-1) {
57 /* if in share level security then don't send a password now */
58 if (!(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL)) {
62 if (passlen > 0 && (cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen != 24) {
63 /* Encrypted mode needed, and non encrypted password supplied. */
65 SMBencrypt(pass,cli->secblob.data,(uchar *)pword);
66 } else if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen == 24) {
67 /* Encrypted mode needed, and encrypted password supplied. */
68 memcpy(pword, pass, passlen);
69 } else if (passlen > 0) {
70 /* Plaintext mode needed, assume plaintext supplied. */
71 passlen = clistr_push(cli, pword, pass, -1, STR_TERMINATE);
74 /* send a session setup command */
75 memset(cli->outbuf,'\0',smb_size);
76 set_message(cli->outbuf,10, 0, True);
77 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
78 cli_setup_packet(cli);
80 SCVAL(cli->outbuf,smb_vwv0,0xFF);
81 SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
82 SSVAL(cli->outbuf,smb_vwv3,2);
83 SSVAL(cli->outbuf,smb_vwv4,1);
84 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
85 SSVAL(cli->outbuf,smb_vwv7,passlen);
87 p = smb_buf(cli->outbuf);
88 memcpy(p,pword,passlen);
90 p += clistr_push(cli, p, user, -1, STR_TERMINATE|STR_UPPER);
91 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
92 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
93 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
94 cli_setup_bcc(cli, p);
97 if (!cli_receive_smb(cli))
100 show_msg(cli->inbuf);
102 if (cli_is_error(cli)) {
106 /* use the returned vuid from now on */
107 cli->vuid = SVAL(cli->inbuf,smb_uid);
108 fstrcpy(cli->user_name, user);
113 /****************************************************************************
114 Work out suitable capabilities to offer the server.
115 ****************************************************************************/
117 static uint32 cli_session_setup_capabilities(struct cli_state *cli)
119 uint32 capabilities = CAP_NT_SMBS;
121 if (!cli->force_dos_errors) {
122 capabilities |= CAP_STATUS32;
125 if (cli->use_level_II_oplocks) {
126 capabilities |= CAP_LEVEL_II_OPLOCKS;
129 if (cli->capabilities & CAP_UNICODE) {
130 capabilities |= CAP_UNICODE;
136 /****************************************************************************
137 Do a NT1 guest session setup.
138 ****************************************************************************/
140 static BOOL cli_session_setup_guest(struct cli_state *cli)
143 uint32 capabilities = cli_session_setup_capabilities(cli);
145 set_message(cli->outbuf,13,0,True);
146 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
147 cli_setup_packet(cli);
149 SCVAL(cli->outbuf,smb_vwv0,0xFF);
150 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
151 SSVAL(cli->outbuf,smb_vwv3,2);
152 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
153 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
154 SSVAL(cli->outbuf,smb_vwv7,0);
155 SSVAL(cli->outbuf,smb_vwv8,0);
156 SIVAL(cli->outbuf,smb_vwv11,capabilities);
157 p = smb_buf(cli->outbuf);
158 p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* username */
159 p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* workgroup */
160 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
161 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
162 cli_setup_bcc(cli, p);
165 if (!cli_receive_smb(cli))
168 show_msg(cli->inbuf);
170 if (cli_is_error(cli)) {
174 cli->vuid = SVAL(cli->inbuf,smb_uid);
176 p = smb_buf(cli->inbuf);
177 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
178 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
179 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
181 fstrcpy(cli->user_name, "");
186 /****************************************************************************
187 Do a NT1 plaintext session setup.
188 ****************************************************************************/
190 static BOOL cli_session_setup_plaintext(struct cli_state *cli, char *user,
191 char *pass, char *workgroup)
193 uint32 capabilities = cli_session_setup_capabilities(cli);
198 passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE|STR_ASCII);
200 set_message(cli->outbuf,13,0,True);
201 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
202 cli_setup_packet(cli);
204 SCVAL(cli->outbuf,smb_vwv0,0xFF);
205 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
206 SSVAL(cli->outbuf,smb_vwv3,2);
207 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
208 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
209 SSVAL(cli->outbuf,smb_vwv7,passlen);
210 SSVAL(cli->outbuf,smb_vwv8,0);
211 SIVAL(cli->outbuf,smb_vwv11,capabilities);
212 p = smb_buf(cli->outbuf);
213 memcpy(p, pword, passlen);
215 p += clistr_push(cli, p, user, -1, STR_TERMINATE); /* username */
216 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE); /* workgroup */
217 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
218 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
219 cli_setup_bcc(cli, p);
222 if (!cli_receive_smb(cli))
225 show_msg(cli->inbuf);
227 if (cli_is_error(cli)) {
231 cli->vuid = SVAL(cli->inbuf,smb_uid);
232 p = smb_buf(cli->inbuf);
233 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
234 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
235 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
236 fstrcpy(cli->user_name, user);
243 do a NT1 NTLM/LM encrypted session setup
244 @param cli client state to create do session setup on
246 @param pass *either* cleartext password (passlen !=24) or LM response.
247 @param ntpass NT response, implies ntpasslen >=24, implies pass is not clear
248 @param workgroup The user's domain.
251 static BOOL cli_session_setup_nt1(struct cli_state *cli, char *user,
252 char *pass, int passlen,
253 char *ntpass, int ntpasslen,
256 uint32 capabilities = cli_session_setup_capabilities(cli);
257 fstring pword, ntpword;
259 BOOL tried_signing = False;
261 if (passlen > sizeof(pword)-1 || ntpasslen > sizeof(ntpword)-1) {
266 /* non encrypted password supplied. Ignore ntpass. */
269 SMBencrypt(pass,cli->secblob.data,(uchar *)pword);
270 SMBNTencrypt(pass,cli->secblob.data,(uchar *)ntpword);
271 if (!cli->sign_info.use_smb_signing && cli->sign_info.negotiated_smb_signing) {
272 cli_calculate_mac_key(cli, pass, (uchar *)ntpword);
273 tried_signing = True;
276 memcpy(pword, pass, passlen);
277 memcpy(ntpword, ntpass, ntpasslen);
280 /* send a session setup command */
281 memset(cli->outbuf,'\0',smb_size);
283 set_message(cli->outbuf,13,0,True);
284 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
285 cli_setup_packet(cli);
287 SCVAL(cli->outbuf,smb_vwv0,0xFF);
288 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
289 SSVAL(cli->outbuf,smb_vwv3,2);
290 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
291 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
292 SSVAL(cli->outbuf,smb_vwv7,passlen);
293 SSVAL(cli->outbuf,smb_vwv8,ntpasslen);
294 SIVAL(cli->outbuf,smb_vwv11,capabilities);
295 p = smb_buf(cli->outbuf);
296 memcpy(p,pword,passlen); p += passlen;
297 memcpy(p,ntpword,ntpasslen); p += ntpasslen;
298 p += clistr_push(cli, p, user, -1, STR_TERMINATE|STR_UPPER);
299 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
300 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
301 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
302 cli_setup_bcc(cli, p);
305 if (!cli_receive_smb(cli))
308 show_msg(cli->inbuf);
310 if (tried_signing && (cli_is_error(cli) || SVAL(cli->inbuf,smb_vwv2) /* guest */)) {
311 /* We only use it if we have a successful non-guest connect */
312 cli->sign_info.use_smb_signing = False;
315 if (cli_is_error(cli)) {
319 /* use the returned vuid from now on */
320 cli->vuid = SVAL(cli->inbuf,smb_uid);
322 p = smb_buf(cli->inbuf);
323 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
324 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
325 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
327 fstrcpy(cli->user_name, user);
332 /****************************************************************************
333 Send a extended security session setup blob, returning a reply blob.
334 ****************************************************************************/
336 static DATA_BLOB cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob)
338 uint32 capabilities = cli_session_setup_capabilities(cli);
343 blob2 = data_blob(NULL, 0);
345 capabilities |= CAP_EXTENDED_SECURITY;
347 /* send a session setup command */
348 memset(cli->outbuf,'\0',smb_size);
350 set_message(cli->outbuf,12,0,True);
351 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
352 cli_setup_packet(cli);
354 SCVAL(cli->outbuf,smb_vwv0,0xFF);
355 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
356 SSVAL(cli->outbuf,smb_vwv3,2);
357 SSVAL(cli->outbuf,smb_vwv4,1);
358 SIVAL(cli->outbuf,smb_vwv5,0);
359 SSVAL(cli->outbuf,smb_vwv7,blob.length);
360 SIVAL(cli->outbuf,smb_vwv10,capabilities);
361 p = smb_buf(cli->outbuf);
362 memcpy(p, blob.data, blob.length);
364 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
365 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
366 cli_setup_bcc(cli, p);
369 if (!cli_receive_smb(cli))
372 show_msg(cli->inbuf);
374 if (cli_is_error(cli) && !NT_STATUS_EQUAL(cli_nt_error(cli),
375 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
379 /* use the returned vuid from now on */
380 cli->vuid = SVAL(cli->inbuf,smb_uid);
382 p = smb_buf(cli->inbuf);
384 blob2 = data_blob(p, SVAL(cli->inbuf, smb_vwv3));
387 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
389 /* w2k with kerberos doesn't properly null terminate this field */
390 len = smb_buflen(cli->inbuf) - PTR_DIFF(p, smb_buf(cli->inbuf));
391 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), len, 0);
398 /****************************************************************************
399 Do a spnego/kerberos encrypted session setup.
400 ****************************************************************************/
402 static BOOL cli_session_setup_kerberos(struct cli_state *cli, char *principal, char *workgroup)
404 DATA_BLOB blob2, negTokenTarg;
406 DEBUG(2,("Doing kerberos session setup\n"));
408 /* generate the encapsulated kerberos5 ticket */
409 negTokenTarg = spnego_gen_negTokenTarg(cli, principal);
411 if (!negTokenTarg.data) return False;
414 file_save("negTokenTarg.dat", negTokenTarg.data, negTokenTarg.length);
417 blob2 = cli_session_setup_blob(cli, negTokenTarg);
419 /* we don't need this blob for kerberos */
420 data_blob_free(&blob2);
422 data_blob_free(&negTokenTarg);
424 return !cli_is_error(cli);
428 /****************************************************************************
429 Do a spnego/NTLMSSP encrypted session setup.
430 ****************************************************************************/
432 static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, char *user,
433 char *pass, char *workgroup)
435 const char *mechs[] = {OID_NTLMSSP, NULL};
437 DATA_BLOB blob, chal1, chal2, auth;
439 uint8 nthash[24], lmhash[24], sess_key[16];
442 neg_flags = NTLMSSP_NEGOTIATE_UNICODE |
443 NTLMSSP_NEGOTIATE_LM_KEY |
444 NTLMSSP_NEGOTIATE_NTLM;
446 memset(sess_key, 0, 16);
448 /* generate the ntlmssp negotiate packet */
449 msrpc_gen(&blob, "CddB",
455 /* and wrap it in a SPNEGO wrapper */
456 msg1 = gen_negTokenTarg(mechs, blob);
457 data_blob_free(&blob);
459 /* now send that blob on its way */
460 blob = cli_session_setup_blob(cli, msg1);
462 data_blob_free(&msg1);
464 if (!NT_STATUS_EQUAL(cli_nt_error(cli), NT_STATUS_MORE_PROCESSING_REQUIRED)) {
469 file_save("chal.dat", blob.data, blob.length);
472 /* the server gives us back two challenges */
473 if (!spnego_parse_challenge(blob, &chal1, &chal2)) {
474 DEBUG(3,("Failed to parse challenges\n"));
478 data_blob_free(&blob);
480 /* encrypt the password with the challenge */
481 memcpy(challenge, chal1.data + 24, 8);
482 SMBencrypt(pass, challenge,lmhash);
483 SMBNTencrypt(pass, challenge,nthash);
486 file_save("nthash.dat", nthash, 24);
487 file_save("lmhash.dat", lmhash, 24);
488 file_save("chal1.dat", chal1.data, chal1.length);
491 data_blob_free(&chal1);
492 data_blob_free(&chal2);
494 /* this generates the actual auth packet */
495 msrpc_gen(&blob, "CdBBUUUBd",
506 /* wrap it in SPNEGO */
507 auth = spnego_gen_auth(blob);
509 data_blob_free(&blob);
511 /* now send the auth packet and we should be done */
512 blob = cli_session_setup_blob(cli, auth);
514 data_blob_free(&auth);
515 data_blob_free(&blob);
517 return !cli_is_error(cli);
520 /****************************************************************************
521 Do a spnego encrypted session setup.
522 ****************************************************************************/
524 static BOOL cli_session_setup_spnego(struct cli_state *cli, char *user,
525 char *pass, char *workgroup)
528 char *OIDs[ASN1_MAX_OIDS];
531 BOOL got_kerberos_mechanism = False;
533 /* spnego security cannot use SMB signing (for now). */
534 cli->sign_info.use_smb_signing = False;
536 DEBUG(2,("Doing spnego session setup (blob length=%d)\n", cli->secblob.length));
538 /* the server might not even do spnego */
539 if (cli->secblob.length == 16) {
540 DEBUG(3,("server didn't supply a full spnego negprot\n"));
545 file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
548 /* the server sent us the first part of the SPNEGO exchange in the negprot
550 if (!spnego_parse_negTokenInit(cli->secblob, guid, OIDs, &principal)) {
554 /* make sure the server understands kerberos */
555 for (i=0;OIDs[i];i++) {
556 DEBUG(3,("got OID=%s\n", OIDs[i]));
557 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
558 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
559 got_kerberos_mechanism = True;
563 DEBUG(3,("got principal=%s\n", principal));
565 fstrcpy(cli->user_name, user);
568 if (got_kerberos_mechanism && cli->use_kerberos) {
569 return cli_session_setup_kerberos(cli, principal, workgroup);
577 return cli_session_setup_ntlmssp(cli, user, pass, workgroup);
580 /****************************************************************************
581 Send a session setup. The username and workgroup is in UNIX character
582 format and must be converted to DOS codepage format before sending. If the
583 password is in plaintext, the same should be done.
584 ****************************************************************************/
586 BOOL cli_session_setup(struct cli_state *cli,
588 char *pass, int passlen,
589 char *ntpass, int ntpasslen,
595 /* allow for workgroups as part of the username */
596 fstrcpy(user2, user);
597 if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/')) ||
598 (p=strchr_m(user2,*lp_winbind_separator()))) {
604 if (cli->protocol < PROTOCOL_LANMAN1)
607 /* now work out what sort of session setup we are going to
608 do. I have split this into separate functions to make the
609 flow a bit easier to understand (tridge) */
611 /* if its an older server then we have to use the older request format */
612 if (cli->protocol < PROTOCOL_NT1) {
613 return cli_session_setup_lanman2(cli, user, pass, passlen, workgroup);
616 /* if no user is supplied then we have to do an anonymous connection.
617 passwords are ignored */
618 if (!user || !*user) {
619 return cli_session_setup_guest(cli);
622 /* if the server is share level then send a plaintext null
623 password at this point. The password is sent in the tree
625 if ((cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) == 0) {
626 return cli_session_setup_plaintext(cli, user, "", workgroup);
629 /* if the server doesn't support encryption then we have to use
630 plaintext. The second password is ignored */
631 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) {
632 return cli_session_setup_plaintext(cli, user, pass, workgroup);
635 /* if the server supports extended security then use SPNEGO */
636 if (cli->capabilities & CAP_EXTENDED_SECURITY) {
637 return cli_session_setup_spnego(cli, user, pass, workgroup);
640 /* otherwise do a NT1 style session setup */
641 return cli_session_setup_nt1(cli, user,
642 pass, passlen, ntpass, ntpasslen,
646 /****************************************************************************
648 *****************************************************************************/
650 BOOL cli_ulogoff(struct cli_state *cli)
652 memset(cli->outbuf,'\0',smb_size);
653 set_message(cli->outbuf,2,0,True);
654 SCVAL(cli->outbuf,smb_com,SMBulogoffX);
655 cli_setup_packet(cli);
656 SSVAL(cli->outbuf,smb_vwv0,0xFF);
657 SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
660 if (!cli_receive_smb(cli))
663 return !cli_is_error(cli);
666 /****************************************************************************
668 ****************************************************************************/
670 BOOL cli_send_tconX(struct cli_state *cli,
671 const char *share, const char *dev, const char *pass, int passlen)
673 fstring fullshare, pword;
675 memset(cli->outbuf,'\0',smb_size);
676 memset(cli->inbuf,'\0',smb_size);
678 fstrcpy(cli->share, share);
680 /* in user level security don't send a password now */
681 if (cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) {
686 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && *pass && passlen != 24) {
688 * Non-encrypted passwords - convert to DOS codepage before encryption.
691 SMBencrypt(pass,cli->secblob.data,(uchar *)pword);
693 if((cli->sec_mode & (NEGOTIATE_SECURITY_USER_LEVEL|NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)) == 0) {
695 * Non-encrypted passwords - convert to DOS codepage before using.
697 passlen = clistr_push(cli, pword, pass, -1, STR_TERMINATE);
699 memcpy(pword, pass, passlen);
703 if (cli->port == 445) {
704 slprintf(fullshare, sizeof(fullshare)-1,
707 slprintf(fullshare, sizeof(fullshare)-1,
708 "\\\\%s\\%s", cli->desthost, share);
711 set_message(cli->outbuf,4, 0, True);
712 SCVAL(cli->outbuf,smb_com,SMBtconX);
713 cli_setup_packet(cli);
715 SSVAL(cli->outbuf,smb_vwv0,0xFF);
716 SSVAL(cli->outbuf,smb_vwv3,passlen);
718 p = smb_buf(cli->outbuf);
719 memcpy(p,pword,passlen);
721 p += clistr_push(cli, p, fullshare, -1, STR_TERMINATE |STR_UPPER);
722 fstrcpy(p, dev); p += strlen(dev)+1;
724 cli_setup_bcc(cli, p);
727 if (!cli_receive_smb(cli))
730 if (cli_is_error(cli)) {
734 clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE|STR_ASCII);
736 if (strcasecmp(share,"IPC$")==0) {
737 fstrcpy(cli->dev, "IPC");
740 if (cli->protocol >= PROTOCOL_NT1 &&
741 smb_buflen(cli->inbuf) == 3) {
742 /* almost certainly win95 - enable bug fixes */
746 cli->cnum = SVAL(cli->inbuf,smb_tid);
750 /****************************************************************************
751 Send a tree disconnect.
752 ****************************************************************************/
754 BOOL cli_tdis(struct cli_state *cli)
756 memset(cli->outbuf,'\0',smb_size);
757 set_message(cli->outbuf,0,0,True);
758 SCVAL(cli->outbuf,smb_com,SMBtdis);
759 SSVAL(cli->outbuf,smb_tid,cli->cnum);
760 cli_setup_packet(cli);
763 if (!cli_receive_smb(cli))
766 return !cli_is_error(cli);
769 /****************************************************************************
770 Send a negprot command.
771 ****************************************************************************/
773 void cli_negprot_send(struct cli_state *cli)
778 if (cli->protocol < PROTOCOL_NT1) {
779 cli->use_spnego = False;
782 memset(cli->outbuf,'\0',smb_size);
784 /* setup the protocol strings */
785 set_message(cli->outbuf,0,0,True);
787 p = smb_buf(cli->outbuf);
789 prots[numprots].name && prots[numprots].prot<=cli->protocol;
792 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
795 SCVAL(cli->outbuf,smb_com,SMBnegprot);
796 cli_setup_bcc(cli, p);
797 cli_setup_packet(cli);
799 SCVAL(smb_buf(cli->outbuf),0,2);
804 /****************************************************************************
805 Send a negprot command.
806 ****************************************************************************/
808 BOOL cli_negprot(struct cli_state *cli)
814 if (cli->sign_info.use_smb_signing) {
815 DEBUG(0, ("Cannot send negprot again, particularly after setting up SMB Signing\n"));
819 if (cli->protocol < PROTOCOL_NT1) {
820 cli->use_spnego = False;
823 memset(cli->outbuf,'\0',smb_size);
825 /* setup the protocol strings */
826 for (plength=0,numprots=0;
827 prots[numprots].name && prots[numprots].prot<=cli->protocol;
829 plength += strlen(prots[numprots].name)+2;
831 set_message(cli->outbuf,0,plength,True);
833 p = smb_buf(cli->outbuf);
835 prots[numprots].name && prots[numprots].prot<=cli->protocol;
838 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
841 SCVAL(cli->outbuf,smb_com,SMBnegprot);
842 cli_setup_packet(cli);
844 SCVAL(smb_buf(cli->outbuf),0,2);
847 if (!cli_receive_smb(cli))
850 show_msg(cli->inbuf);
852 if (cli_is_error(cli) ||
853 ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
857 cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
859 if (cli->protocol >= PROTOCOL_NT1) {
861 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
862 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
863 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
864 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
865 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1);
866 cli->serverzone *= 60;
867 /* this time arrives in real GMT */
868 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
869 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
870 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
871 if (cli->capabilities & CAP_RAW_MODE) {
872 cli->readbraw_supported = True;
873 cli->writebraw_supported = True;
875 /* work out if they sent us a workgroup */
876 if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
877 smb_buflen(cli->inbuf) > 8) {
878 clistr_pull(cli, cli->server_domain,
879 smb_buf(cli->inbuf)+8, sizeof(cli->server_domain),
880 smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
883 /* A way to attempt to force SMB signing */
884 if (getenv("CLI_FORCE_SMB_SIGNING"))
885 cli->sign_info.negotiated_smb_signing = True;
887 if (cli->sign_info.negotiated_smb_signing && !(cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED))
888 cli->sign_info.negotiated_smb_signing = False;
890 } else if (cli->protocol >= PROTOCOL_LANMAN1) {
891 cli->use_spnego = False;
892 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
893 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
894 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
895 cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
896 cli->serverzone *= 60;
897 /* this time is converted to GMT by make_unix_date */
898 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
899 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
900 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
901 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
903 /* the old core protocol */
904 cli->use_spnego = False;
906 cli->serverzone = TimeDiff(time(NULL));
909 cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
911 /* a way to force ascii SMB */
912 if (getenv("CLI_FORCE_ASCII")) {
913 cli->capabilities &= ~CAP_UNICODE;
919 /****************************************************************************
920 Send a session request. See rfc1002.txt 4.3 and 4.3.2.
921 ****************************************************************************/
923 BOOL cli_session_request(struct cli_state *cli,
924 struct nmb_name *calling, struct nmb_name *called)
928 extern pstring user_socket_options;
930 /* 445 doesn't have session request */
931 if (cli->port == 445) return True;
933 if (cli->sign_info.use_smb_signing) {
934 DEBUG(0, ("Cannot send session resquest again, particularly after setting up SMB Signing\n"));
938 /* send a session request (RFC 1002) */
939 memcpy(&(cli->calling), calling, sizeof(*calling));
940 memcpy(&(cli->called ), called , sizeof(*called ));
942 /* put in the destination name */
944 name_mangle(cli->called .name, p, cli->called .name_type);
949 name_mangle(cli->calling.name, p, cli->calling.name_type);
952 /* setup the packet length
953 * Remove four bytes from the length count, since the length
954 * field in the NBT Session Service header counts the number
955 * of bytes which follow. The cli_send_smb() function knows
956 * about this and accounts for those four bytes.
960 _smb_setlen(cli->outbuf,len);
961 SCVAL(cli->outbuf,0,0x81);
964 DEBUG(5,("Sent session request\n"));
966 if (!cli_receive_smb(cli))
969 if (CVAL(cli->inbuf,0) == 0x84) {
970 /* C. Hoch 9/14/95 Start */
971 /* For information, here is the response structure.
972 * We do the byte-twiddling to for portability.
973 struct RetargetResponse{
981 int port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
982 /* SESSION RETARGET */
983 putip((char *)&cli->dest_ip,cli->inbuf+4);
985 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
989 DEBUG(3,("Retargeted\n"));
991 set_socket_options(cli->fd,user_socket_options);
998 DEBUG(0,("Retarget recursion - failing\n"));
1002 ret = cli_session_request(cli, calling, called);
1006 } /* C. Hoch 9/14/95 End */
1008 if (CVAL(cli->inbuf,0) != 0x82) {
1009 /* This is the wrong place to put the error... JRA. */
1010 cli->rap_error = CVAL(cli->inbuf,4);
1016 /****************************************************************************
1017 Open the client sockets.
1018 ****************************************************************************/
1020 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
1022 extern pstring user_socket_options;
1023 int name_type = 0x20;
1026 /* reasonable default hostname */
1027 if (!host) host = "*SMBSERVER";
1029 fstrcpy(cli->desthost, host);
1031 /* allow hostnames of the form NAME#xx and do a netbios lookup */
1032 if ((p = strchr(cli->desthost, '#'))) {
1033 name_type = strtol(p+1, NULL, 16);
1037 if (!ip || is_zero_ip(*ip)) {
1038 if (!resolve_name(cli->desthost, &cli->dest_ip, name_type)) {
1041 if (ip) *ip = cli->dest_ip;
1046 if (getenv("LIBSMB_PROG")) {
1047 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
1049 /* try 445 first, then 139 */
1050 int port = cli->port?cli->port:445;
1051 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
1052 port, cli->timeout);
1053 if (cli->fd == -1 && cli->port == 0) {
1055 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
1056 port, cli->timeout);
1058 if (cli->fd != -1) cli->port = port;
1060 if (cli->fd == -1) {
1061 DEBUG(1,("Error connecting to %s (%s)\n",
1062 inet_ntoa(*ip),strerror(errno)));
1066 set_socket_options(cli->fd,user_socket_options);
1071 /****************************************************************************
1072 Initialise client credentials for authenticated pipe access.
1073 ****************************************************************************/
1075 static void init_creds(struct ntuser_creds *creds, char* username,
1076 char* domain, char* password)
1078 ZERO_STRUCTP(creds);
1080 pwd_set_cleartext(&creds->pwd, password);
1082 fstrcpy(creds->user_name, username);
1083 fstrcpy(creds->domain, domain);
1086 creds->pwd.null_pwd = True;
1091 establishes a connection right up to doing tconX, password specified.
1092 @param output_cli A fully initialised cli structure, non-null only on success
1093 @param dest_host The netbios name of the remote host
1094 @param dest_ip (optional) The the destination IP, NULL for name based lookup
1095 @param port (optional) The destination port (0 for default)
1096 @param service (optional) The share to make the connection to. Should be 'unqualified' in any way.
1097 @param service_type The 'type' of serivice.
1098 @param user Username, unix string
1099 @param domain User's domain
1100 @param password User's password, unencrypted unix string.
1103 NTSTATUS cli_full_connection(struct cli_state **output_cli,
1104 const char *my_name,
1105 const char *dest_host,
1106 struct in_addr *dest_ip, int port,
1107 char *service, char *service_type,
1108 char *user, char *domain,
1109 char *password, int flags)
1111 struct ntuser_creds creds;
1113 struct nmb_name calling;
1114 struct nmb_name called;
1115 struct cli_state *cli;
1117 extern pstring global_myname;
1120 my_name = global_myname;
1122 if (!(cli = cli_initialise(NULL)))
1123 return NT_STATUS_NO_MEMORY;
1125 make_nmb_name(&calling, my_name, 0x0);
1126 make_nmb_name(&called , dest_host, 0x20);
1128 if (cli_set_port(cli, port) != port) {
1130 return NT_STATUS_UNSUCCESSFUL;
1141 DEBUG(3,("Connecting to host=%s share=%s\n", dest_host, service));
1143 if (!cli_connect(cli, dest_host, &ip)) {
1144 DEBUG(1,("cli_full_connection: failed to connect to %s (%s)\n",
1145 nmb_namestr(&called), inet_ntoa(ip)));
1147 return NT_STATUS_UNSUCCESSFUL;
1150 if (!cli_session_request(cli, &calling, &called)) {
1152 DEBUG(1,("session request to %s failed (%s)\n",
1153 called.name, cli_errstr(cli)));
1155 if ((p=strchr(called.name, '.'))) {
1159 if (strcmp(called.name, "*SMBSERVER")) {
1160 make_nmb_name(&called , "*SMBSERVER", 0x20);
1163 return NT_STATUS_UNSUCCESSFUL;
1166 if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO) {
1167 cli->use_spnego = False;
1168 } else if (flags & CLI_FULL_CONNECTION_USE_KERBEROS) {
1169 cli->use_kerberos = True;
1172 if (!cli_negprot(cli)) {
1173 DEBUG(1,("failed negprot\n"));
1174 nt_status = NT_STATUS_UNSUCCESSFUL;
1179 if (!cli_session_setup(cli, user, password, strlen(password)+1,
1180 password, strlen(password)+1,
1182 if (!(flags & CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK)
1183 || cli_session_setup(cli, "", "", 0,
1186 nt_status = cli_nt_error(cli);
1187 DEBUG(1,("failed session setup with %s\n", nt_errstr(nt_status)));
1189 if (NT_STATUS_IS_OK(nt_status))
1190 nt_status = NT_STATUS_UNSUCCESSFUL;
1196 if (!cli_send_tconX(cli, service, service_type,
1197 (char*)password, strlen(password)+1)) {
1198 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(nt_status)));
1199 nt_status = cli_nt_error(cli);
1201 if (NT_STATUS_IS_OK(nt_status)) {
1202 nt_status = NT_STATUS_UNSUCCESSFUL;
1208 init_creds(&creds, user, domain, password);
1209 cli_init_creds(cli, &creds);
1212 return NT_STATUS_OK;
1215 /****************************************************************************
1216 Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
1217 ****************************************************************************/
1219 BOOL attempt_netbios_session_request(struct cli_state *cli, char *srchost, char *desthost,
1220 struct in_addr *pdest_ip)
1222 struct nmb_name calling, called;
1224 make_nmb_name(&calling, srchost, 0x0);
1227 * If the called name is an IP address
1228 * then use *SMBSERVER immediately.
1231 if(is_ipaddress(desthost))
1232 make_nmb_name(&called, "*SMBSERVER", 0x20);
1234 make_nmb_name(&called, desthost, 0x20);
1236 if (!cli_session_request(cli, &calling, &called)) {
1237 struct nmb_name smbservername;
1239 make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
1242 * If the name wasn't *SMBSERVER then
1243 * try with *SMBSERVER if the first name fails.
1246 if (nmb_name_equal(&called, &smbservername)) {
1249 * The name used was *SMBSERVER, don't bother with another name.
1252 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
1253 with error %s.\n", desthost, cli_errstr(cli) ));
1260 if (!cli_initialise(cli) ||
1261 !cli_connect(cli, desthost, pdest_ip) ||
1262 !cli_session_request(cli, &calling, &smbservername)) {
1263 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
1264 name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) ));