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 0 /* JRATEST for signing. */
639 /* if the server supports extended security then use SPNEGO */
640 if (cli->capabilities & CAP_EXTENDED_SECURITY) {
641 return cli_session_setup_spnego(cli, user, pass, workgroup);
645 /* otherwise do a NT1 style session setup */
646 return cli_session_setup_nt1(cli, user,
647 pass, passlen, ntpass, ntpasslen,
651 /****************************************************************************
653 *****************************************************************************/
655 BOOL cli_ulogoff(struct cli_state *cli)
657 memset(cli->outbuf,'\0',smb_size);
658 set_message(cli->outbuf,2,0,True);
659 SCVAL(cli->outbuf,smb_com,SMBulogoffX);
660 cli_setup_packet(cli);
661 SSVAL(cli->outbuf,smb_vwv0,0xFF);
662 SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
665 if (!cli_receive_smb(cli))
668 return !cli_is_error(cli);
671 /****************************************************************************
673 ****************************************************************************/
675 BOOL cli_send_tconX(struct cli_state *cli,
676 const char *share, const char *dev, const char *pass, int passlen)
678 fstring fullshare, pword;
680 memset(cli->outbuf,'\0',smb_size);
681 memset(cli->inbuf,'\0',smb_size);
683 fstrcpy(cli->share, share);
685 /* in user level security don't send a password now */
686 if (cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) {
691 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && *pass && passlen != 24) {
693 * Non-encrypted passwords - convert to DOS codepage before encryption.
696 SMBencrypt(pass,cli->secblob.data,(uchar *)pword);
698 if((cli->sec_mode & (NEGOTIATE_SECURITY_USER_LEVEL|NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)) == 0) {
700 * Non-encrypted passwords - convert to DOS codepage before using.
702 passlen = clistr_push(cli, pword, pass, -1, STR_TERMINATE);
704 memcpy(pword, pass, passlen);
708 if (cli->port == 445) {
709 slprintf(fullshare, sizeof(fullshare)-1,
712 slprintf(fullshare, sizeof(fullshare)-1,
713 "\\\\%s\\%s", cli->desthost, share);
716 set_message(cli->outbuf,4, 0, True);
717 SCVAL(cli->outbuf,smb_com,SMBtconX);
718 cli_setup_packet(cli);
720 SSVAL(cli->outbuf,smb_vwv0,0xFF);
721 SSVAL(cli->outbuf,smb_vwv3,passlen);
723 p = smb_buf(cli->outbuf);
724 memcpy(p,pword,passlen);
726 p += clistr_push(cli, p, fullshare, -1, STR_TERMINATE |STR_UPPER);
727 fstrcpy(p, dev); p += strlen(dev)+1;
729 cli_setup_bcc(cli, p);
732 if (!cli_receive_smb(cli))
735 if (cli_is_error(cli)) {
739 clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE|STR_ASCII);
741 if (strcasecmp(share,"IPC$")==0) {
742 fstrcpy(cli->dev, "IPC");
745 if (cli->protocol >= PROTOCOL_NT1 &&
746 smb_buflen(cli->inbuf) == 3) {
747 /* almost certainly win95 - enable bug fixes */
751 cli->cnum = SVAL(cli->inbuf,smb_tid);
755 /****************************************************************************
756 Send a tree disconnect.
757 ****************************************************************************/
759 BOOL cli_tdis(struct cli_state *cli)
761 memset(cli->outbuf,'\0',smb_size);
762 set_message(cli->outbuf,0,0,True);
763 SCVAL(cli->outbuf,smb_com,SMBtdis);
764 SSVAL(cli->outbuf,smb_tid,cli->cnum);
765 cli_setup_packet(cli);
768 if (!cli_receive_smb(cli))
771 return !cli_is_error(cli);
774 /****************************************************************************
775 Send a negprot command.
776 ****************************************************************************/
778 void cli_negprot_send(struct cli_state *cli)
783 if (cli->protocol < PROTOCOL_NT1) {
784 cli->use_spnego = False;
787 memset(cli->outbuf,'\0',smb_size);
789 /* setup the protocol strings */
790 set_message(cli->outbuf,0,0,True);
792 p = smb_buf(cli->outbuf);
794 prots[numprots].name && prots[numprots].prot<=cli->protocol;
797 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
800 SCVAL(cli->outbuf,smb_com,SMBnegprot);
801 cli_setup_bcc(cli, p);
802 cli_setup_packet(cli);
804 SCVAL(smb_buf(cli->outbuf),0,2);
809 /****************************************************************************
810 Send a negprot command.
811 ****************************************************************************/
813 BOOL cli_negprot(struct cli_state *cli)
819 if (cli->sign_info.use_smb_signing) {
820 DEBUG(0, ("Cannot send negprot again, particularly after setting up SMB Signing\n"));
824 if (cli->protocol < PROTOCOL_NT1) {
825 cli->use_spnego = False;
828 #if 1 /* JRA SIGN TEST */
829 cli->use_spnego = False;
832 memset(cli->outbuf,'\0',smb_size);
834 /* setup the protocol strings */
835 for (plength=0,numprots=0;
836 prots[numprots].name && prots[numprots].prot<=cli->protocol;
838 plength += strlen(prots[numprots].name)+2;
840 set_message(cli->outbuf,0,plength,True);
842 p = smb_buf(cli->outbuf);
844 prots[numprots].name && prots[numprots].prot<=cli->protocol;
847 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
850 SCVAL(cli->outbuf,smb_com,SMBnegprot);
851 cli_setup_packet(cli);
853 SCVAL(smb_buf(cli->outbuf),0,2);
856 if (!cli_receive_smb(cli))
859 show_msg(cli->inbuf);
861 if (cli_is_error(cli) ||
862 ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
866 cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
868 if (cli->protocol >= PROTOCOL_NT1) {
870 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
871 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
872 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
873 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
874 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1);
875 cli->serverzone *= 60;
876 /* this time arrives in real GMT */
877 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
878 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
879 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
880 if (cli->capabilities & CAP_RAW_MODE) {
881 cli->readbraw_supported = True;
882 cli->writebraw_supported = True;
884 /* work out if they sent us a workgroup */
885 if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
886 smb_buflen(cli->inbuf) > 8) {
887 clistr_pull(cli, cli->server_domain,
888 smb_buf(cli->inbuf)+8, sizeof(cli->server_domain),
889 smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
892 /* A way to attempt to force SMB signing */
893 if (getenv("CLI_FORCE_SMB_SIGNING"))
894 cli->sign_info.negotiated_smb_signing = True;
897 if (cli->sign_info.negotiated_smb_signing && !(cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED))
898 cli->sign_info.negotiated_smb_signing = False;
901 } else if (cli->protocol >= PROTOCOL_LANMAN1) {
902 cli->use_spnego = False;
903 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
904 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
905 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
906 cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
907 cli->serverzone *= 60;
908 /* this time is converted to GMT by make_unix_date */
909 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
910 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
911 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
912 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
914 /* the old core protocol */
915 cli->use_spnego = False;
917 cli->serverzone = TimeDiff(time(NULL));
920 cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
922 /* a way to force ascii SMB */
923 if (getenv("CLI_FORCE_ASCII")) {
924 cli->capabilities &= ~CAP_UNICODE;
930 /****************************************************************************
931 Send a session request. See rfc1002.txt 4.3 and 4.3.2.
932 ****************************************************************************/
934 BOOL cli_session_request(struct cli_state *cli,
935 struct nmb_name *calling, struct nmb_name *called)
939 extern pstring user_socket_options;
941 /* 445 doesn't have session request */
942 if (cli->port == 445) return True;
944 if (cli->sign_info.use_smb_signing) {
945 DEBUG(0, ("Cannot send session resquest again, particularly after setting up SMB Signing\n"));
949 /* send a session request (RFC 1002) */
950 memcpy(&(cli->calling), calling, sizeof(*calling));
951 memcpy(&(cli->called ), called , sizeof(*called ));
953 /* put in the destination name */
955 name_mangle(cli->called .name, p, cli->called .name_type);
960 name_mangle(cli->calling.name, p, cli->calling.name_type);
963 /* setup the packet length */
964 _smb_setlen(cli->outbuf,len);
965 SCVAL(cli->outbuf,0,0x81);
968 DEBUG(5,("Sent session request\n"));
970 if (!cli_receive_smb(cli))
973 if (CVAL(cli->inbuf,0) == 0x84) {
974 /* C. Hoch 9/14/95 Start */
975 /* For information, here is the response structure.
976 * We do the byte-twiddling to for portability.
977 struct RetargetResponse{
985 int port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
986 /* SESSION RETARGET */
987 putip((char *)&cli->dest_ip,cli->inbuf+4);
989 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
993 DEBUG(3,("Retargeted\n"));
995 set_socket_options(cli->fd,user_socket_options);
1002 DEBUG(0,("Retarget recursion - failing\n"));
1006 ret = cli_session_request(cli, calling, called);
1010 } /* C. Hoch 9/14/95 End */
1012 if (CVAL(cli->inbuf,0) != 0x82) {
1013 /* This is the wrong place to put the error... JRA. */
1014 cli->rap_error = CVAL(cli->inbuf,4);
1020 /****************************************************************************
1021 Open the client sockets.
1022 ****************************************************************************/
1024 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
1026 extern pstring user_socket_options;
1027 int name_type = 0x20;
1030 /* reasonable default hostname */
1031 if (!host) host = "*SMBSERVER";
1033 fstrcpy(cli->desthost, host);
1035 /* allow hostnames of the form NAME#xx and do a netbios lookup */
1036 if ((p = strchr(cli->desthost, '#'))) {
1037 name_type = strtol(p+1, NULL, 16);
1041 if (!ip || is_zero_ip(*ip)) {
1042 if (!resolve_name(cli->desthost, &cli->dest_ip, name_type)) {
1045 if (ip) *ip = cli->dest_ip;
1050 if (getenv("LIBSMB_PROG")) {
1051 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
1053 /* try 445 first, then 139 */
1054 int port = cli->port?cli->port:445;
1055 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
1056 port, cli->timeout);
1057 if (cli->fd == -1 && cli->port == 0) {
1059 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
1060 port, cli->timeout);
1062 if (cli->fd != -1) cli->port = port;
1064 if (cli->fd == -1) {
1065 DEBUG(1,("Error connecting to %s (%s)\n",
1066 inet_ntoa(*ip),strerror(errno)));
1070 set_socket_options(cli->fd,user_socket_options);
1075 /****************************************************************************
1076 Initialise client credentials for authenticated pipe access.
1077 ****************************************************************************/
1079 static void init_creds(struct ntuser_creds *creds, char* username,
1080 char* domain, char* password)
1082 ZERO_STRUCTP(creds);
1084 pwd_set_cleartext(&creds->pwd, password);
1086 fstrcpy(creds->user_name, username);
1087 fstrcpy(creds->domain, domain);
1090 creds->pwd.null_pwd = True;
1095 establishes a connection right up to doing tconX, password specified.
1096 @param output_cli A fully initialised cli structure, non-null only on success
1097 @param dest_host The netbios name of the remote host
1098 @param dest_ip (optional) The the destination IP, NULL for name based lookup
1099 @param port (optional) The destination port (0 for default)
1100 @param service (optional) The share to make the connection to. Should be 'unqualified' in any way.
1101 @param service_type The 'type' of serivice.
1102 @param user Username, unix string
1103 @param domain User's domain
1104 @param password User's password, unencrypted unix string.
1107 NTSTATUS cli_full_connection(struct cli_state **output_cli,
1108 const char *my_name,
1109 const char *dest_host,
1110 struct in_addr *dest_ip, int port,
1111 char *service, char *service_type,
1112 char *user, char *domain,
1113 char *password, int flags)
1115 struct ntuser_creds creds;
1117 struct nmb_name calling;
1118 struct nmb_name called;
1119 struct cli_state *cli;
1121 extern pstring global_myname;
1124 DEBUG(0, ("output_cli is NULL!?!"));
1125 SMB_ASSERT("output_cli for cli_full_connection was NULL.\n");
1129 my_name = global_myname;
1131 if (!(cli = cli_initialise(NULL)))
1132 return NT_STATUS_NO_MEMORY;
1134 make_nmb_name(&calling, my_name, 0x0);
1135 make_nmb_name(&called , dest_host, 0x20);
1137 if (cli_set_port(cli, port) != port) {
1139 return NT_STATUS_UNSUCCESSFUL;
1150 DEBUG(3,("Connecting to host=%s share=%s\n", dest_host, service));
1152 if (!cli_connect(cli, dest_host, &ip)) {
1153 DEBUG(1,("cli_full_connection: failed to connect to %s (%s)\n",
1154 nmb_namestr(&called), inet_ntoa(ip)));
1156 return NT_STATUS_UNSUCCESSFUL;
1159 if (!cli_session_request(cli, &calling, &called)) {
1161 DEBUG(1,("session request to %s failed (%s)\n",
1162 called.name, cli_errstr(cli)));
1164 if ((p=strchr(called.name, '.'))) {
1168 if (strcmp(called.name, "*SMBSERVER")) {
1169 make_nmb_name(&called , "*SMBSERVER", 0x20);
1172 return NT_STATUS_UNSUCCESSFUL;
1175 if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO) {
1176 cli->use_spnego = False;
1177 } else if (flags & CLI_FULL_CONNECTION_USE_KERBEROS) {
1178 cli->use_kerberos = True;
1181 if (!cli_negprot(cli)) {
1182 DEBUG(1,("failed negprot\n"));
1183 nt_status = NT_STATUS_UNSUCCESSFUL;
1188 if (!cli_session_setup(cli, user, password, strlen(password)+1,
1189 password, strlen(password)+1,
1191 if (!(flags & CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK)
1192 || cli_session_setup(cli, "", "", 0,
1195 nt_status = cli_nt_error(cli);
1196 DEBUG(1,("failed session setup with %s\n", nt_errstr(nt_status)));
1198 if (NT_STATUS_IS_OK(nt_status))
1199 nt_status = NT_STATUS_UNSUCCESSFUL;
1205 if (!cli_send_tconX(cli, service, service_type,
1206 (char*)password, strlen(password)+1)) {
1207 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(nt_status)));
1208 nt_status = cli_nt_error(cli);
1210 if (NT_STATUS_IS_OK(nt_status)) {
1211 nt_status = NT_STATUS_UNSUCCESSFUL;
1217 init_creds(&creds, user, domain, password);
1218 cli_init_creds(cli, &creds);
1221 return NT_STATUS_OK;
1224 /****************************************************************************
1225 Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
1226 ****************************************************************************/
1228 BOOL attempt_netbios_session_request(struct cli_state *cli, char *srchost, char *desthost,
1229 struct in_addr *pdest_ip)
1231 struct nmb_name calling, called;
1233 make_nmb_name(&calling, srchost, 0x0);
1236 * If the called name is an IP address
1237 * then use *SMBSERVER immediately.
1240 if(is_ipaddress(desthost))
1241 make_nmb_name(&called, "*SMBSERVER", 0x20);
1243 make_nmb_name(&called, desthost, 0x20);
1245 if (!cli_session_request(cli, &calling, &called)) {
1246 struct nmb_name smbservername;
1248 make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
1251 * If the name wasn't *SMBSERVER then
1252 * try with *SMBSERVER if the first name fails.
1255 if (nmb_name_equal(&called, &smbservername)) {
1258 * The name used was *SMBSERVER, don't bother with another name.
1261 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
1262 with error %s.\n", desthost, cli_errstr(cli) ));
1269 if (!cli_initialise(cli) ||
1270 !cli_connect(cli, desthost, pdest_ip) ||
1271 !cli_session_request(cli, &calling, &smbservername)) {
1272 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
1273 name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) ));