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)
56 /* if in share level security then don't send a password now */
57 if (!(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL))
60 if (passlen > 0 && (cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen != 24) {
61 /* Encrypted mode needed, and non encrypted password supplied. */
63 SMBencrypt(pass,cli->secblob.data,(uchar *)pword);
64 } else if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen == 24) {
65 /* Encrypted mode needed, and encrypted password supplied. */
66 memcpy(pword, pass, passlen);
67 } else if (passlen > 0) {
68 /* Plaintext mode needed, assume plaintext supplied. */
69 passlen = clistr_push(cli, pword, pass, -1, STR_TERMINATE);
72 /* send a session setup command */
73 memset(cli->outbuf,'\0',smb_size);
74 set_message(cli->outbuf,10, 0, True);
75 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
76 cli_setup_packet(cli);
78 SCVAL(cli->outbuf,smb_vwv0,0xFF);
79 SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
80 SSVAL(cli->outbuf,smb_vwv3,2);
81 SSVAL(cli->outbuf,smb_vwv4,1);
82 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
83 SSVAL(cli->outbuf,smb_vwv7,passlen);
85 p = smb_buf(cli->outbuf);
86 memcpy(p,pword,passlen);
88 p += clistr_push(cli, p, user, -1, STR_TERMINATE|STR_UPPER);
89 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
90 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
91 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
92 cli_setup_bcc(cli, p);
95 if (!cli_receive_smb(cli))
100 if (cli_is_error(cli))
103 /* use the returned vuid from now on */
104 cli->vuid = SVAL(cli->inbuf,smb_uid);
105 fstrcpy(cli->user_name, user);
110 /****************************************************************************
111 Work out suitable capabilities to offer the server.
112 ****************************************************************************/
114 static uint32 cli_session_setup_capabilities(struct cli_state *cli)
116 uint32 capabilities = CAP_NT_SMBS;
118 if (!cli->force_dos_errors)
119 capabilities |= CAP_STATUS32;
121 if (cli->use_level_II_oplocks)
122 capabilities |= CAP_LEVEL_II_OPLOCKS;
124 if (cli->capabilities & CAP_UNICODE)
125 capabilities |= CAP_UNICODE;
130 /****************************************************************************
131 Do a NT1 guest session setup.
132 ****************************************************************************/
134 static BOOL cli_session_setup_guest(struct cli_state *cli)
137 uint32 capabilities = cli_session_setup_capabilities(cli);
139 set_message(cli->outbuf,13,0,True);
140 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
141 cli_setup_packet(cli);
143 SCVAL(cli->outbuf,smb_vwv0,0xFF);
144 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
145 SSVAL(cli->outbuf,smb_vwv3,2);
146 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
147 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
148 SSVAL(cli->outbuf,smb_vwv7,0);
149 SSVAL(cli->outbuf,smb_vwv8,0);
150 SIVAL(cli->outbuf,smb_vwv11,capabilities);
151 p = smb_buf(cli->outbuf);
152 p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* username */
153 p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* workgroup */
154 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
155 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
156 cli_setup_bcc(cli, p);
159 if (!cli_receive_smb(cli))
162 show_msg(cli->inbuf);
164 if (cli_is_error(cli))
167 cli->vuid = SVAL(cli->inbuf,smb_uid);
169 p = smb_buf(cli->inbuf);
170 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
171 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
172 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
174 fstrcpy(cli->user_name, "");
179 /****************************************************************************
180 Do a NT1 plaintext session setup.
181 ****************************************************************************/
183 static BOOL cli_session_setup_plaintext(struct cli_state *cli, char *user,
184 char *pass, char *workgroup)
186 uint32 capabilities = cli_session_setup_capabilities(cli);
189 set_message(cli->outbuf,13,0,True);
190 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
191 cli_setup_packet(cli);
193 SCVAL(cli->outbuf,smb_vwv0,0xFF);
194 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
195 SSVAL(cli->outbuf,smb_vwv3,2);
196 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
197 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
198 SSVAL(cli->outbuf,smb_vwv8,0);
199 SIVAL(cli->outbuf,smb_vwv11,capabilities);
200 p = smb_buf(cli->outbuf);
201 p += clistr_push(cli, p, pass, -1, STR_TERMINATE); /* password */
202 SSVAL(cli->outbuf,smb_vwv7,PTR_DIFF(p, smb_buf(cli->outbuf)));
203 p += clistr_push(cli, p, user, -1, STR_TERMINATE); /* username */
204 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE); /* workgroup */
205 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
206 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
207 cli_setup_bcc(cli, p);
210 if (!cli_receive_smb(cli))
213 show_msg(cli->inbuf);
215 if (cli_is_error(cli))
218 cli->vuid = SVAL(cli->inbuf,smb_uid);
219 p = smb_buf(cli->inbuf);
220 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
221 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
222 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
223 fstrcpy(cli->user_name, user);
228 static void set_signing_on_cli (struct cli_state *cli, char* pass, uint8 response[24])
231 ZERO_STRUCT(zero_sig);
233 DEBUG(5, ("Server returned security sig:\n"));
234 dump_data(5, &cli->inbuf[smb_ss_field], 8);
236 if (cli->sign_info.use_smb_signing) {
237 DEBUG(5, ("smb signing already active on connection\n"));
238 } else if (memcmp(&cli->inbuf[smb_ss_field], zero_sig, 8) != 0) {
240 DEBUG(3, ("smb signing enabled!\n"));
241 cli->sign_info.use_smb_signing = True;
242 cli_calculate_mac_key(cli, pass, response);
244 DEBUG(5, ("smb signing NOT enabled!\n"));
248 static void set_temp_signing_on_cli(struct cli_state *cli)
250 if (cli->sign_info.negotiated_smb_signing)
251 cli->sign_info.temp_smb_signing = True;
255 /****************************************************************************
256 do a NT1 NTLM/LM encrypted session setup
257 @param cli client state to create do session setup on
259 @param pass *either* cleartext password (passlen !=24) or LM response.
260 @param ntpass NT response, implies ntpasslen >=24, implies pass is not clear
261 @param workgroup The user's domain.
262 ****************************************************************************/
264 static BOOL cli_session_setup_nt1(struct cli_state *cli, char *user,
265 char *pass, int passlen,
266 char *ntpass, int ntpasslen,
269 uint32 capabilities = cli_session_setup_capabilities(cli);
273 BOOL have_plaintext = False;
275 if (passlen > sizeof(pword) || ntpasslen > sizeof(ntpword))
279 /* non encrypted password supplied. Ignore ntpass. */
282 SMBencrypt(pass,cli->secblob.data,pword);
283 SMBNTencrypt(pass,cli->secblob.data,ntpword);
285 have_plaintext = True;
286 set_temp_signing_on_cli(cli);
288 /* pre-encrypted password supplied. Only used for
289 security=server, can't do
290 signing becouse we don't have oringial key */
291 memcpy(pword, pass, 24);
293 memcpy(ntpword, ntpass, 24);
295 ZERO_STRUCT(ntpword);
298 /* send a session setup command */
299 memset(cli->outbuf,'\0',smb_size);
301 set_message(cli->outbuf,13,0,True);
302 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
303 cli_setup_packet(cli);
305 SCVAL(cli->outbuf,smb_vwv0,0xFF);
306 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
307 SSVAL(cli->outbuf,smb_vwv3,2);
308 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
309 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
310 SSVAL(cli->outbuf,smb_vwv7,passlen);
311 SSVAL(cli->outbuf,smb_vwv8,ntpasslen);
312 SIVAL(cli->outbuf,smb_vwv11,capabilities);
313 p = smb_buf(cli->outbuf);
314 memcpy(p,pword,passlen); p += passlen;
315 memcpy(p,ntpword,ntpasslen); p += ntpasslen;
316 p += clistr_push(cli, p, user, -1, STR_TERMINATE);
317 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE);
318 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
319 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
320 cli_setup_bcc(cli, p);
322 if (!cli_send_smb(cli))
325 if (!cli_receive_smb(cli))
328 show_msg(cli->inbuf);
330 if (cli_is_error(cli))
333 /* use the returned vuid from now on */
334 cli->vuid = SVAL(cli->inbuf,smb_uid);
336 p = smb_buf(cli->inbuf);
337 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
338 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
339 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
341 fstrcpy(cli->user_name, user);
343 if (have_plaintext) {
344 /* Have plaintext orginal */
345 set_signing_on_cli(cli, pass, ntpword);
351 /****************************************************************************
352 Send a extended security session setup blob, returning a reply blob.
353 ****************************************************************************/
355 static DATA_BLOB cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob)
357 uint32 capabilities = cli_session_setup_capabilities(cli);
362 blob2 = data_blob(NULL, 0);
364 capabilities |= CAP_EXTENDED_SECURITY;
366 /* send a session setup command */
367 memset(cli->outbuf,'\0',smb_size);
369 set_message(cli->outbuf,12,0,True);
370 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
372 set_temp_signing_on_cli(cli);
374 cli_setup_packet(cli);
376 SCVAL(cli->outbuf,smb_vwv0,0xFF);
377 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
378 SSVAL(cli->outbuf,smb_vwv3,2);
379 SSVAL(cli->outbuf,smb_vwv4,1);
380 SIVAL(cli->outbuf,smb_vwv5,0);
381 SSVAL(cli->outbuf,smb_vwv7,blob.length);
382 SIVAL(cli->outbuf,smb_vwv10,capabilities);
383 p = smb_buf(cli->outbuf);
384 memcpy(p, blob.data, blob.length);
386 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
387 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
388 cli_setup_bcc(cli, p);
391 if (!cli_receive_smb(cli))
394 show_msg(cli->inbuf);
396 if (cli_is_error(cli) && !NT_STATUS_EQUAL(cli_nt_error(cli),
397 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
401 /* use the returned vuid from now on */
402 cli->vuid = SVAL(cli->inbuf,smb_uid);
404 p = smb_buf(cli->inbuf);
406 blob2 = data_blob(p, SVAL(cli->inbuf, smb_vwv3));
409 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
411 /* w2k with kerberos doesn't properly null terminate this field */
412 len = smb_buflen(cli->inbuf) - PTR_DIFF(p, smb_buf(cli->inbuf));
413 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), len, 0);
419 /****************************************************************************
420 Do a spnego/kerberos encrypted session setup.
421 ****************************************************************************/
423 static BOOL cli_session_setup_kerberos(struct cli_state *cli, char *principal, char *workgroup)
425 DATA_BLOB blob2, negTokenTarg;
427 DEBUG(2,("Doing kerberos session setup\n"));
429 /* generate the encapsulated kerberos5 ticket */
430 negTokenTarg = spnego_gen_negTokenTarg(principal, 0);
432 if (!negTokenTarg.data) return False;
435 file_save("negTokenTarg.dat", negTokenTarg.data, negTokenTarg.length);
438 blob2 = cli_session_setup_blob(cli, negTokenTarg);
440 /* we don't need this blob for kerberos */
441 data_blob_free(&blob2);
443 data_blob_free(&negTokenTarg);
445 return !cli_is_error(cli);
449 /****************************************************************************
450 Do a spnego/NTLMSSP encrypted session setup.
451 ****************************************************************************/
453 static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, char *user,
454 char *pass, char *workgroup)
456 DATA_BLOB msg1, struct_blob;
457 DATA_BLOB blob, chal1, chal2, auth, challenge_blob;
459 uint8 nthash[24], lmhash[24], sess_key[16];
460 uint32 neg_flags, chal_flags, ntlmssp_command, unkn1, unkn2;
461 pstring server_domain; /* FIX THIS, SHOULD be UCS2-LE */
463 neg_flags = NTLMSSP_NEGOTIATE_UNICODE |
464 NTLMSSP_NEGOTIATE_128 |
465 NTLMSSP_NEGOTIATE_NTLM;
467 memset(sess_key, 0, 16);
469 DEBUG(10, ("sending NTLMSSP_NEGOTIATE\n"));
471 /* generate the ntlmssp negotiate packet */
472 msrpc_gen(&blob, "CddAA",
476 workgroup, strlen(workgroup),
477 cli->calling.name, strlen(cli->calling.name) + 1);
478 DEBUG(10, ("neg_flags: %0X, workgroup: %s, calling name %s\n",
479 neg_flags, workgroup, cli->calling.name));
480 /* and wrap it in a SPNEGO wrapper */
481 msg1 = gen_negTokenInit(OID_NTLMSSP, blob);
482 data_blob_free(&blob);
484 /* now send that blob on its way */
485 blob = cli_session_setup_blob(cli, msg1);
487 data_blob_free(&msg1);
489 if (!NT_STATUS_EQUAL(cli_nt_error(cli), NT_STATUS_MORE_PROCESSING_REQUIRED))
493 file_save("chal.dat", blob.data, blob.length);
496 /* the server gives us back two challenges */
497 if (!spnego_parse_challenge(blob, &chal1, &chal2)) {
498 DEBUG(3,("Failed to parse challenges\n"));
502 data_blob_free(&blob);
505 * Ok, chal1 and chal2 are actually two identical copies of
506 * the NTLMSSP Challenge BLOB, and they contain, encoded in them
507 * the challenge to use.
510 if (!msrpc_parse(&chal1, "CdUdbddB",
518 DEBUG(0, ("Failed to parse the NTLMSSP Challenge\n"));
522 if (ntlmssp_command != NTLMSSP_CHALLENGE) {
523 DEBUG(0, ("NTLMSSP Response != NTLMSSP_CHALLENGE. Got %0X\n",
528 DEBUG(10, ("Challenge:\n"));
529 dump_data(10, challenge_blob.data, 8);
531 /* encrypt the password with the challenge which is in the blob */
532 memcpy(challenge, challenge_blob.data, 8);
533 SMBencrypt(pass, challenge,lmhash);
534 SMBNTencrypt(pass, challenge,nthash);
535 data_blob_free(&challenge_blob);
538 file_save("nthash.dat", nthash, 24);
539 file_save("lmhash.dat", lmhash, 24);
540 file_save("chal1.dat", chal1.data, chal1.length);
543 data_blob_free(&chal1);
544 data_blob_free(&chal2);
546 /* this generates the actual auth packet */
547 msrpc_gen(&blob, "CdBBUUUBd",
558 /* wrap it in SPNEGO */
559 auth = spnego_gen_auth(blob);
561 data_blob_free(&blob);
563 /* now send the auth packet and we should be done */
564 blob = cli_session_setup_blob(cli, auth);
566 data_blob_free(&auth);
567 data_blob_free(&blob);
569 if (cli_is_error(cli))
572 set_signing_on_cli(cli, pass, nthash);
577 /****************************************************************************
578 Do a spnego encrypted session setup.
579 ****************************************************************************/
581 static BOOL cli_session_setup_spnego(struct cli_state *cli, char *user,
582 char *pass, char *workgroup)
585 char *OIDs[ASN1_MAX_OIDS];
587 BOOL got_kerberos_mechanism = False;
590 DEBUG(2,("Doing spnego session setup (blob length=%d)\n", cli->secblob.length));
592 /* the server might not even do spnego */
593 if (cli->secblob.length <= 16) {
594 DEBUG(3,("server didn't supply a full spnego negprot\n"));
599 file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
602 /* there is 16 bytes of GUID before the real spnego packet starts */
603 blob = data_blob(cli->secblob.data+16, cli->secblob.length-16);
605 /* the server sent us the first part of the SPNEGO exchange in the negprot
607 if (!spnego_parse_negTokenInit(blob, OIDs, &principal)) {
608 data_blob_free(&blob);
611 data_blob_free(&blob);
613 /* make sure the server understands kerberos */
614 for (i=0;OIDs[i];i++) {
615 DEBUG(3,("got OID=%s\n", OIDs[i]));
616 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
617 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
618 got_kerberos_mechanism = True;
622 DEBUG(3,("got principal=%s\n", principal));
624 fstrcpy(cli->user_name, user);
627 if (got_kerberos_mechanism && cli->use_kerberos) {
628 return cli_session_setup_kerberos(cli, principal, workgroup);
636 return cli_session_setup_ntlmssp(cli, user, pass, workgroup);
639 /****************************************************************************
640 Send a session setup. The username and workgroup is in UNIX character
641 format and must be converted to DOS codepage format before sending. If the
642 password is in plaintext, the same should be done.
643 ****************************************************************************/
645 BOOL cli_session_setup(struct cli_state *cli,
647 char *pass, int passlen,
648 char *ntpass, int ntpasslen,
654 /* allow for workgroups as part of the username */
655 fstrcpy(user2, user);
656 if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/')) ||
657 (p=strchr_m(user2,*lp_winbind_separator()))) {
663 if (cli->protocol < PROTOCOL_LANMAN1)
666 /* now work out what sort of session setup we are going to
667 do. I have split this into separate functions to make the
668 flow a bit easier to understand (tridge) */
670 /* if its an older server then we have to use the older request format */
672 if (cli->protocol < PROTOCOL_NT1)
673 return cli_session_setup_lanman2(cli, user, pass, passlen, workgroup);
675 /* if no user is supplied then we have to do an anonymous connection.
676 passwords are ignored */
679 return cli_session_setup_guest(cli);
681 /* if the server is share level then send a plaintext null
682 password at this point. The password is sent in the tree
685 if ((cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) == 0)
686 return cli_session_setup_plaintext(cli, user, "", workgroup);
688 /* if the server doesn't support encryption then we have to use
689 plaintext. The second password is ignored */
691 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0)
692 return cli_session_setup_plaintext(cli, user, pass, workgroup);
694 /* Indidicate signing */
696 /* if the server supports extended security then use SPNEGO */
698 if (cli->capabilities & CAP_EXTENDED_SECURITY)
699 return cli_session_setup_spnego(cli, user, pass, workgroup);
701 /* otherwise do a NT1 style session setup */
703 return cli_session_setup_nt1(cli, user,
704 pass, passlen, ntpass, ntpasslen,
708 /****************************************************************************
710 *****************************************************************************/
712 BOOL cli_ulogoff(struct cli_state *cli)
714 memset(cli->outbuf,'\0',smb_size);
715 set_message(cli->outbuf,2,0,True);
716 SCVAL(cli->outbuf,smb_com,SMBulogoffX);
717 cli_setup_packet(cli);
718 SSVAL(cli->outbuf,smb_vwv0,0xFF);
719 SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
722 if (!cli_receive_smb(cli))
725 return !cli_is_error(cli);
728 /****************************************************************************
730 ****************************************************************************/
732 BOOL cli_send_tconX(struct cli_state *cli,
733 const char *share, const char *dev, const char *pass, int passlen)
735 fstring fullshare, pword;
737 memset(cli->outbuf,'\0',smb_size);
738 memset(cli->inbuf,'\0',smb_size);
740 fstrcpy(cli->share, share);
742 /* in user level security don't send a password now */
743 if (cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) {
748 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && *pass && passlen != 24) {
750 * Non-encrypted passwords - convert to DOS codepage before encryption.
753 SMBencrypt(pass,cli->secblob.data,(uchar *)pword);
755 if((cli->sec_mode & (NEGOTIATE_SECURITY_USER_LEVEL|NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)) == 0) {
757 * Non-encrypted passwords - convert to DOS codepage before using.
759 passlen = clistr_push(cli, pword, pass, -1, STR_TERMINATE);
761 memcpy(pword, pass, passlen);
765 if (cli->port == 445) {
766 slprintf(fullshare, sizeof(fullshare)-1,
769 slprintf(fullshare, sizeof(fullshare)-1,
770 "\\\\%s\\%s", cli->desthost, share);
773 set_message(cli->outbuf,4, 0, True);
774 SCVAL(cli->outbuf,smb_com,SMBtconX);
775 cli_setup_packet(cli);
777 SSVAL(cli->outbuf,smb_vwv0,0xFF);
778 SSVAL(cli->outbuf,smb_vwv3,passlen);
780 p = smb_buf(cli->outbuf);
781 memcpy(p,pword,passlen);
783 p += clistr_push(cli, p, fullshare, -1, STR_TERMINATE |STR_UPPER);
784 fstrcpy(p, dev); p += strlen(dev)+1;
786 cli_setup_bcc(cli, p);
789 if (!cli_receive_smb(cli))
792 if (cli_is_error(cli))
795 clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE|STR_ASCII);
797 if (strcasecmp(share,"IPC$")==0)
798 fstrcpy(cli->dev, "IPC");
800 if (cli->protocol >= PROTOCOL_NT1 &&
801 smb_buflen(cli->inbuf) == 3) {
802 /* almost certainly win95 - enable bug fixes */
806 cli->cnum = SVAL(cli->inbuf,smb_tid);
810 /****************************************************************************
811 Send a tree disconnect.
812 ****************************************************************************/
814 BOOL cli_tdis(struct cli_state *cli)
816 memset(cli->outbuf,'\0',smb_size);
817 set_message(cli->outbuf,0,0,True);
818 SCVAL(cli->outbuf,smb_com,SMBtdis);
819 SSVAL(cli->outbuf,smb_tid,cli->cnum);
820 cli_setup_packet(cli);
823 if (!cli_receive_smb(cli))
826 return !cli_is_error(cli);
829 /****************************************************************************
830 Send a negprot command.
831 ****************************************************************************/
833 void cli_negprot_send(struct cli_state *cli)
838 if (cli->protocol < PROTOCOL_NT1)
839 cli->use_spnego = False;
841 memset(cli->outbuf,'\0',smb_size);
843 /* setup the protocol strings */
844 set_message(cli->outbuf,0,0,True);
846 p = smb_buf(cli->outbuf);
848 prots[numprots].name && prots[numprots].prot<=cli->protocol;
851 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
854 SCVAL(cli->outbuf,smb_com,SMBnegprot);
855 cli_setup_bcc(cli, p);
856 cli_setup_packet(cli);
858 SCVAL(smb_buf(cli->outbuf),0,2);
863 /****************************************************************************
864 Send a negprot command.
865 ****************************************************************************/
867 BOOL cli_negprot(struct cli_state *cli)
873 if (cli->sign_info.use_smb_signing) {
874 DEBUG(0, ("Cannot send negprot again, particularly after setting up SMB Signing\n"));
878 if (cli->protocol < PROTOCOL_NT1)
879 cli->use_spnego = False;
881 memset(cli->outbuf,'\0',smb_size);
883 /* setup the protocol strings */
884 for (plength=0,numprots=0;
885 prots[numprots].name && prots[numprots].prot<=cli->protocol;
887 plength += strlen(prots[numprots].name)+2;
889 set_message(cli->outbuf,0,plength,True);
891 p = smb_buf(cli->outbuf);
893 prots[numprots].name && prots[numprots].prot<=cli->protocol;
896 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
899 SCVAL(cli->outbuf,smb_com,SMBnegprot);
900 cli_setup_packet(cli);
902 SCVAL(smb_buf(cli->outbuf),0,2);
905 if (!cli_receive_smb(cli))
908 show_msg(cli->inbuf);
910 if (cli_is_error(cli) ||
911 ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
915 cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
917 if (cli->protocol >= PROTOCOL_NT1) {
919 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
920 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
921 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
922 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
923 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1);
924 cli->serverzone *= 60;
925 /* this time arrives in real GMT */
926 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
927 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
928 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
929 if (cli->capabilities & CAP_RAW_MODE) {
930 cli->readbraw_supported = True;
931 cli->writebraw_supported = True;
933 /* work out if they sent us a workgroup */
934 if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
935 smb_buflen(cli->inbuf) > 8) {
936 clistr_pull(cli, cli->server_domain,
937 smb_buf(cli->inbuf)+8, sizeof(cli->server_domain),
938 smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
941 if ((cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED))
942 cli->sign_info.negotiated_smb_signing = True;
944 } else if (cli->protocol >= PROTOCOL_LANMAN1) {
945 cli->use_spnego = False;
946 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
947 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
948 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
949 cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
950 cli->serverzone *= 60;
951 /* this time is converted to GMT by make_unix_date */
952 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
953 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
954 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
955 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
957 /* the old core protocol */
958 cli->use_spnego = False;
960 cli->serverzone = TimeDiff(time(NULL));
963 cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
965 /* a way to force ascii SMB */
966 if (getenv("CLI_FORCE_ASCII"))
967 cli->capabilities &= ~CAP_UNICODE;
972 /****************************************************************************
973 Send a session request. See rfc1002.txt 4.3 and 4.3.2.
974 ****************************************************************************/
976 BOOL cli_session_request(struct cli_state *cli,
977 struct nmb_name *calling, struct nmb_name *called)
981 extern pstring user_socket_options;
983 memcpy(&(cli->calling), calling, sizeof(*calling));
984 memcpy(&(cli->called ), called , sizeof(*called ));
986 /* put in the destination name */
988 name_mangle(cli->called .name, p, cli->called .name_type);
993 name_mangle(cli->calling.name, p, cli->calling.name_type);
996 /* 445 doesn't have session request */
997 if (cli->port == 445)
1000 if (cli->sign_info.use_smb_signing) {
1001 DEBUG(0, ("Cannot send session resquest again, particularly after setting up SMB Signing\n"));
1005 /* send a session request (RFC 1002) */
1006 /* setup the packet length
1007 * Remove four bytes from the length count, since the length
1008 * field in the NBT Session Service header counts the number
1009 * of bytes which follow. The cli_send_smb() function knows
1010 * about this and accounts for those four bytes.
1014 _smb_setlen(cli->outbuf,len);
1015 SCVAL(cli->outbuf,0,0x81);
1018 DEBUG(5,("Sent session request\n"));
1020 if (!cli_receive_smb(cli))
1023 if (CVAL(cli->inbuf,0) == 0x84) {
1024 /* C. Hoch 9/14/95 Start */
1025 /* For information, here is the response structure.
1026 * We do the byte-twiddling to for portability.
1027 struct RetargetResponse{
1029 unsigned char flags;
1035 int port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
1036 /* SESSION RETARGET */
1037 putip((char *)&cli->dest_ip,cli->inbuf+4);
1039 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
1043 DEBUG(3,("Retargeted\n"));
1045 set_socket_options(cli->fd,user_socket_options);
1052 DEBUG(0,("Retarget recursion - failing\n"));
1056 ret = cli_session_request(cli, calling, called);
1060 } /* C. Hoch 9/14/95 End */
1062 if (CVAL(cli->inbuf,0) != 0x82) {
1063 /* This is the wrong place to put the error... JRA. */
1064 cli->rap_error = CVAL(cli->inbuf,4);
1070 /****************************************************************************
1071 Open the client sockets.
1072 ****************************************************************************/
1074 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
1076 extern pstring user_socket_options;
1077 int name_type = 0x20;
1080 /* reasonable default hostname */
1081 if (!host) host = "*SMBSERVER";
1083 fstrcpy(cli->desthost, host);
1085 /* allow hostnames of the form NAME#xx and do a netbios lookup */
1086 if ((p = strchr(cli->desthost, '#'))) {
1087 name_type = strtol(p+1, NULL, 16);
1091 if (!ip || is_zero_ip(*ip)) {
1092 if (!resolve_name(cli->desthost, &cli->dest_ip, name_type)) {
1095 if (ip) *ip = cli->dest_ip;
1100 if (getenv("LIBSMB_PROG")) {
1101 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
1103 /* try 445 first, then 139 */
1104 int port = cli->port?cli->port:445;
1105 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
1106 port, cli->timeout);
1107 if (cli->fd == -1 && cli->port == 0) {
1109 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
1110 port, cli->timeout);
1115 if (cli->fd == -1) {
1116 DEBUG(1,("Error connecting to %s (%s)\n",
1117 ip?inet_ntoa(*ip):host,strerror(errno)));
1121 set_socket_options(cli->fd,user_socket_options);
1126 /****************************************************************************
1127 Initialise client credentials for authenticated pipe access.
1128 ****************************************************************************/
1130 static void init_creds(struct ntuser_creds *creds, char* username,
1131 char* domain, char* password)
1133 ZERO_STRUCTP(creds);
1135 pwd_set_cleartext(&creds->pwd, password);
1137 fstrcpy(creds->user_name, username);
1138 fstrcpy(creds->domain, domain);
1141 creds->pwd.null_pwd = True;
1146 establishes a connection right up to doing tconX, password specified.
1147 @param output_cli A fully initialised cli structure, non-null only on success
1148 @param dest_host The netbios name of the remote host
1149 @param dest_ip (optional) The the destination IP, NULL for name based lookup
1150 @param port (optional) The destination port (0 for default)
1151 @param service (optional) The share to make the connection to. Should be 'unqualified' in any way.
1152 @param service_type The 'type' of serivice.
1153 @param user Username, unix string
1154 @param domain User's domain
1155 @param password User's password, unencrypted unix string.
1156 @param retry BOOL. Did this connection fail with a retryable error ?
1159 NTSTATUS cli_full_connection(struct cli_state **output_cli,
1160 const char *my_name,
1161 const char *dest_host,
1162 struct in_addr *dest_ip, int port,
1163 char *service, char *service_type,
1164 char *user, char *domain,
1165 char *password, int flags,
1168 struct ntuser_creds creds;
1170 struct nmb_name calling;
1171 struct nmb_name called;
1172 struct cli_state *cli;
1174 extern pstring global_myname;
1180 my_name = global_myname;
1182 if (!(cli = cli_initialise(NULL)))
1183 return NT_STATUS_NO_MEMORY;
1185 make_nmb_name(&calling, my_name, 0x0);
1186 make_nmb_name(&called , dest_host, 0x20);
1188 if (cli_set_port(cli, port) != port) {
1190 return NT_STATUS_UNSUCCESSFUL;
1193 cli_set_timeout(cli, 10000); /* 10 seconds. */
1202 DEBUG(3,("Connecting to host=%s share=%s\n", dest_host, service));
1204 if (!cli_connect(cli, dest_host, &ip)) {
1205 DEBUG(1,("cli_full_connection: failed to connect to %s (%s)\n",
1206 nmb_namestr(&called), inet_ntoa(ip)));
1208 return NT_STATUS_UNSUCCESSFUL;
1214 if (!cli_session_request(cli, &calling, &called)) {
1216 DEBUG(1,("session request to %s failed (%s)\n",
1217 called.name, cli_errstr(cli)));
1218 if ((p=strchr(called.name, '.')) && !is_ipaddress(called.name)) {
1222 if (strcmp(called.name, "*SMBSERVER")) {
1223 make_nmb_name(&called , "*SMBSERVER", 0x20);
1226 return NT_STATUS_UNSUCCESSFUL;
1229 if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO)
1230 cli->use_spnego = False;
1231 else if (flags & CLI_FULL_CONNECTION_USE_KERBEROS)
1232 cli->use_kerberos = True;
1234 if (!cli_negprot(cli)) {
1235 DEBUG(1,("failed negprot\n"));
1236 nt_status = NT_STATUS_UNSUCCESSFUL;
1241 if (!cli_session_setup(cli, user, password, strlen(password)+1,
1242 password, strlen(password)+1,
1244 if ((flags & CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK)
1245 && cli_session_setup(cli, "", "", 0, "", 0, domain)) {
1247 nt_status = cli_nt_error(cli);
1248 DEBUG(1,("failed session setup with %s\n", nt_errstr(nt_status)));
1250 if (NT_STATUS_IS_OK(nt_status))
1251 nt_status = NT_STATUS_UNSUCCESSFUL;
1257 if (!cli_send_tconX(cli, service, service_type,
1258 (char*)password, strlen(password)+1)) {
1259 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(nt_status)));
1260 nt_status = cli_nt_error(cli);
1262 if (NT_STATUS_IS_OK(nt_status)) {
1263 nt_status = NT_STATUS_UNSUCCESSFUL;
1269 init_creds(&creds, user, domain, password);
1270 cli_init_creds(cli, &creds);
1273 return NT_STATUS_OK;
1276 /****************************************************************************
1277 Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
1278 ****************************************************************************/
1280 BOOL attempt_netbios_session_request(struct cli_state *cli, char *srchost, char *desthost,
1281 struct in_addr *pdest_ip)
1283 struct nmb_name calling, called;
1285 make_nmb_name(&calling, srchost, 0x0);
1288 * If the called name is an IP address
1289 * then use *SMBSERVER immediately.
1292 if(is_ipaddress(desthost))
1293 make_nmb_name(&called, "*SMBSERVER", 0x20);
1295 make_nmb_name(&called, desthost, 0x20);
1297 if (!cli_session_request(cli, &calling, &called)) {
1298 struct nmb_name smbservername;
1300 make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
1303 * If the name wasn't *SMBSERVER then
1304 * try with *SMBSERVER if the first name fails.
1307 if (nmb_name_equal(&called, &smbservername)) {
1310 * The name used was *SMBSERVER, don't bother with another name.
1313 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
1314 with error %s.\n", desthost, cli_errstr(cli) ));
1319 * We need to close the connection here but can't call cli_shutdown as
1320 * will free an allocated cli struct. cli_close_connection was invented
1321 * for this purpose. JRA. Based on work by "Kim R. Pedersen" <krp@filanet.dk>.
1324 cli_close_connection(cli);
1326 if (!cli_initialise(cli) ||
1327 !cli_connect(cli, desthost, pdest_ip) ||
1328 !cli_session_request(cli, &calling, &smbservername)) {
1329 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
1330 name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) ));