2 Unix SMB/Netbios implementation.
4 client connect/disconnect routines
5 Copyright (C) Andrew Tridgell 1994-1998
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.
33 {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"},
34 {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
35 {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
36 {PROTOCOL_LANMAN1,"LANMAN1.0"},
37 {PROTOCOL_LANMAN2,"LM1.2X002"},
38 {PROTOCOL_LANMAN2,"Samba"},
39 {PROTOCOL_NT1,"NT LANMAN 1.0"},
40 {PROTOCOL_NT1,"NT LM 0.12"},
45 /****************************************************************************
46 do an old lanman2 style session setup
47 ****************************************************************************/
48 static BOOL cli_session_setup_lanman2(struct cli_state *cli, char *user,
49 char *pass, int passlen)
54 if (passlen > sizeof(pword)-1) {
58 /* if in share level security then don't send a password now */
59 if (!(cli->sec_mode & 1)) {
63 if (passlen > 0 && (cli->sec_mode & 2) && passlen != 24) {
64 /* Encrypted mode needed, and non encrypted password supplied. */
66 clistr_push(cli, pword, pass, -1, STR_TERMINATE);
67 SMBencrypt((uchar *)pword,cli->secblob.data,(uchar *)pword);
68 } else if ((cli->sec_mode & 2) && passlen == 24) {
69 /* Encrypted mode needed, and encrypted password supplied. */
70 memcpy(pword, pass, passlen);
71 } else if (passlen > 0) {
72 /* Plaintext mode needed, assume plaintext supplied. */
73 passlen = clistr_push(cli, pword, pass, -1, STR_TERMINATE);
76 /* send a session setup command */
77 memset(cli->outbuf,'\0',smb_size);
78 set_message(cli->outbuf,10, 0, True);
79 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
80 cli_setup_packet(cli);
82 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
83 SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
84 SSVAL(cli->outbuf,smb_vwv3,2);
85 SSVAL(cli->outbuf,smb_vwv4,1);
86 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
87 SSVAL(cli->outbuf,smb_vwv7,passlen);
89 p = smb_buf(cli->outbuf);
90 memcpy(p,pword,passlen);
92 p += clistr_push(cli, p, user, -1, STR_TERMINATE);
93 cli_setup_bcc(cli, p);
96 if (!cli_receive_smb(cli))
101 if (cli_is_error(cli)) {
105 /* use the returned vuid from now on */
106 cli->vuid = SVAL(cli->inbuf,smb_uid);
107 fstrcpy(cli->user_name, user);
113 /****************************************************************************
114 work out suitable capabilities to offer the server
115 ****************************************************************************/
116 static uint32 cli_session_setup_capabilities(struct cli_state *cli)
118 uint32 capabilities = CAP_NT_SMBS;
120 if (!cli->force_dos_errors) {
121 capabilities |= CAP_STATUS32;
124 if (cli->use_level_II_oplocks) {
125 capabilities |= CAP_LEVEL_II_OPLOCKS;
128 if (cli->capabilities & CAP_UNICODE) {
129 capabilities |= CAP_UNICODE;
136 /****************************************************************************
137 do a NT1 guest session setup
138 ****************************************************************************/
139 static BOOL cli_session_setup_guest(struct cli_state *cli)
142 uint32 capabilities = cli_session_setup_capabilities(cli);
144 set_message(cli->outbuf,13,0,True);
145 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
146 cli_setup_packet(cli);
148 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
149 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
150 SSVAL(cli->outbuf,smb_vwv3,2);
151 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
152 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
153 SSVAL(cli->outbuf,smb_vwv7,0);
154 SSVAL(cli->outbuf,smb_vwv8,0);
155 SIVAL(cli->outbuf,smb_vwv11,capabilities);
156 p = smb_buf(cli->outbuf);
157 p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* username */
158 p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* workgroup */
159 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
160 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
161 cli_setup_bcc(cli, p);
164 if (!cli_receive_smb(cli))
167 show_msg(cli->inbuf);
169 if (cli_is_error(cli)) {
173 cli->vuid = SVAL(cli->inbuf,smb_uid);
175 p = smb_buf(cli->inbuf);
176 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
177 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
178 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
180 fstrcpy(cli->user_name, "");
186 /****************************************************************************
187 do a NT1 plaintext session setup
188 ****************************************************************************/
189 static BOOL cli_session_setup_plaintext(struct cli_state *cli, char *user,
190 char *pass, char *workgroup)
192 uint32 capabilities = cli_session_setup_capabilities(cli);
197 passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE|STR_ASCII);
199 set_message(cli->outbuf,13,0,True);
200 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
201 cli_setup_packet(cli);
203 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
204 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
205 SSVAL(cli->outbuf,smb_vwv3,2);
206 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
207 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
208 SSVAL(cli->outbuf,smb_vwv7,passlen);
209 SSVAL(cli->outbuf,smb_vwv8,0);
210 SIVAL(cli->outbuf,smb_vwv11,capabilities);
211 p = smb_buf(cli->outbuf);
212 memcpy(p, pword, passlen);
214 p += clistr_push(cli, p, user, -1, STR_TERMINATE); /* username */
215 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE); /* workgroup */
216 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
217 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
218 cli_setup_bcc(cli, p);
221 if (!cli_receive_smb(cli))
224 show_msg(cli->inbuf);
226 if (cli_is_error(cli)) {
230 cli->vuid = SVAL(cli->inbuf,smb_uid);
231 p = smb_buf(cli->inbuf);
232 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
233 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
234 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
235 fstrcpy(cli->user_name, user);
241 /****************************************************************************
242 do a NT1 NTLM/LM encrypted session setup
243 ****************************************************************************/
244 static BOOL cli_session_setup_nt1(struct cli_state *cli, char *user,
245 char *pass, int passlen,
246 char *ntpass, int ntpasslen,
249 uint32 capabilities = cli_session_setup_capabilities(cli);
250 fstring pword, ntpword;
253 if (passlen > sizeof(pword)-1 || ntpasslen > sizeof(ntpword)-1) {
258 /* non encrypted password supplied. Ignore ntpass. */
261 clistr_push(cli, pword,
262 pass?pass:"", sizeof(pword), STR_TERMINATE|STR_ASCII);
263 clistr_push(cli, ntpword,
264 pass?pass:"", sizeof(ntpword), STR_TERMINATE|STR_ASCII);
265 SMBencrypt((uchar *)pword,cli->secblob.data,(uchar *)pword);
266 SMBNTencrypt((uchar *)ntpword,cli->secblob.data,(uchar *)ntpword);
268 memcpy(pword, pass, passlen);
269 memcpy(ntpword, ntpass, ntpasslen);
272 /* send a session setup command */
273 memset(cli->outbuf,'\0',smb_size);
275 set_message(cli->outbuf,13,0,True);
276 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
277 cli_setup_packet(cli);
279 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
280 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
281 SSVAL(cli->outbuf,smb_vwv3,2);
282 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
283 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
284 SSVAL(cli->outbuf,smb_vwv7,passlen);
285 SSVAL(cli->outbuf,smb_vwv8,ntpasslen);
286 SIVAL(cli->outbuf,smb_vwv11,capabilities);
287 p = smb_buf(cli->outbuf);
288 memcpy(p,pword,passlen); p += passlen;
289 memcpy(p,ntpword,ntpasslen); p += ntpasslen;
290 p += clistr_push(cli, p, user, -1, STR_TERMINATE|STR_UPPER);
291 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
292 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
293 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
294 cli_setup_bcc(cli, p);
297 if (!cli_receive_smb(cli))
300 show_msg(cli->inbuf);
302 if (cli_is_error(cli)) {
306 /* use the returned vuid from now on */
307 cli->vuid = SVAL(cli->inbuf,smb_uid);
309 p = smb_buf(cli->inbuf);
310 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
311 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
312 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
314 fstrcpy(cli->user_name, user);
320 /****************************************************************************
321 send a extended security session setup blob, returning a reply blob
322 ****************************************************************************/
323 static DATA_BLOB cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob)
325 uint32 capabilities = cli_session_setup_capabilities(cli);
330 blob2 = data_blob(NULL, 0);
332 capabilities |= CAP_EXTENDED_SECURITY;
334 /* send a session setup command */
335 memset(cli->outbuf,'\0',smb_size);
337 set_message(cli->outbuf,12,0,True);
338 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
339 cli_setup_packet(cli);
341 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
342 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
343 SSVAL(cli->outbuf,smb_vwv3,2);
344 SSVAL(cli->outbuf,smb_vwv4,1);
345 SIVAL(cli->outbuf,smb_vwv5,0);
346 SSVAL(cli->outbuf,smb_vwv7,blob.length);
347 SIVAL(cli->outbuf,smb_vwv10,capabilities);
348 p = smb_buf(cli->outbuf);
349 memcpy(p, blob.data, blob.length);
351 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
352 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
353 cli_setup_bcc(cli, p);
356 if (!cli_receive_smb(cli))
359 show_msg(cli->inbuf);
361 if (cli_is_error(cli) && !NT_STATUS_EQUAL(cli_nt_error(cli),
362 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
366 /* use the returned vuid from now on */
367 cli->vuid = SVAL(cli->inbuf,smb_uid);
369 p = smb_buf(cli->inbuf);
371 blob2 = data_blob(p, SVAL(cli->inbuf, smb_vwv3));
374 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
376 /* w2k with kerberos doesn't properly null terminate this field */
377 len = smb_buflen(cli->inbuf) - PTR_DIFF(p, smb_buf(cli->inbuf));
378 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), len, 0);
385 /****************************************************************************
386 do a spnego/kerberos encrypted session setup
387 ****************************************************************************/
388 static BOOL cli_session_setup_kerberos(struct cli_state *cli, char *principal, char *workgroup)
390 DATA_BLOB blob2, negTokenTarg;
392 DEBUG(2,("Doing kerberos session setup\n"));
394 /* generate the encapsulated kerberos5 ticket */
395 negTokenTarg = spnego_gen_negTokenTarg(cli, principal);
397 if (!negTokenTarg.data) return False;
400 file_save("negTokenTarg.dat", negTokenTarg.data, negTokenTarg.length);
403 blob2 = cli_session_setup_blob(cli, negTokenTarg);
405 /* we don't need this blob for kerberos */
406 data_blob_free(&blob2);
408 data_blob_free(&negTokenTarg);
410 return !cli_is_error(cli);
414 /****************************************************************************
415 do a spnego/NTLMSSP encrypted session setup
416 ****************************************************************************/
417 static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, char *user,
418 char *pass, char *workgroup)
420 const char *mechs[] = {OID_NTLMSSP, NULL};
422 DATA_BLOB blob, chal1, chal2, auth;
424 uint8 nthash[24], lmhash[24], sess_key[16];
427 neg_flags = NTLMSSP_NEGOTIATE_UNICODE |
428 NTLMSSP_NEGOTIATE_LM_KEY |
429 NTLMSSP_NEGOTIATE_NTLM;
431 memset(sess_key, 0, 16);
433 /* generate the ntlmssp negotiate packet */
434 msrpc_gen(&blob, "CddB",
440 /* and wrap it in a SPNEGO wrapper */
441 msg1 = gen_negTokenTarg(mechs, blob);
442 data_blob_free(&blob);
444 /* now send that blob on its way */
445 blob = cli_session_setup_blob(cli, msg1);
447 data_blob_free(&msg1);
449 if (!NT_STATUS_EQUAL(cli_nt_error(cli), NT_STATUS_MORE_PROCESSING_REQUIRED)) {
454 file_save("chal.dat", blob.data, blob.length);
457 /* the server gives us back two challenges */
458 if (!spnego_parse_challenge(blob, &chal1, &chal2)) {
459 DEBUG(3,("Failed to parse challenges\n"));
463 data_blob_free(&blob);
465 /* encrypt the password with the challenge */
466 memcpy(challenge, chal1.data + 24, 8);
467 SMBencrypt((unsigned char *)pass, challenge,lmhash);
468 SMBNTencrypt((unsigned char *)pass, challenge,nthash);
471 file_save("nthash.dat", nthash, 24);
472 file_save("lmhash.dat", lmhash, 24);
473 file_save("chal1.dat", chal1.data, chal1.length);
476 data_blob_free(&chal1);
477 data_blob_free(&chal2);
479 /* this generates the actual auth packet */
480 msrpc_gen(&blob, "CdBBUUUBd",
491 /* wrap it in SPNEGO */
492 auth = spnego_gen_auth(blob);
494 data_blob_free(&blob);
496 /* now send the auth packet and we should be done */
497 blob = cli_session_setup_blob(cli, auth);
499 data_blob_free(&auth);
500 data_blob_free(&blob);
502 return !cli_is_error(cli);
506 /****************************************************************************
507 do a spnego encrypted session setup
508 ****************************************************************************/
509 static BOOL cli_session_setup_spnego(struct cli_state *cli, char *user,
510 char *pass, char *workgroup)
513 char *OIDs[ASN1_MAX_OIDS];
516 BOOL got_kerberos_mechanism = False;
518 DEBUG(2,("Doing spnego session setup (blob length=%d)\n", cli->secblob.length));
520 /* the server might not even do spnego */
521 if (cli->secblob.length == 16) {
522 DEBUG(3,("server didn't supply a full spnego negprot\n"));
527 file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
530 /* the server sent us the first part of the SPNEGO exchange in the negprot
532 if (!spnego_parse_negTokenInit(cli->secblob, guid, OIDs, &principal)) {
536 /* make sure the server understands kerberos */
537 for (i=0;OIDs[i];i++) {
538 DEBUG(3,("got OID=%s\n", OIDs[i]));
539 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
540 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
541 got_kerberos_mechanism = True;
545 DEBUG(3,("got principal=%s\n", principal));
547 fstrcpy(cli->user_name, user);
550 if (got_kerberos_mechanism && cli->use_kerberos) {
551 return cli_session_setup_kerberos(cli, principal, workgroup);
559 return cli_session_setup_ntlmssp(cli, user, pass, workgroup);
563 /****************************************************************************
564 Send a session setup. The username and workgroup is in UNIX character
565 format and must be converted to DOS codepage format before sending. If the
566 password is in plaintext, the same should be done.
567 ****************************************************************************/
568 BOOL cli_session_setup(struct cli_state *cli,
570 char *pass, int passlen,
571 char *ntpass, int ntpasslen,
577 /* allow for workgroups as part of the username */
578 fstrcpy(user2, user);
579 if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/'))) {
585 if (cli->protocol < PROTOCOL_LANMAN1)
588 /* now work out what sort of session setup we are going to
589 do. I have split this into separate functions to make the
590 flow a bit easier to understand (tridge) */
592 /* if its an older server then we have to use the older request format */
593 if (cli->protocol < PROTOCOL_NT1) {
594 return cli_session_setup_lanman2(cli, user, pass, passlen);
597 /* if no user is supplied then we have to do an anonymous connection.
598 passwords are ignored */
599 if (!user || !*user) {
600 return cli_session_setup_guest(cli);
603 /* if the server is share level then send a plaintext null
604 password at this point. The password is sent in the tree
606 if ((cli->sec_mode & 1) == 0) {
607 return cli_session_setup_plaintext(cli, user, "", workgroup);
610 /* if the server doesn't support encryption then we have to use plaintext. The
611 second password is ignored */
612 if ((cli->sec_mode & 2) == 0) {
613 return cli_session_setup_plaintext(cli, user, pass, workgroup);
616 /* if the server supports extended security then use SPNEGO */
617 if (cli->capabilities & CAP_EXTENDED_SECURITY) {
618 return cli_session_setup_spnego(cli, user, pass, workgroup);
621 /* otherwise do a NT1 style session setup */
622 return cli_session_setup_nt1(cli, user,
623 pass, passlen, ntpass, ntpasslen,
627 /****************************************************************************
629 *****************************************************************************/
631 BOOL cli_ulogoff(struct cli_state *cli)
633 memset(cli->outbuf,'\0',smb_size);
634 set_message(cli->outbuf,2,0,True);
635 CVAL(cli->outbuf,smb_com) = SMBulogoffX;
636 cli_setup_packet(cli);
637 SSVAL(cli->outbuf,smb_vwv0,0xFF);
638 SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
641 if (!cli_receive_smb(cli))
644 return !cli_is_error(cli);
647 /****************************************************************************
649 ****************************************************************************/
650 BOOL cli_send_tconX(struct cli_state *cli,
651 const char *share, const char *dev, const char *pass, int passlen)
653 fstring fullshare, pword, dos_pword;
655 memset(cli->outbuf,'\0',smb_size);
656 memset(cli->inbuf,'\0',smb_size);
658 fstrcpy(cli->share, share);
660 /* in user level security don't send a password now */
661 if (cli->sec_mode & 1) {
666 if ((cli->sec_mode & 2) && *pass && passlen != 24) {
668 * Non-encrypted passwords - convert to DOS codepage before encryption.
671 clistr_push(cli, dos_pword, pass, -1, STR_TERMINATE);
672 SMBencrypt((uchar *)dos_pword,cli->secblob.data,(uchar *)pword);
674 if((cli->sec_mode & 3) == 0) {
676 * Non-encrypted passwords - convert to DOS codepage before using.
678 passlen = clistr_push(cli, pword, pass, -1, STR_TERMINATE);
680 memcpy(pword, pass, passlen);
684 if (cli->port == 445) {
685 slprintf(fullshare, sizeof(fullshare)-1,
688 slprintf(fullshare, sizeof(fullshare)-1,
689 "\\\\%s\\%s", cli->desthost, share);
692 set_message(cli->outbuf,4, 0, True);
693 CVAL(cli->outbuf,smb_com) = SMBtconX;
694 cli_setup_packet(cli);
696 SSVAL(cli->outbuf,smb_vwv0,0xFF);
697 SSVAL(cli->outbuf,smb_vwv3,passlen);
699 p = smb_buf(cli->outbuf);
700 memcpy(p,pword,passlen);
702 p += clistr_push(cli, p, fullshare, -1, STR_TERMINATE |STR_UPPER);
703 fstrcpy(p, dev); p += strlen(dev)+1;
705 cli_setup_bcc(cli, p);
708 if (!cli_receive_smb(cli))
711 if (cli_is_error(cli)) {
715 clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE|STR_ASCII);
717 if (strcasecmp(share,"IPC$")==0) {
718 fstrcpy(cli->dev, "IPC");
721 if (cli->protocol >= PROTOCOL_NT1 &&
722 smb_buflen(cli->inbuf) == 3) {
723 /* almost certainly win95 - enable bug fixes */
727 cli->cnum = SVAL(cli->inbuf,smb_tid);
732 /****************************************************************************
733 send a tree disconnect
734 ****************************************************************************/
735 BOOL cli_tdis(struct cli_state *cli)
737 memset(cli->outbuf,'\0',smb_size);
738 set_message(cli->outbuf,0,0,True);
739 CVAL(cli->outbuf,smb_com) = SMBtdis;
740 SSVAL(cli->outbuf,smb_tid,cli->cnum);
741 cli_setup_packet(cli);
744 if (!cli_receive_smb(cli))
747 return !cli_is_error(cli);
751 /****************************************************************************
752 send a negprot command
753 ****************************************************************************/
754 void cli_negprot_send(struct cli_state *cli)
759 memset(cli->outbuf,'\0',smb_size);
761 /* setup the protocol strings */
762 set_message(cli->outbuf,0,0,True);
764 p = smb_buf(cli->outbuf);
766 prots[numprots].name && prots[numprots].prot<=cli->protocol;
769 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
772 CVAL(cli->outbuf,smb_com) = SMBnegprot;
773 cli_setup_bcc(cli, p);
774 cli_setup_packet(cli);
776 CVAL(smb_buf(cli->outbuf),0) = 2;
782 /****************************************************************************
783 send a negprot command
784 ****************************************************************************/
785 BOOL cli_negprot(struct cli_state *cli)
791 memset(cli->outbuf,'\0',smb_size);
793 /* setup the protocol strings */
794 for (plength=0,numprots=0;
795 prots[numprots].name && prots[numprots].prot<=cli->protocol;
797 plength += strlen(prots[numprots].name)+2;
799 set_message(cli->outbuf,0,plength,True);
801 p = smb_buf(cli->outbuf);
803 prots[numprots].name && prots[numprots].prot<=cli->protocol;
806 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
809 CVAL(cli->outbuf,smb_com) = SMBnegprot;
810 cli_setup_packet(cli);
812 CVAL(smb_buf(cli->outbuf),0) = 2;
815 if (!cli_receive_smb(cli))
818 show_msg(cli->inbuf);
820 if (cli_is_error(cli) ||
821 ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
825 cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
827 if (cli->protocol >= PROTOCOL_NT1) {
829 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
830 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
831 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
832 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
833 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1);
834 cli->serverzone *= 60;
835 /* this time arrives in real GMT */
836 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
837 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
838 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
839 if (cli->capabilities & CAP_RAW_MODE) {
840 cli->readbraw_supported = True;
841 cli->writebraw_supported = True;
843 /* work out if they sent us a workgroup */
844 if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
845 smb_buflen(cli->inbuf) > 8) {
846 clistr_pull(cli, cli->server_domain,
847 smb_buf(cli->inbuf)+8, sizeof(cli->server_domain),
848 smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
850 } else if (cli->protocol >= PROTOCOL_LANMAN1) {
851 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
852 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
853 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
854 cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
855 cli->serverzone *= 60;
856 /* this time is converted to GMT by make_unix_date */
857 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
858 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
859 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
860 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
862 /* the old core protocol */
864 cli->serverzone = TimeDiff(time(NULL));
867 cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
869 /* a way to force ascii SMB */
870 if (getenv("CLI_FORCE_ASCII")) {
871 cli->capabilities &= ~CAP_UNICODE;
878 /****************************************************************************
879 send a session request. see rfc1002.txt 4.3 and 4.3.2
880 ****************************************************************************/
881 BOOL cli_session_request(struct cli_state *cli,
882 struct nmb_name *calling, struct nmb_name *called)
886 extern pstring user_socket_options;
888 /* 445 doesn't have session request */
889 if (cli->port == 445) return True;
891 /* send a session request (RFC 1002) */
892 memcpy(&(cli->calling), calling, sizeof(*calling));
893 memcpy(&(cli->called ), called , sizeof(*called ));
895 /* put in the destination name */
897 name_mangle(cli->called .name, p, cli->called .name_type);
902 name_mangle(cli->calling.name, p, cli->calling.name_type);
905 /* setup the packet length */
906 _smb_setlen(cli->outbuf,len);
907 CVAL(cli->outbuf,0) = 0x81;
911 #endif /* WITH_SSL */
914 DEBUG(5,("Sent session request\n"));
916 if (!cli_receive_smb(cli))
919 if (CVAL(cli->inbuf,0) == 0x84) {
920 /* C. Hoch 9/14/95 Start */
921 /* For information, here is the response structure.
922 * We do the byte-twiddling to for portability.
923 struct RetargetResponse{
931 int port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
932 /* SESSION RETARGET */
933 putip((char *)&cli->dest_ip,cli->inbuf+4);
935 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
939 DEBUG(3,("Retargeted\n"));
941 set_socket_options(cli->fd,user_socket_options);
948 DEBUG(0,("Retarget recursion - failing\n"));
952 ret = cli_session_request(cli, calling, called);
956 } /* C. Hoch 9/14/95 End */
959 if (CVAL(cli->inbuf,0) == 0x83 && CVAL(cli->inbuf,4) == 0x8e){ /* use ssl */
960 if (!sslutil_fd_is_ssl(cli->fd)){
961 if (sslutil_connect(cli->fd) == 0)
965 #endif /* WITH_SSL */
967 if (CVAL(cli->inbuf,0) != 0x82) {
968 /* This is the wrong place to put the error... JRA. */
969 cli->rap_error = CVAL(cli->inbuf,4);
975 /****************************************************************************
976 open the client sockets
977 ****************************************************************************/
978 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
980 extern pstring user_socket_options;
981 int name_type = 0x20;
984 /* reasonable default hostname */
985 if (!host) host = "*SMBSERVER";
987 fstrcpy(cli->desthost, host);
989 /* allow hostnames of the form NAME#xx and do a netbios lookup */
990 if ((p = strchr(cli->desthost, '#'))) {
991 name_type = strtol(p+1, NULL, 16);
995 if (!ip || is_zero_ip(*ip)) {
996 if (!resolve_name(cli->desthost, &cli->dest_ip, name_type)) {
999 if (ip) *ip = cli->dest_ip;
1004 if (getenv("LIBSMB_PROG")) {
1005 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
1007 /* try 445 first, then 139 */
1008 int port = cli->port?cli->port:445;
1009 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
1010 port, cli->timeout);
1011 if (cli->fd == -1 && cli->port == 0) {
1013 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
1014 port, cli->timeout);
1016 if (cli->fd != -1) cli->port = port;
1018 if (cli->fd == -1) {
1019 DEBUG(1,("Error connecting to %s (%s)\n",
1020 inet_ntoa(*ip),strerror(errno)));
1024 set_socket_options(cli->fd,user_socket_options);
1029 /****************************************************************************
1030 establishes a connection right up to doing tconX, password in cache.
1031 ****************************************************************************/
1032 BOOL cli_establish_connection(struct cli_state *cli,
1033 char *dest_host, struct in_addr *dest_ip,
1034 struct nmb_name *calling, struct nmb_name *called,
1035 char *service, char *service_type,
1036 BOOL do_shutdown, BOOL do_tcon)
1038 DEBUG(5,("cli_establish_connection: %s connecting to %s (%s) - %s [%s]\n",
1039 nmb_namestr(calling), nmb_namestr(called), inet_ntoa(*dest_ip),
1040 cli->user_name, cli->domain));
1042 /* establish connection */
1044 if ((!cli->initialised))
1049 /* cli_establish_connection() can't handle spnego yet. Once we get rid of
1050 pwd_cache and other horrors we can get rid of this */
1051 cli->use_spnego = False;
1055 if (!cli_connect(cli, dest_host, dest_ip))
1057 DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n",
1058 nmb_namestr(called), inet_ntoa(*dest_ip)));
1063 if (!cli_session_request(cli, calling, called))
1065 DEBUG(1,("failed session request\n"));
1071 if (!cli_negprot(cli))
1073 DEBUG(1,("failed negprot\n"));
1079 if (cli->pwd.cleartext || cli->pwd.null_pwd)
1084 if (cli->pwd.null_pwd)
1086 /* attempt null session */
1092 /* attempt clear-text session */
1093 pwd_get_cleartext(&(cli->pwd), passwd);
1094 pass_len = strlen(passwd);
1097 /* attempt clear-text session */
1098 if (!cli_session_setup(cli, cli->user_name,
1103 DEBUG(1,("failed session setup\n"));
1112 if (!cli_send_tconX(cli, service, service_type,
1113 (char*)passwd, strlen(passwd)))
1115 DEBUG(1,("failed tcon_X\n"));
1126 /* attempt encrypted session */
1127 unsigned char nt_sess_pwd[24];
1128 unsigned char lm_sess_pwd[24];
1130 /* creates (storing a copy of) and then obtains a 24 byte password OWF */
1131 pwd_make_lm_nt_owf(&(cli->pwd), cli->secblob.data);
1132 pwd_get_lm_nt_owf(&(cli->pwd), lm_sess_pwd, nt_sess_pwd);
1134 /* attempt encrypted session */
1135 if (!cli_session_setup(cli, cli->user_name,
1136 (char*)lm_sess_pwd, sizeof(lm_sess_pwd),
1137 (char*)nt_sess_pwd, sizeof(nt_sess_pwd),
1140 DEBUG(1,("failed session setup\n"));
1146 DEBUG(1,("session setup ok\n"));
1148 if (*cli->server_domain || *cli->server_os || *cli->server_type)
1150 DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",
1158 if (!cli_send_tconX(cli, service, service_type,
1159 (char*)nt_sess_pwd, sizeof(nt_sess_pwd)))
1161 DEBUG(1,("failed tcon_X\n"));
1175 /* Initialise client credentials for authenticated pipe access */
1177 static void init_creds(struct ntuser_creds *creds, char* username,
1178 char* domain, char* password, int pass_len)
1180 ZERO_STRUCTP(creds);
1182 pwd_set_cleartext(&creds->pwd, password);
1184 fstrcpy(creds->user_name, username);
1185 fstrcpy(creds->domain, domain);
1188 creds->pwd.null_pwd = True;
1192 /****************************************************************************
1193 establishes a connection right up to doing tconX, password specified.
1194 ****************************************************************************/
1195 NTSTATUS cli_full_connection(struct cli_state **output_cli,
1196 const char *my_name, const char *dest_host,
1197 struct in_addr *dest_ip, int port,
1198 char *service, char *service_type,
1199 char *user, char *domain,
1200 char *password, int pass_len)
1202 struct ntuser_creds creds;
1204 struct nmb_name calling;
1205 struct nmb_name called;
1206 struct cli_state *cli;
1210 DEBUG(0, ("output_cli is NULL!?!"));
1215 make_nmb_name(&calling, my_name, 0x0);
1216 make_nmb_name(&called , dest_host, 0x20);
1220 if (!(cli = cli_initialise(NULL))) {
1221 return NT_STATUS_NO_MEMORY;
1224 if (cli_set_port(cli, port) != port) {
1225 return NT_STATUS_UNSUCCESSFUL;
1230 DEBUG(3,("Connecting to host=%s share=%s\n\n",
1231 dest_host, service));
1233 if (!cli_connect(cli, dest_host, &ip))
1235 DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n",
1236 nmb_namestr(&called), inet_ntoa(*dest_ip)));
1237 return NT_STATUS_UNSUCCESSFUL;
1240 if (!cli_session_request(cli, &calling, &called)) {
1242 DEBUG(1,("session request to %s failed (%s)\n",
1243 called.name, cli_errstr(cli)));
1245 if ((p=strchr(called.name, '.'))) {
1249 if (strcmp(called.name, "*SMBSERVER")) {
1250 make_nmb_name(&called , "*SMBSERVER", 0x20);
1253 return NT_STATUS_UNSUCCESSFUL;
1256 if (!cli_negprot(cli))
1258 DEBUG(1,("failed negprot\n"));
1259 nt_status = cli_nt_error(cli);
1264 if (!cli_session_setup(cli, user,
1269 DEBUG(1,("failed session setup\n"));
1270 nt_status = cli_nt_error(cli);
1277 if (!cli_send_tconX(cli, service, service_type,
1278 (char*)password, pass_len))
1280 DEBUG(1,("failed tcon_X\n"));
1281 nt_status = cli_nt_error(cli);
1287 init_creds(&creds, user, domain, password, pass_len);
1288 cli_init_creds(cli, &creds);
1291 return NT_STATUS_OK;
1294 /****************************************************************************
1295 Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
1296 ****************************************************************************/
1298 BOOL attempt_netbios_session_request(struct cli_state *cli, char *srchost, char *desthost,
1299 struct in_addr *pdest_ip)
1301 struct nmb_name calling, called;
1303 make_nmb_name(&calling, srchost, 0x0);
1306 * If the called name is an IP address
1307 * then use *SMBSERVER immediately.
1310 if(is_ipaddress(desthost))
1311 make_nmb_name(&called, "*SMBSERVER", 0x20);
1313 make_nmb_name(&called, desthost, 0x20);
1315 if (!cli_session_request(cli, &calling, &called)) {
1316 struct nmb_name smbservername;
1318 make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
1321 * If the name wasn't *SMBSERVER then
1322 * try with *SMBSERVER if the first name fails.
1325 if (nmb_name_equal(&called, &smbservername)) {
1328 * The name used was *SMBSERVER, don't bother with another name.
1331 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
1332 with error %s.\n", desthost, cli_errstr(cli) ));
1339 if (!cli_initialise(cli) ||
1340 !cli_connect(cli, desthost, pdest_ip) ||
1341 !cli_session_request(cli, &calling, &smbservername)) {
1342 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
1343 name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) ));