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 * Remove four bytes from the length count, since the length
957 * field in the NBT Session Service header counts the number
958 * of bytes which follow. The cli_send_smb() function knows
959 * about this and accounts for those four bytes.
963 _smb_setlen(cli->outbuf,len);
964 SCVAL(cli->outbuf,0,0x81);
967 DEBUG(5,("Sent session request\n"));
969 if (!cli_receive_smb(cli))
972 if (CVAL(cli->inbuf,0) == 0x84) {
973 /* C. Hoch 9/14/95 Start */
974 /* For information, here is the response structure.
975 * We do the byte-twiddling to for portability.
976 struct RetargetResponse{
984 int port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
985 /* SESSION RETARGET */
986 putip((char *)&cli->dest_ip,cli->inbuf+4);
988 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
992 DEBUG(3,("Retargeted\n"));
994 set_socket_options(cli->fd,user_socket_options);
1001 DEBUG(0,("Retarget recursion - failing\n"));
1005 ret = cli_session_request(cli, calling, called);
1009 } /* C. Hoch 9/14/95 End */
1011 if (CVAL(cli->inbuf,0) != 0x82) {
1012 /* This is the wrong place to put the error... JRA. */
1013 cli->rap_error = CVAL(cli->inbuf,4);
1019 /****************************************************************************
1020 Open the client sockets.
1021 ****************************************************************************/
1023 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
1025 extern pstring user_socket_options;
1026 int name_type = 0x20;
1029 /* reasonable default hostname */
1030 if (!host) host = "*SMBSERVER";
1032 fstrcpy(cli->desthost, host);
1034 /* allow hostnames of the form NAME#xx and do a netbios lookup */
1035 if ((p = strchr(cli->desthost, '#'))) {
1036 name_type = strtol(p+1, NULL, 16);
1040 if (!ip || is_zero_ip(*ip)) {
1041 if (!resolve_name(cli->desthost, &cli->dest_ip, name_type)) {
1044 if (ip) *ip = cli->dest_ip;
1049 if (getenv("LIBSMB_PROG")) {
1050 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
1052 /* try 445 first, then 139 */
1053 int port = cli->port?cli->port:445;
1054 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
1055 port, cli->timeout);
1056 if (cli->fd == -1 && cli->port == 0) {
1058 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
1059 port, cli->timeout);
1061 if (cli->fd != -1) cli->port = port;
1063 if (cli->fd == -1) {
1064 DEBUG(1,("Error connecting to %s (%s)\n",
1065 inet_ntoa(*ip),strerror(errno)));
1069 set_socket_options(cli->fd,user_socket_options);
1074 /****************************************************************************
1075 Initialise client credentials for authenticated pipe access.
1076 ****************************************************************************/
1078 static void init_creds(struct ntuser_creds *creds, char* username,
1079 char* domain, char* password)
1081 ZERO_STRUCTP(creds);
1083 pwd_set_cleartext(&creds->pwd, password);
1085 fstrcpy(creds->user_name, username);
1086 fstrcpy(creds->domain, domain);
1089 creds->pwd.null_pwd = True;
1094 establishes a connection right up to doing tconX, password specified.
1095 @param output_cli A fully initialised cli structure, non-null only on success
1096 @param dest_host The netbios name of the remote host
1097 @param dest_ip (optional) The the destination IP, NULL for name based lookup
1098 @param port (optional) The destination port (0 for default)
1099 @param service (optional) The share to make the connection to. Should be 'unqualified' in any way.
1100 @param service_type The 'type' of serivice.
1101 @param user Username, unix string
1102 @param domain User's domain
1103 @param password User's password, unencrypted unix string.
1106 NTSTATUS cli_full_connection(struct cli_state **output_cli,
1107 const char *my_name,
1108 const char *dest_host,
1109 struct in_addr *dest_ip, int port,
1110 char *service, char *service_type,
1111 char *user, char *domain,
1112 char *password, int flags)
1114 struct ntuser_creds creds;
1116 struct nmb_name calling;
1117 struct nmb_name called;
1118 struct cli_state *cli;
1120 extern pstring global_myname;
1123 DEBUG(0, ("output_cli is NULL!?!"));
1124 SMB_ASSERT("output_cli for cli_full_connection was NULL.\n");
1128 my_name = global_myname;
1130 if (!(cli = cli_initialise(NULL)))
1131 return NT_STATUS_NO_MEMORY;
1133 make_nmb_name(&calling, my_name, 0x0);
1134 make_nmb_name(&called , dest_host, 0x20);
1136 if (cli_set_port(cli, port) != port) {
1138 return NT_STATUS_UNSUCCESSFUL;
1149 DEBUG(3,("Connecting to host=%s share=%s\n", dest_host, service));
1151 if (!cli_connect(cli, dest_host, &ip)) {
1152 DEBUG(1,("cli_full_connection: failed to connect to %s (%s)\n",
1153 nmb_namestr(&called), inet_ntoa(ip)));
1155 return NT_STATUS_UNSUCCESSFUL;
1158 if (!cli_session_request(cli, &calling, &called)) {
1160 DEBUG(1,("session request to %s failed (%s)\n",
1161 called.name, cli_errstr(cli)));
1163 if ((p=strchr(called.name, '.'))) {
1167 if (strcmp(called.name, "*SMBSERVER")) {
1168 make_nmb_name(&called , "*SMBSERVER", 0x20);
1171 return NT_STATUS_UNSUCCESSFUL;
1174 if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO) {
1175 cli->use_spnego = False;
1176 } else if (flags & CLI_FULL_CONNECTION_USE_KERBEROS) {
1177 cli->use_kerberos = True;
1180 if (!cli_negprot(cli)) {
1181 DEBUG(1,("failed negprot\n"));
1182 nt_status = NT_STATUS_UNSUCCESSFUL;
1187 if (!cli_session_setup(cli, user, password, strlen(password)+1,
1188 password, strlen(password)+1,
1190 if (!(flags & CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK)
1191 || cli_session_setup(cli, "", "", 0,
1194 nt_status = cli_nt_error(cli);
1195 DEBUG(1,("failed session setup with %s\n", nt_errstr(nt_status)));
1197 if (NT_STATUS_IS_OK(nt_status))
1198 nt_status = NT_STATUS_UNSUCCESSFUL;
1204 if (!cli_send_tconX(cli, service, service_type,
1205 (char*)password, strlen(password)+1)) {
1206 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(nt_status)));
1207 nt_status = cli_nt_error(cli);
1209 if (NT_STATUS_IS_OK(nt_status)) {
1210 nt_status = NT_STATUS_UNSUCCESSFUL;
1216 init_creds(&creds, user, domain, password);
1217 cli_init_creds(cli, &creds);
1220 return NT_STATUS_OK;
1223 /****************************************************************************
1224 Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
1225 ****************************************************************************/
1227 BOOL attempt_netbios_session_request(struct cli_state *cli, char *srchost, char *desthost,
1228 struct in_addr *pdest_ip)
1230 struct nmb_name calling, called;
1232 make_nmb_name(&calling, srchost, 0x0);
1235 * If the called name is an IP address
1236 * then use *SMBSERVER immediately.
1239 if(is_ipaddress(desthost))
1240 make_nmb_name(&called, "*SMBSERVER", 0x20);
1242 make_nmb_name(&called, desthost, 0x20);
1244 if (!cli_session_request(cli, &calling, &called)) {
1245 struct nmb_name smbservername;
1247 make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
1250 * If the name wasn't *SMBSERVER then
1251 * try with *SMBSERVER if the first name fails.
1254 if (nmb_name_equal(&called, &smbservername)) {
1257 * The name used was *SMBSERVER, don't bother with another name.
1260 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
1261 with error %s.\n", desthost, cli_errstr(cli) ));
1268 if (!cli_initialise(cli) ||
1269 !cli_connect(cli, desthost, pdest_ip) ||
1270 !cli_session_request(cli, &calling, &smbservername)) {
1271 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
1272 name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) ));