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 /* Lanman2 cannot use SMB signing. */
58 cli->sign_info.use_smb_signing = False;
60 /* if in share level security then don't send a password now */
61 if (!(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL)) {
65 if (passlen > 0 && (cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen != 24) {
66 /* Encrypted mode needed, and non encrypted password supplied. */
68 SMBencrypt(pass,cli->secblob.data,(uchar *)pword);
69 } else if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen == 24) {
70 /* Encrypted mode needed, and encrypted password supplied. */
71 memcpy(pword, pass, passlen);
72 } else if (passlen > 0) {
73 /* Plaintext mode needed, assume plaintext supplied. */
74 passlen = clistr_push(cli, pword, pass, -1, STR_TERMINATE);
77 /* send a session setup command */
78 memset(cli->outbuf,'\0',smb_size);
79 set_message(cli->outbuf,10, 0, True);
80 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
81 cli_setup_packet(cli);
83 SCVAL(cli->outbuf,smb_vwv0,0xFF);
84 SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
85 SSVAL(cli->outbuf,smb_vwv3,2);
86 SSVAL(cli->outbuf,smb_vwv4,1);
87 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
88 SSVAL(cli->outbuf,smb_vwv7,passlen);
90 p = smb_buf(cli->outbuf);
91 memcpy(p,pword,passlen);
93 p += clistr_push(cli, p, user, -1, STR_TERMINATE|STR_UPPER);
94 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
95 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
96 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
97 cli_setup_bcc(cli, p);
100 if (!cli_receive_smb(cli))
103 show_msg(cli->inbuf);
105 if (cli_is_error(cli)) {
109 /* use the returned vuid from now on */
110 cli->vuid = SVAL(cli->inbuf,smb_uid);
111 fstrcpy(cli->user_name, user);
116 /****************************************************************************
117 Work out suitable capabilities to offer the server.
118 ****************************************************************************/
120 static uint32 cli_session_setup_capabilities(struct cli_state *cli)
122 uint32 capabilities = CAP_NT_SMBS;
124 if (!cli->force_dos_errors) {
125 capabilities |= CAP_STATUS32;
128 if (cli->use_level_II_oplocks) {
129 capabilities |= CAP_LEVEL_II_OPLOCKS;
132 if (cli->capabilities & CAP_UNICODE) {
133 capabilities |= CAP_UNICODE;
139 /****************************************************************************
140 Do a NT1 guest session setup.
141 ****************************************************************************/
143 static BOOL cli_session_setup_guest(struct cli_state *cli)
146 uint32 capabilities = cli_session_setup_capabilities(cli);
148 set_message(cli->outbuf,13,0,True);
149 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
150 cli_setup_packet(cli);
152 SCVAL(cli->outbuf,smb_vwv0,0xFF);
153 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
154 SSVAL(cli->outbuf,smb_vwv3,2);
155 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
156 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
157 SSVAL(cli->outbuf,smb_vwv7,0);
158 SSVAL(cli->outbuf,smb_vwv8,0);
159 SIVAL(cli->outbuf,smb_vwv11,capabilities);
160 p = smb_buf(cli->outbuf);
161 p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* username */
162 p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* workgroup */
163 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
164 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
165 cli_setup_bcc(cli, p);
168 if (!cli_receive_smb(cli))
171 show_msg(cli->inbuf);
173 if (cli_is_error(cli)) {
177 cli->vuid = SVAL(cli->inbuf,smb_uid);
179 p = smb_buf(cli->inbuf);
180 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
181 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
182 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
184 fstrcpy(cli->user_name, "");
189 /****************************************************************************
190 Do a NT1 plaintext session setup.
191 ****************************************************************************/
193 static BOOL cli_session_setup_plaintext(struct cli_state *cli, char *user,
194 char *pass, char *workgroup)
196 uint32 capabilities = cli_session_setup_capabilities(cli);
201 passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE|STR_ASCII);
203 set_message(cli->outbuf,13,0,True);
204 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
205 cli_setup_packet(cli);
207 SCVAL(cli->outbuf,smb_vwv0,0xFF);
208 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
209 SSVAL(cli->outbuf,smb_vwv3,2);
210 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
211 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
212 SSVAL(cli->outbuf,smb_vwv7,passlen);
213 SSVAL(cli->outbuf,smb_vwv8,0);
214 SIVAL(cli->outbuf,smb_vwv11,capabilities);
215 p = smb_buf(cli->outbuf);
216 memcpy(p, pword, passlen);
218 p += clistr_push(cli, p, user, -1, STR_TERMINATE); /* username */
219 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE); /* workgroup */
220 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
221 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
222 cli_setup_bcc(cli, p);
225 if (!cli_receive_smb(cli))
228 show_msg(cli->inbuf);
230 if (cli_is_error(cli)) {
234 cli->vuid = SVAL(cli->inbuf,smb_uid);
235 p = smb_buf(cli->inbuf);
236 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
237 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
238 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
239 fstrcpy(cli->user_name, user);
246 do a NT1 NTLM/LM encrypted session setup
247 @param cli client state to create do session setup on
249 @param pass *either* cleartext password (passlen !=24) or LM response.
250 @param ntpass NT response, implies ntpasslen >=24, implies pass is not clear
251 @param workgroup The user's domain.
254 static BOOL cli_session_setup_nt1(struct cli_state *cli, char *user,
255 char *pass, int passlen,
256 char *ntpass, int ntpasslen,
259 uint32 capabilities = cli_session_setup_capabilities(cli);
260 fstring pword, ntpword;
262 BOOL tried_signing = False;
264 if (passlen > sizeof(pword)-1 || ntpasslen > sizeof(ntpword)-1) {
269 /* non encrypted password supplied. Ignore ntpass. */
272 SMBencrypt((uchar *)pass,cli->secblob.data,(uchar *)pword);
273 SMBNTencrypt((uchar *)pass,cli->secblob.data,(uchar *)ntpword);
274 if (!cli->sign_info.use_smb_signing && cli->sign_info.negotiated_smb_signing) {
275 cli_calculate_mac_key(cli, (uchar *)pass, (uchar *)ntpword);
276 tried_signing = True;
279 memcpy(pword, pass, passlen);
280 memcpy(ntpword, ntpass, ntpasslen);
283 /* send a session setup command */
284 memset(cli->outbuf,'\0',smb_size);
286 set_message(cli->outbuf,13,0,True);
287 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
288 cli_setup_packet(cli);
290 SCVAL(cli->outbuf,smb_vwv0,0xFF);
291 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
292 SSVAL(cli->outbuf,smb_vwv3,2);
293 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
294 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
295 SSVAL(cli->outbuf,smb_vwv7,passlen);
296 SSVAL(cli->outbuf,smb_vwv8,ntpasslen);
297 SIVAL(cli->outbuf,smb_vwv11,capabilities);
298 p = smb_buf(cli->outbuf);
299 memcpy(p,pword,passlen); p += passlen;
300 memcpy(p,ntpword,ntpasslen); p += ntpasslen;
301 p += clistr_push(cli, p, user, -1, STR_TERMINATE|STR_UPPER);
302 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
303 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
304 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
305 cli_setup_bcc(cli, p);
308 if (!cli_receive_smb(cli))
311 show_msg(cli->inbuf);
313 if (tried_signing && (cli_is_error(cli) || SVAL(cli->inbuf,smb_vwv2) /* guest */)) {
314 /* We only use it if we have a successful non-guest connect */
315 cli->sign_info.use_smb_signing = False;
318 if (cli_is_error(cli)) {
322 /* use the returned vuid from now on */
323 cli->vuid = SVAL(cli->inbuf,smb_uid);
325 p = smb_buf(cli->inbuf);
326 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
327 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
328 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
330 fstrcpy(cli->user_name, user);
335 /****************************************************************************
336 Send a extended security session setup blob, returning a reply blob.
337 ****************************************************************************/
339 static DATA_BLOB cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob)
341 uint32 capabilities = cli_session_setup_capabilities(cli);
346 blob2 = data_blob(NULL, 0);
348 capabilities |= CAP_EXTENDED_SECURITY;
350 /* send a session setup command */
351 memset(cli->outbuf,'\0',smb_size);
353 set_message(cli->outbuf,12,0,True);
354 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
355 cli_setup_packet(cli);
357 SCVAL(cli->outbuf,smb_vwv0,0xFF);
358 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
359 SSVAL(cli->outbuf,smb_vwv3,2);
360 SSVAL(cli->outbuf,smb_vwv4,1);
361 SIVAL(cli->outbuf,smb_vwv5,0);
362 SSVAL(cli->outbuf,smb_vwv7,blob.length);
363 SIVAL(cli->outbuf,smb_vwv10,capabilities);
364 p = smb_buf(cli->outbuf);
365 memcpy(p, blob.data, blob.length);
367 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
368 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
369 cli_setup_bcc(cli, p);
372 if (!cli_receive_smb(cli))
375 show_msg(cli->inbuf);
377 if (cli_is_error(cli) && !NT_STATUS_EQUAL(cli_nt_error(cli),
378 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
382 /* use the returned vuid from now on */
383 cli->vuid = SVAL(cli->inbuf,smb_uid);
385 p = smb_buf(cli->inbuf);
387 blob2 = data_blob(p, SVAL(cli->inbuf, smb_vwv3));
390 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
392 /* w2k with kerberos doesn't properly null terminate this field */
393 len = smb_buflen(cli->inbuf) - PTR_DIFF(p, smb_buf(cli->inbuf));
394 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), len, 0);
401 /****************************************************************************
402 Do a spnego/kerberos encrypted session setup.
403 ****************************************************************************/
405 static BOOL cli_session_setup_kerberos(struct cli_state *cli, char *principal, char *workgroup)
407 DATA_BLOB blob2, negTokenTarg;
409 DEBUG(2,("Doing kerberos session setup\n"));
411 /* generate the encapsulated kerberos5 ticket */
412 negTokenTarg = spnego_gen_negTokenTarg(cli, principal);
414 if (!negTokenTarg.data) return False;
417 file_save("negTokenTarg.dat", negTokenTarg.data, negTokenTarg.length);
420 blob2 = cli_session_setup_blob(cli, negTokenTarg);
422 /* we don't need this blob for kerberos */
423 data_blob_free(&blob2);
425 data_blob_free(&negTokenTarg);
427 return !cli_is_error(cli);
431 /****************************************************************************
432 Do a spnego/NTLMSSP encrypted session setup.
433 ****************************************************************************/
435 static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, char *user,
436 char *pass, char *workgroup)
438 const char *mechs[] = {OID_NTLMSSP, NULL};
440 DATA_BLOB blob, chal1, chal2, auth;
442 uint8 nthash[24], lmhash[24], sess_key[16];
445 neg_flags = NTLMSSP_NEGOTIATE_UNICODE |
446 NTLMSSP_NEGOTIATE_LM_KEY |
447 NTLMSSP_NEGOTIATE_NTLM;
449 memset(sess_key, 0, 16);
451 /* generate the ntlmssp negotiate packet */
452 msrpc_gen(&blob, "CddB",
458 /* and wrap it in a SPNEGO wrapper */
459 msg1 = gen_negTokenTarg(mechs, blob);
460 data_blob_free(&blob);
462 /* now send that blob on its way */
463 blob = cli_session_setup_blob(cli, msg1);
465 data_blob_free(&msg1);
467 if (!NT_STATUS_EQUAL(cli_nt_error(cli), NT_STATUS_MORE_PROCESSING_REQUIRED)) {
472 file_save("chal.dat", blob.data, blob.length);
475 /* the server gives us back two challenges */
476 if (!spnego_parse_challenge(blob, &chal1, &chal2)) {
477 DEBUG(3,("Failed to parse challenges\n"));
481 data_blob_free(&blob);
483 /* encrypt the password with the challenge */
484 memcpy(challenge, chal1.data + 24, 8);
485 SMBencrypt((unsigned char *)pass, challenge,lmhash);
486 SMBNTencrypt((unsigned char *)pass, challenge,nthash);
489 file_save("nthash.dat", nthash, 24);
490 file_save("lmhash.dat", lmhash, 24);
491 file_save("chal1.dat", chal1.data, chal1.length);
494 data_blob_free(&chal1);
495 data_blob_free(&chal2);
497 /* this generates the actual auth packet */
498 msrpc_gen(&blob, "CdBBUUUBd",
509 /* wrap it in SPNEGO */
510 auth = spnego_gen_auth(blob);
512 data_blob_free(&blob);
514 /* now send the auth packet and we should be done */
515 blob = cli_session_setup_blob(cli, auth);
517 data_blob_free(&auth);
518 data_blob_free(&blob);
520 return !cli_is_error(cli);
523 /****************************************************************************
524 Do a spnego encrypted session setup.
525 ****************************************************************************/
527 static BOOL cli_session_setup_spnego(struct cli_state *cli, char *user,
528 char *pass, char *workgroup)
531 char *OIDs[ASN1_MAX_OIDS];
534 BOOL got_kerberos_mechanism = False;
536 /* spnego security cannot use SMB signing (for now). */
537 cli->sign_info.use_smb_signing = False;
539 DEBUG(2,("Doing spnego session setup (blob length=%d)\n", cli->secblob.length));
541 /* the server might not even do spnego */
542 if (cli->secblob.length == 16) {
543 DEBUG(3,("server didn't supply a full spnego negprot\n"));
548 file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
551 /* the server sent us the first part of the SPNEGO exchange in the negprot
553 if (!spnego_parse_negTokenInit(cli->secblob, guid, OIDs, &principal)) {
557 /* make sure the server understands kerberos */
558 for (i=0;OIDs[i];i++) {
559 DEBUG(3,("got OID=%s\n", OIDs[i]));
560 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
561 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
562 got_kerberos_mechanism = True;
566 DEBUG(3,("got principal=%s\n", principal));
568 fstrcpy(cli->user_name, user);
571 if (got_kerberos_mechanism && cli->use_kerberos) {
572 return cli_session_setup_kerberos(cli, principal, workgroup);
580 return cli_session_setup_ntlmssp(cli, user, pass, workgroup);
583 /****************************************************************************
584 Send a session setup. The username and workgroup is in UNIX character
585 format and must be converted to DOS codepage format before sending. If the
586 password is in plaintext, the same should be done.
587 ****************************************************************************/
589 BOOL cli_session_setup(struct cli_state *cli,
591 char *pass, int passlen,
592 char *ntpass, int ntpasslen,
598 /* allow for workgroups as part of the username */
599 fstrcpy(user2, user);
600 if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/')) ||
601 (p=strchr_m(user2,*lp_winbind_separator()))) {
607 if (cli->protocol < PROTOCOL_LANMAN1)
610 /* now work out what sort of session setup we are going to
611 do. I have split this into separate functions to make the
612 flow a bit easier to understand (tridge) */
614 /* if its an older server then we have to use the older request format */
615 if (cli->protocol < PROTOCOL_NT1) {
616 return cli_session_setup_lanman2(cli, user, pass, passlen, workgroup);
619 /* if no user is supplied then we have to do an anonymous connection.
620 passwords are ignored */
621 if (!user || !*user) {
622 return cli_session_setup_guest(cli);
625 /* if the server is share level then send a plaintext null
626 password at this point. The password is sent in the tree
628 if ((cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) == 0) {
629 return cli_session_setup_plaintext(cli, user, "", workgroup);
632 /* if the server doesn't support encryption then we have to use
633 plaintext. The second password is ignored */
634 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) {
635 return cli_session_setup_plaintext(cli, user, pass, workgroup);
638 /* if the server supports extended security then use SPNEGO */
639 if (cli->capabilities & CAP_EXTENDED_SECURITY) {
640 return cli_session_setup_spnego(cli, user, pass, workgroup);
643 /* otherwise do a NT1 style session setup */
644 return cli_session_setup_nt1(cli, user,
645 pass, passlen, ntpass, ntpasslen,
649 /****************************************************************************
651 *****************************************************************************/
653 BOOL cli_ulogoff(struct cli_state *cli)
655 memset(cli->outbuf,'\0',smb_size);
656 set_message(cli->outbuf,2,0,True);
657 SCVAL(cli->outbuf,smb_com,SMBulogoffX);
658 cli_setup_packet(cli);
659 SSVAL(cli->outbuf,smb_vwv0,0xFF);
660 SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
663 if (!cli_receive_smb(cli))
666 return !cli_is_error(cli);
669 /****************************************************************************
671 ****************************************************************************/
673 BOOL cli_send_tconX(struct cli_state *cli,
674 const char *share, const char *dev, const char *pass, int passlen)
676 fstring fullshare, pword;
678 memset(cli->outbuf,'\0',smb_size);
679 memset(cli->inbuf,'\0',smb_size);
681 fstrcpy(cli->share, share);
683 /* in user level security don't send a password now */
684 if (cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) {
689 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && *pass && passlen != 24) {
691 * Non-encrypted passwords - convert to DOS codepage before encryption.
694 SMBencrypt(pass,cli->secblob.data,(uchar *)pword);
696 if((cli->sec_mode & (NEGOTIATE_SECURITY_USER_LEVEL|NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)) == 0) {
698 * Non-encrypted passwords - convert to DOS codepage before using.
700 passlen = clistr_push(cli, pword, pass, -1, STR_TERMINATE);
702 memcpy(pword, pass, passlen);
706 if (cli->port == 445) {
707 slprintf(fullshare, sizeof(fullshare)-1,
710 slprintf(fullshare, sizeof(fullshare)-1,
711 "\\\\%s\\%s", cli->desthost, share);
714 set_message(cli->outbuf,4, 0, True);
715 SCVAL(cli->outbuf,smb_com,SMBtconX);
716 cli_setup_packet(cli);
718 SSVAL(cli->outbuf,smb_vwv0,0xFF);
719 SSVAL(cli->outbuf,smb_vwv3,passlen);
721 p = smb_buf(cli->outbuf);
722 memcpy(p,pword,passlen);
724 p += clistr_push(cli, p, fullshare, -1, STR_TERMINATE |STR_UPPER);
725 fstrcpy(p, dev); p += strlen(dev)+1;
727 cli_setup_bcc(cli, p);
730 if (!cli_receive_smb(cli))
733 if (cli_is_error(cli)) {
737 clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE|STR_ASCII);
739 if (strcasecmp(share,"IPC$")==0) {
740 fstrcpy(cli->dev, "IPC");
743 if (cli->protocol >= PROTOCOL_NT1 &&
744 smb_buflen(cli->inbuf) == 3) {
745 /* almost certainly win95 - enable bug fixes */
749 cli->cnum = SVAL(cli->inbuf,smb_tid);
753 /****************************************************************************
754 Send a tree disconnect.
755 ****************************************************************************/
757 BOOL cli_tdis(struct cli_state *cli)
759 memset(cli->outbuf,'\0',smb_size);
760 set_message(cli->outbuf,0,0,True);
761 SCVAL(cli->outbuf,smb_com,SMBtdis);
762 SSVAL(cli->outbuf,smb_tid,cli->cnum);
763 cli_setup_packet(cli);
766 if (!cli_receive_smb(cli))
769 return !cli_is_error(cli);
772 /****************************************************************************
773 Send a negprot command.
774 ****************************************************************************/
776 void cli_negprot_send(struct cli_state *cli)
781 if (cli->protocol < PROTOCOL_NT1) {
782 cli->use_spnego = False;
785 memset(cli->outbuf,'\0',smb_size);
787 /* setup the protocol strings */
788 set_message(cli->outbuf,0,0,True);
790 p = smb_buf(cli->outbuf);
792 prots[numprots].name && prots[numprots].prot<=cli->protocol;
795 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
798 SCVAL(cli->outbuf,smb_com,SMBnegprot);
799 cli_setup_bcc(cli, p);
800 cli_setup_packet(cli);
802 SCVAL(smb_buf(cli->outbuf),0,2);
807 /****************************************************************************
808 Send a negprot command.
809 ****************************************************************************/
811 BOOL cli_negprot(struct cli_state *cli)
817 if (cli->sign_info.use_smb_signing) {
818 DEBUG(0, ("Cannot send negprot again, particularly after setting up SMB Signing\n"));
822 if (cli->protocol < PROTOCOL_NT1) {
823 cli->use_spnego = False;
826 memset(cli->outbuf,'\0',smb_size);
828 /* setup the protocol strings */
829 for (plength=0,numprots=0;
830 prots[numprots].name && prots[numprots].prot<=cli->protocol;
832 plength += strlen(prots[numprots].name)+2;
834 set_message(cli->outbuf,0,plength,True);
836 p = smb_buf(cli->outbuf);
838 prots[numprots].name && prots[numprots].prot<=cli->protocol;
841 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
844 SCVAL(cli->outbuf,smb_com,SMBnegprot);
845 cli_setup_packet(cli);
847 SCVAL(smb_buf(cli->outbuf),0,2);
850 if (!cli_receive_smb(cli))
853 show_msg(cli->inbuf);
855 if (cli_is_error(cli) ||
856 ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
860 cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
862 if (cli->protocol >= PROTOCOL_NT1) {
864 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
865 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
866 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
867 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
868 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1);
869 cli->serverzone *= 60;
870 /* this time arrives in real GMT */
871 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
872 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
873 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
874 if (cli->capabilities & CAP_RAW_MODE) {
875 cli->readbraw_supported = True;
876 cli->writebraw_supported = True;
878 /* work out if they sent us a workgroup */
879 if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
880 smb_buflen(cli->inbuf) > 8) {
881 clistr_pull(cli, cli->server_domain,
882 smb_buf(cli->inbuf)+8, sizeof(cli->server_domain),
883 smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
886 /* A way to attempt to force SMB signing */
887 if (getenv("CLI_FORCE_SMB_SIGNING"))
888 cli->sign_info.negotiated_smb_signing = True;
890 if (cli->sign_info.negotiated_smb_signing && !(cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED))
891 cli->sign_info.negotiated_smb_signing = False;
893 } else if (cli->protocol >= PROTOCOL_LANMAN1) {
894 cli->use_spnego = False;
895 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
896 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
897 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
898 cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
899 cli->serverzone *= 60;
900 /* this time is converted to GMT by make_unix_date */
901 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
902 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
903 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
904 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
906 /* the old core protocol */
907 cli->use_spnego = False;
909 cli->serverzone = TimeDiff(time(NULL));
912 cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
914 /* a way to force ascii SMB */
915 if (getenv("CLI_FORCE_ASCII")) {
916 cli->capabilities &= ~CAP_UNICODE;
922 /****************************************************************************
923 Send a session request. See rfc1002.txt 4.3 and 4.3.2.
924 ****************************************************************************/
926 BOOL cli_session_request(struct cli_state *cli,
927 struct nmb_name *calling, struct nmb_name *called)
931 extern pstring user_socket_options;
933 /* 445 doesn't have session request */
934 if (cli->port == 445) return True;
936 if (cli->sign_info.use_smb_signing) {
937 DEBUG(0, ("Cannot send session resquest again, particularly after setting up SMB Signing\n"));
941 /* send a session request (RFC 1002) */
942 memcpy(&(cli->calling), calling, sizeof(*calling));
943 memcpy(&(cli->called ), called , sizeof(*called ));
945 /* put in the destination name */
947 name_mangle(cli->called .name, p, cli->called .name_type);
952 name_mangle(cli->calling.name, p, cli->calling.name_type);
955 /* setup the packet length */
956 _smb_setlen(cli->outbuf,len);
957 SCVAL(cli->outbuf,0,0x81);
960 DEBUG(5,("Sent session request\n"));
962 if (!cli_receive_smb(cli))
965 if (CVAL(cli->inbuf,0) == 0x84) {
966 /* C. Hoch 9/14/95 Start */
967 /* For information, here is the response structure.
968 * We do the byte-twiddling to for portability.
969 struct RetargetResponse{
977 int port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
978 /* SESSION RETARGET */
979 putip((char *)&cli->dest_ip,cli->inbuf+4);
981 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
985 DEBUG(3,("Retargeted\n"));
987 set_socket_options(cli->fd,user_socket_options);
994 DEBUG(0,("Retarget recursion - failing\n"));
998 ret = cli_session_request(cli, calling, called);
1002 } /* C. Hoch 9/14/95 End */
1004 if (CVAL(cli->inbuf,0) != 0x82) {
1005 /* This is the wrong place to put the error... JRA. */
1006 cli->rap_error = CVAL(cli->inbuf,4);
1012 /****************************************************************************
1013 Open the client sockets.
1014 ****************************************************************************/
1016 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
1018 extern pstring user_socket_options;
1019 int name_type = 0x20;
1022 /* reasonable default hostname */
1023 if (!host) host = "*SMBSERVER";
1025 fstrcpy(cli->desthost, host);
1027 /* allow hostnames of the form NAME#xx and do a netbios lookup */
1028 if ((p = strchr(cli->desthost, '#'))) {
1029 name_type = strtol(p+1, NULL, 16);
1033 if (!ip || is_zero_ip(*ip)) {
1034 if (!resolve_name(cli->desthost, &cli->dest_ip, name_type)) {
1037 if (ip) *ip = cli->dest_ip;
1042 if (getenv("LIBSMB_PROG")) {
1043 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
1045 /* try 445 first, then 139 */
1046 int port = cli->port?cli->port:445;
1047 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
1048 port, cli->timeout);
1049 if (cli->fd == -1 && cli->port == 0) {
1051 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
1052 port, cli->timeout);
1054 if (cli->fd != -1) cli->port = port;
1056 if (cli->fd == -1) {
1057 DEBUG(1,("Error connecting to %s (%s)\n",
1058 inet_ntoa(*ip),strerror(errno)));
1062 set_socket_options(cli->fd,user_socket_options);
1067 /****************************************************************************
1068 Initialise client credentials for authenticated pipe access.
1069 ****************************************************************************/
1071 static void init_creds(struct ntuser_creds *creds, char* username,
1072 char* domain, char* password)
1074 ZERO_STRUCTP(creds);
1076 pwd_set_cleartext(&creds->pwd, password);
1078 fstrcpy(creds->user_name, username);
1079 fstrcpy(creds->domain, domain);
1082 creds->pwd.null_pwd = True;
1087 establishes a connection right up to doing tconX, password specified.
1088 @param output_cli A fully initialised cli structure, non-null only on success
1089 @param dest_host The netbios name of the remote host
1090 @param dest_ip (optional) The the destination IP, NULL for name based lookup
1091 @param port (optional) The destination port (0 for default)
1092 @param service (optional) The share to make the connection to. Should be 'unqualified' in any way.
1093 @param service_type The 'type' of serivice.
1094 @param user Username, unix string
1095 @param domain User's domain
1096 @param password User's password, unencrypted unix string.
1099 NTSTATUS cli_full_connection(struct cli_state **output_cli,
1100 const char *my_name,
1101 const char *dest_host,
1102 struct in_addr *dest_ip, int port,
1103 char *service, char *service_type,
1104 char *user, char *domain,
1105 char *password, int flags)
1107 struct ntuser_creds creds;
1109 struct nmb_name calling;
1110 struct nmb_name called;
1111 struct cli_state *cli;
1113 extern pstring global_myname;
1116 DEBUG(0, ("output_cli is NULL!?!"));
1117 SMB_ASSERT("output_cli for cli_full_connection was NULL.\n");
1121 my_name = global_myname;
1123 if (!(cli = cli_initialise(NULL)))
1124 return NT_STATUS_NO_MEMORY;
1126 make_nmb_name(&calling, my_name, 0x0);
1127 make_nmb_name(&called , dest_host, 0x20);
1129 if (cli_set_port(cli, port) != port) {
1131 return NT_STATUS_UNSUCCESSFUL;
1142 DEBUG(3,("Connecting to host=%s share=%s\n", dest_host, service));
1144 if (!cli_connect(cli, dest_host, &ip)) {
1145 DEBUG(1,("cli_full_connection: failed to connect to %s (%s)\n",
1146 nmb_namestr(&called), inet_ntoa(ip)));
1148 return NT_STATUS_UNSUCCESSFUL;
1151 if (!cli_session_request(cli, &calling, &called)) {
1153 DEBUG(1,("session request to %s failed (%s)\n",
1154 called.name, cli_errstr(cli)));
1156 if ((p=strchr(called.name, '.'))) {
1160 if (strcmp(called.name, "*SMBSERVER")) {
1161 make_nmb_name(&called , "*SMBSERVER", 0x20);
1164 return NT_STATUS_UNSUCCESSFUL;
1167 if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO) {
1168 cli->use_spnego = False;
1169 } else if (flags & CLI_FULL_CONNECTION_USE_KERBEROS) {
1170 cli->use_kerberos = True;
1173 if (!cli_negprot(cli)) {
1174 DEBUG(1,("failed negprot\n"));
1175 nt_status = NT_STATUS_UNSUCCESSFUL;
1180 if (!cli_session_setup(cli, user, password, strlen(password)+1,
1181 password, strlen(password)+1,
1183 if (!(flags & CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK)
1184 || cli_session_setup(cli, "", "", 0,
1187 nt_status = cli_nt_error(cli);
1188 DEBUG(1,("failed session setup with %s\n", nt_errstr(nt_status)));
1190 if (NT_STATUS_IS_OK(nt_status))
1191 nt_status = NT_STATUS_UNSUCCESSFUL;
1197 if (!cli_send_tconX(cli, service, service_type,
1198 (char*)password, strlen(password)+1)) {
1199 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(nt_status)));
1200 nt_status = cli_nt_error(cli);
1202 if (NT_STATUS_IS_OK(nt_status)) {
1203 nt_status = NT_STATUS_UNSUCCESSFUL;
1209 init_creds(&creds, user, domain, password);
1210 cli_init_creds(cli, &creds);
1213 return NT_STATUS_OK;
1216 /****************************************************************************
1217 Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
1218 ****************************************************************************/
1220 BOOL attempt_netbios_session_request(struct cli_state *cli, char *srchost, char *desthost,
1221 struct in_addr *pdest_ip)
1223 struct nmb_name calling, called;
1225 make_nmb_name(&calling, srchost, 0x0);
1228 * If the called name is an IP address
1229 * then use *SMBSERVER immediately.
1232 if(is_ipaddress(desthost))
1233 make_nmb_name(&called, "*SMBSERVER", 0x20);
1235 make_nmb_name(&called, desthost, 0x20);
1237 if (!cli_session_request(cli, &calling, &called)) {
1238 struct nmb_name smbservername;
1240 make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
1243 * If the name wasn't *SMBSERVER then
1244 * try with *SMBSERVER if the first name fails.
1247 if (nmb_name_equal(&called, &smbservername)) {
1250 * The name used was *SMBSERVER, don't bother with another name.
1253 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
1254 with error %s.\n", desthost, cli_errstr(cli) ));
1261 if (!cli_initialise(cli) ||
1262 !cli_connect(cli, desthost, pdest_ip) ||
1263 !cli_session_request(cli, &calling, &smbservername)) {
1264 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
1265 name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) ));