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);
329 blob2 = data_blob(NULL, 0);
331 capabilities |= CAP_EXTENDED_SECURITY;
333 /* send a session setup command */
334 memset(cli->outbuf,'\0',smb_size);
336 set_message(cli->outbuf,12,0,True);
337 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
338 cli_setup_packet(cli);
340 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
341 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
342 SSVAL(cli->outbuf,smb_vwv3,2);
343 SSVAL(cli->outbuf,smb_vwv4,1);
344 SIVAL(cli->outbuf,smb_vwv5,0);
345 SSVAL(cli->outbuf,smb_vwv7,blob.length);
346 SIVAL(cli->outbuf,smb_vwv10,capabilities);
347 p = smb_buf(cli->outbuf);
348 memcpy(p, blob.data, blob.length);
350 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
351 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
352 cli_setup_bcc(cli, p);
355 if (!cli_receive_smb(cli))
358 show_msg(cli->inbuf);
360 if (cli_is_error(cli) && !NT_STATUS_EQUAL(cli_nt_error(cli),
361 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
365 /* use the returned vuid from now on */
366 cli->vuid = SVAL(cli->inbuf,smb_uid);
368 p = smb_buf(cli->inbuf);
370 blob2 = data_blob(p, SVAL(cli->inbuf, smb_vwv3));
373 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
374 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
375 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
382 /****************************************************************************
383 do a spnego/kerberos encrypted session setup
384 ****************************************************************************/
385 static BOOL cli_session_setup_kerberos(struct cli_state *cli, char *principal, char *workgroup)
387 DATA_BLOB blob2, negTokenTarg;
389 DEBUG(2,("Doing kerberos session setup\n"));
391 /* generate the encapsulated kerberos5 ticket */
392 negTokenTarg = spnego_gen_negTokenTarg(cli, principal);
394 if (!negTokenTarg.data) return False;
397 file_save("negTokenTarg.dat", negTokenTarg.data, negTokenTarg.length);
400 blob2 = cli_session_setup_blob(cli, negTokenTarg);
402 /* we don't need this blob for kerberos */
403 data_blob_free(&blob2);
405 data_blob_free(&negTokenTarg);
407 return !cli_is_error(cli);
411 /****************************************************************************
412 do a spnego/NTLMSSP encrypted session setup
413 ****************************************************************************/
414 static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, char *user,
415 char *pass, char *workgroup)
417 const char *mechs[] = {OID_NTLMSSP, NULL};
419 DATA_BLOB blob, chal1, chal2, auth;
421 uint8 nthash[24], lmhash[24], sess_key[16];
424 neg_flags = NTLMSSP_NEGOTIATE_UNICODE |
425 NTLMSSP_NEGOTIATE_LM_KEY |
426 NTLMSSP_NEGOTIATE_NTLM;
428 memset(sess_key, 0, 16);
430 /* generate the ntlmssp negotiate packet */
431 msrpc_gen(&blob, "CddB",
437 /* and wrap it in a SPNEGO wrapper */
438 msg1 = gen_negTokenTarg(mechs, blob);
439 data_blob_free(&blob);
441 /* now send that blob on its way */
442 blob = cli_session_setup_blob(cli, msg1);
444 data_blob_free(&msg1);
446 if (!NT_STATUS_EQUAL(cli_nt_error(cli), NT_STATUS_MORE_PROCESSING_REQUIRED)) {
451 file_save("chal.dat", blob.data, blob.length);
454 /* the server gives us back two challenges */
455 if (!spnego_parse_challenge(blob, &chal1, &chal2)) {
456 DEBUG(3,("Failed to parse challenges\n"));
460 data_blob_free(&blob);
462 /* encrypt the password with the challenge */
463 memcpy(challenge, chal1.data + 24, 8);
464 SMBencrypt((unsigned char *)pass, challenge,lmhash);
465 SMBNTencrypt((unsigned char *)pass, challenge,nthash);
468 file_save("nthash.dat", nthash, 24);
469 file_save("lmhash.dat", lmhash, 24);
470 file_save("chal1.dat", chal1.data, chal1.length);
473 data_blob_free(&chal1);
474 data_blob_free(&chal2);
476 /* this generates the actual auth packet */
477 msrpc_gen(&blob, "CdBBUUUBd",
488 /* wrap it in SPNEGO */
489 auth = spnego_gen_auth(blob);
491 data_blob_free(&blob);
493 /* now send the auth packet and we should be done */
494 blob = cli_session_setup_blob(cli, auth);
496 data_blob_free(&auth);
497 data_blob_free(&blob);
499 return !cli_is_error(cli);
503 /****************************************************************************
504 do a spnego encrypted session setup
505 ****************************************************************************/
506 static BOOL cli_session_setup_spnego(struct cli_state *cli, char *user,
507 char *pass, char *workgroup)
510 char *OIDs[ASN1_MAX_OIDS];
513 BOOL got_kerberos_mechanism = False;
515 DEBUG(2,("Doing spnego session setup (blob length=%d)\n", cli->secblob.length));
517 /* the server might not even do spnego */
518 if (cli->secblob.length == 16) {
519 DEBUG(3,("server didn't supply a full spnego negprot\n"));
524 file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
527 /* the server sent us the first part of the SPNEGO exchange in the negprot
529 if (!spnego_parse_negTokenInit(cli->secblob, guid, OIDs, &principal)) {
533 /* make sure the server understands kerberos */
534 for (i=0;OIDs[i];i++) {
535 DEBUG(3,("got OID=%s\n", OIDs[i]));
536 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
537 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
538 got_kerberos_mechanism = True;
542 DEBUG(3,("got principal=%s\n", principal));
544 fstrcpy(cli->user_name, user);
547 if (got_kerberos_mechanism && cli->use_kerberos) {
548 return cli_session_setup_kerberos(cli, principal, workgroup);
556 return cli_session_setup_ntlmssp(cli, user, pass, workgroup);
560 /****************************************************************************
561 Send a session setup. The username and workgroup is in UNIX character
562 format and must be converted to DOS codepage format before sending. If the
563 password is in plaintext, the same should be done.
564 ****************************************************************************/
565 BOOL cli_session_setup(struct cli_state *cli,
567 char *pass, int passlen,
568 char *ntpass, int ntpasslen,
574 /* allow for workgroups as part of the username */
575 fstrcpy(user2, user);
576 if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/'))) {
582 if (cli->protocol < PROTOCOL_LANMAN1)
585 /* now work out what sort of session setup we are going to
586 do. I have split this into separate functions to make the
587 flow a bit easier to understand (tridge) */
589 /* if its an older server then we have to use the older request format */
590 if (cli->protocol < PROTOCOL_NT1) {
591 return cli_session_setup_lanman2(cli, user, pass, passlen);
594 /* if no user is supplied then we have to do an anonymous connection.
595 passwords are ignored */
596 if (!user || !*user) {
597 return cli_session_setup_guest(cli);
600 /* if the server is share level then send a plaintext null
601 password at this point. The password is sent in the tree
603 if ((cli->sec_mode & 1) == 0) {
604 return cli_session_setup_plaintext(cli, user, "", workgroup);
607 /* if the server doesn't support encryption then we have to use plaintext. The
608 second password is ignored */
609 if ((cli->sec_mode & 2) == 0) {
610 return cli_session_setup_plaintext(cli, user, pass, workgroup);
613 /* if the server supports extended security then use SPNEGO */
614 if (cli->capabilities & CAP_EXTENDED_SECURITY) {
615 return cli_session_setup_spnego(cli, user, pass, workgroup);
618 /* otherwise do a NT1 style session setup */
619 return cli_session_setup_nt1(cli, user,
620 pass, passlen, ntpass, ntpasslen,
624 /****************************************************************************
626 *****************************************************************************/
628 BOOL cli_ulogoff(struct cli_state *cli)
630 memset(cli->outbuf,'\0',smb_size);
631 set_message(cli->outbuf,2,0,True);
632 CVAL(cli->outbuf,smb_com) = SMBulogoffX;
633 cli_setup_packet(cli);
634 SSVAL(cli->outbuf,smb_vwv0,0xFF);
635 SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
638 if (!cli_receive_smb(cli))
641 return !cli_is_error(cli);
644 /****************************************************************************
646 ****************************************************************************/
647 BOOL cli_send_tconX(struct cli_state *cli,
648 const char *share, const char *dev, const char *pass, int passlen)
650 fstring fullshare, pword, dos_pword;
652 memset(cli->outbuf,'\0',smb_size);
653 memset(cli->inbuf,'\0',smb_size);
655 fstrcpy(cli->share, share);
657 /* in user level security don't send a password now */
658 if (cli->sec_mode & 1) {
663 if ((cli->sec_mode & 2) && *pass && passlen != 24) {
665 * Non-encrypted passwords - convert to DOS codepage before encryption.
668 clistr_push(cli, dos_pword, pass, -1, STR_TERMINATE);
669 SMBencrypt((uchar *)dos_pword,cli->secblob.data,(uchar *)pword);
671 if((cli->sec_mode & 3) == 0) {
673 * Non-encrypted passwords - convert to DOS codepage before using.
675 passlen = clistr_push(cli, pword, pass, -1, STR_TERMINATE);
677 memcpy(pword, pass, passlen);
681 if (cli->port == 445) {
682 slprintf(fullshare, sizeof(fullshare)-1,
685 slprintf(fullshare, sizeof(fullshare)-1,
686 "\\\\%s\\%s", cli->desthost, share);
689 set_message(cli->outbuf,4, 0, True);
690 CVAL(cli->outbuf,smb_com) = SMBtconX;
691 cli_setup_packet(cli);
693 SSVAL(cli->outbuf,smb_vwv0,0xFF);
694 SSVAL(cli->outbuf,smb_vwv3,passlen);
696 p = smb_buf(cli->outbuf);
697 memcpy(p,pword,passlen);
699 p += clistr_push(cli, p, fullshare, -1, STR_TERMINATE |STR_UPPER);
700 fstrcpy(p, dev); p += strlen(dev)+1;
702 cli_setup_bcc(cli, p);
705 if (!cli_receive_smb(cli))
708 if (cli_is_error(cli)) {
712 clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE|STR_ASCII);
714 if (strcasecmp(share,"IPC$")==0) {
715 fstrcpy(cli->dev, "IPC");
718 if (cli->protocol >= PROTOCOL_NT1 &&
719 smb_buflen(cli->inbuf) == 3) {
720 /* almost certainly win95 - enable bug fixes */
724 cli->cnum = SVAL(cli->inbuf,smb_tid);
729 /****************************************************************************
730 send a tree disconnect
731 ****************************************************************************/
732 BOOL cli_tdis(struct cli_state *cli)
734 memset(cli->outbuf,'\0',smb_size);
735 set_message(cli->outbuf,0,0,True);
736 CVAL(cli->outbuf,smb_com) = SMBtdis;
737 SSVAL(cli->outbuf,smb_tid,cli->cnum);
738 cli_setup_packet(cli);
741 if (!cli_receive_smb(cli))
744 return !cli_is_error(cli);
748 /****************************************************************************
749 send a negprot command
750 ****************************************************************************/
751 void cli_negprot_send(struct cli_state *cli)
756 memset(cli->outbuf,'\0',smb_size);
758 /* setup the protocol strings */
759 set_message(cli->outbuf,0,0,True);
761 p = smb_buf(cli->outbuf);
763 prots[numprots].name && prots[numprots].prot<=cli->protocol;
766 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
769 CVAL(cli->outbuf,smb_com) = SMBnegprot;
770 cli_setup_bcc(cli, p);
771 cli_setup_packet(cli);
773 CVAL(smb_buf(cli->outbuf),0) = 2;
779 /****************************************************************************
780 send a negprot command
781 ****************************************************************************/
782 BOOL cli_negprot(struct cli_state *cli)
788 memset(cli->outbuf,'\0',smb_size);
790 /* setup the protocol strings */
791 for (plength=0,numprots=0;
792 prots[numprots].name && prots[numprots].prot<=cli->protocol;
794 plength += strlen(prots[numprots].name)+2;
796 set_message(cli->outbuf,0,plength,True);
798 p = smb_buf(cli->outbuf);
800 prots[numprots].name && prots[numprots].prot<=cli->protocol;
803 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
806 CVAL(cli->outbuf,smb_com) = SMBnegprot;
807 cli_setup_packet(cli);
809 CVAL(smb_buf(cli->outbuf),0) = 2;
812 if (!cli_receive_smb(cli))
815 show_msg(cli->inbuf);
817 if (cli_is_error(cli) ||
818 ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
822 cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
824 if (cli->protocol >= PROTOCOL_NT1) {
826 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
827 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
828 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
829 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
830 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1);
831 cli->serverzone *= 60;
832 /* this time arrives in real GMT */
833 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
834 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
835 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
836 if (cli->capabilities & CAP_RAW_MODE) {
837 cli->readbraw_supported = True;
838 cli->writebraw_supported = True;
840 /* work out if they sent us a workgroup */
841 if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
842 smb_buflen(cli->inbuf) > 8) {
843 clistr_pull(cli, cli->server_domain,
844 smb_buf(cli->inbuf)+8, sizeof(cli->server_domain),
845 smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
847 } else if (cli->protocol >= PROTOCOL_LANMAN1) {
848 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
849 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
850 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
851 cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
852 cli->serverzone *= 60;
853 /* this time is converted to GMT by make_unix_date */
854 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
855 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
856 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
857 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
859 /* the old core protocol */
861 cli->serverzone = TimeDiff(time(NULL));
864 cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
866 /* a way to force ascii SMB */
867 if (getenv("CLI_FORCE_ASCII")) {
868 cli->capabilities &= ~CAP_UNICODE;
875 /****************************************************************************
876 send a session request. see rfc1002.txt 4.3 and 4.3.2
877 ****************************************************************************/
878 BOOL cli_session_request(struct cli_state *cli,
879 struct nmb_name *calling, struct nmb_name *called)
883 extern pstring user_socket_options;
885 /* 445 doesn't have session request */
886 if (cli->port == 445) return True;
888 /* send a session request (RFC 1002) */
889 memcpy(&(cli->calling), calling, sizeof(*calling));
890 memcpy(&(cli->called ), called , sizeof(*called ));
892 /* put in the destination name */
894 name_mangle(cli->called .name, p, cli->called .name_type);
899 name_mangle(cli->calling.name, p, cli->calling.name_type);
902 /* setup the packet length */
903 _smb_setlen(cli->outbuf,len);
904 CVAL(cli->outbuf,0) = 0x81;
908 #endif /* WITH_SSL */
911 DEBUG(5,("Sent session request\n"));
913 if (!cli_receive_smb(cli))
916 if (CVAL(cli->inbuf,0) == 0x84) {
917 /* C. Hoch 9/14/95 Start */
918 /* For information, here is the response structure.
919 * We do the byte-twiddling to for portability.
920 struct RetargetResponse{
928 int port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
929 /* SESSION RETARGET */
930 putip((char *)&cli->dest_ip,cli->inbuf+4);
932 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
936 DEBUG(3,("Retargeted\n"));
938 set_socket_options(cli->fd,user_socket_options);
945 DEBUG(0,("Retarget recursion - failing\n"));
949 ret = cli_session_request(cli, calling, called);
953 } /* C. Hoch 9/14/95 End */
956 if (CVAL(cli->inbuf,0) == 0x83 && CVAL(cli->inbuf,4) == 0x8e){ /* use ssl */
957 if (!sslutil_fd_is_ssl(cli->fd)){
958 if (sslutil_connect(cli->fd) == 0)
962 #endif /* WITH_SSL */
964 if (CVAL(cli->inbuf,0) != 0x82) {
965 /* This is the wrong place to put the error... JRA. */
966 cli->rap_error = CVAL(cli->inbuf,4);
972 /****************************************************************************
973 open the client sockets
974 ****************************************************************************/
975 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
977 extern pstring user_socket_options;
979 fstrcpy(cli->desthost, host);
981 if (!ip || is_zero_ip(*ip)) {
982 if (!resolve_name( cli->desthost, &cli->dest_ip, 0x20)) {
985 if (ip) *ip = cli->dest_ip;
990 if (getenv("LIBSMB_PROG")) {
991 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
993 /* try 445 first, then 139 */
994 int port = cli->port?cli->port:445;
995 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
997 if (cli->fd == -1 && cli->port == 0) {
999 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
1000 port, cli->timeout);
1002 if (cli->fd != -1) cli->port = port;
1004 if (cli->fd == -1) {
1005 DEBUG(1,("Error connecting to %s (%s)\n",
1006 inet_ntoa(*ip),strerror(errno)));
1010 set_socket_options(cli->fd,user_socket_options);
1015 /****************************************************************************
1016 establishes a connection right up to doing tconX, password in cache.
1017 ****************************************************************************/
1018 BOOL cli_establish_connection(struct cli_state *cli,
1019 char *dest_host, struct in_addr *dest_ip,
1020 struct nmb_name *calling, struct nmb_name *called,
1021 char *service, char *service_type,
1022 BOOL do_shutdown, BOOL do_tcon)
1024 DEBUG(5,("cli_establish_connection: %s connecting to %s (%s) - %s [%s]\n",
1025 nmb_namestr(calling), nmb_namestr(called), inet_ntoa(*dest_ip),
1026 cli->user_name, cli->domain));
1028 /* establish connection */
1030 if ((!cli->initialised))
1035 /* cli_establish_connection() can't handle spnego yet. Once we get rid of
1036 pwd_cache and other horrors we can get rid of this */
1037 cli->use_spnego = False;
1041 if (!cli_connect(cli, dest_host, dest_ip))
1043 DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n",
1044 nmb_namestr(called), inet_ntoa(*dest_ip)));
1049 if (!cli_session_request(cli, calling, called))
1051 DEBUG(1,("failed session request\n"));
1057 if (!cli_negprot(cli))
1059 DEBUG(1,("failed negprot\n"));
1065 if (cli->pwd.cleartext || cli->pwd.null_pwd)
1070 if (cli->pwd.null_pwd)
1072 /* attempt null session */
1078 /* attempt clear-text session */
1079 pwd_get_cleartext(&(cli->pwd), passwd);
1080 pass_len = strlen(passwd);
1083 /* attempt clear-text session */
1084 if (!cli_session_setup(cli, cli->user_name,
1089 DEBUG(1,("failed session setup\n"));
1098 if (!cli_send_tconX(cli, service, service_type,
1099 (char*)passwd, strlen(passwd)))
1101 DEBUG(1,("failed tcon_X\n"));
1112 /* attempt encrypted session */
1113 unsigned char nt_sess_pwd[24];
1114 unsigned char lm_sess_pwd[24];
1116 /* creates (storing a copy of) and then obtains a 24 byte password OWF */
1117 pwd_make_lm_nt_owf(&(cli->pwd), cli->secblob.data);
1118 pwd_get_lm_nt_owf(&(cli->pwd), lm_sess_pwd, nt_sess_pwd);
1120 /* attempt encrypted session */
1121 if (!cli_session_setup(cli, cli->user_name,
1122 (char*)lm_sess_pwd, sizeof(lm_sess_pwd),
1123 (char*)nt_sess_pwd, sizeof(nt_sess_pwd),
1126 DEBUG(1,("failed session setup\n"));
1132 DEBUG(1,("session setup ok\n"));
1134 if (*cli->server_domain || *cli->server_os || *cli->server_type)
1136 DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",
1144 if (!cli_send_tconX(cli, service, service_type,
1145 (char*)nt_sess_pwd, sizeof(nt_sess_pwd)))
1147 DEBUG(1,("failed tcon_X\n"));
1161 /* Initialise client credentials for authenticated pipe access */
1163 static void init_creds(struct ntuser_creds *creds, char* username,
1164 char* domain, char* password, int pass_len)
1166 ZERO_STRUCTP(creds);
1168 pwd_set_cleartext(&creds->pwd, password);
1170 fstrcpy(creds->user_name, username);
1171 fstrcpy(creds->domain, domain);
1174 creds->pwd.null_pwd = True;
1178 /****************************************************************************
1179 establishes a connection right up to doing tconX, password specified.
1180 ****************************************************************************/
1181 NTSTATUS cli_full_connection(struct cli_state **output_cli,
1182 const char *my_name, const char *dest_host,
1183 struct in_addr *dest_ip, int port,
1184 char *service, char *service_type,
1185 char *user, char *domain,
1186 char *password, int pass_len)
1188 struct ntuser_creds creds;
1190 struct nmb_name calling;
1191 struct nmb_name called;
1192 struct cli_state *cli;
1195 make_nmb_name(&calling, my_name, 0x0);
1196 make_nmb_name(&called , dest_host, 0x20);
1200 if (!(cli = cli_initialise(NULL))) {
1201 return NT_STATUS_NO_MEMORY;
1204 if (cli_set_port(cli, port) != port) {
1205 return NT_STATUS_UNSUCCESSFUL;
1210 DEBUG(3,("Connecting to host=%s share=%s\n\n",
1211 dest_host, service));
1213 if (!cli_connect(cli, dest_host, &ip))
1215 DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n",
1216 nmb_namestr(&called), inet_ntoa(*dest_ip)));
1217 return NT_STATUS_UNSUCCESSFUL;
1220 if (!cli_session_request(cli, &calling, &called)) {
1222 DEBUG(1,("session request to %s failed (%s)\n",
1223 called.name, cli_errstr(cli)));
1225 if ((p=strchr(called.name, '.'))) {
1229 if (strcmp(called.name, "*SMBSERVER")) {
1230 make_nmb_name(&called , "*SMBSERVER", 0x20);
1233 return NT_STATUS_UNSUCCESSFUL;
1236 if (!cli_negprot(cli))
1238 DEBUG(1,("failed negprot\n"));
1239 nt_status = cli_nt_error(cli);
1244 if (!cli_session_setup(cli, user,
1249 DEBUG(1,("failed session setup\n"));
1250 nt_status = cli_nt_error(cli);
1257 if (!cli_send_tconX(cli, service, service_type,
1258 (char*)password, pass_len))
1260 DEBUG(1,("failed tcon_X\n"));
1261 nt_status = cli_nt_error(cli);
1267 init_creds(&creds, user, domain, password, pass_len);
1268 cli_init_creds(cli, &creds);
1271 return NT_STATUS_OK;
1274 /****************************************************************************
1275 Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
1276 ****************************************************************************/
1278 BOOL attempt_netbios_session_request(struct cli_state *cli, char *srchost, char *desthost,
1279 struct in_addr *pdest_ip)
1281 struct nmb_name calling, called;
1283 make_nmb_name(&calling, srchost, 0x0);
1286 * If the called name is an IP address
1287 * then use *SMBSERVER immediately.
1290 if(is_ipaddress(desthost))
1291 make_nmb_name(&called, "*SMBSERVER", 0x20);
1293 make_nmb_name(&called, desthost, 0x20);
1295 if (!cli_session_request(cli, &calling, &called)) {
1296 struct nmb_name smbservername;
1298 make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
1301 * If the name wasn't *SMBSERVER then
1302 * try with *SMBSERVER if the first name fails.
1305 if (nmb_name_equal(&called, &smbservername)) {
1308 * The name used was *SMBSERVER, don't bother with another name.
1311 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
1312 with error %s.\n", desthost, cli_errstr(cli) ));
1319 if (!cli_initialise(cli) ||
1320 !cli_connect(cli, desthost, pdest_ip) ||
1321 !cli_session_request(cli, &calling, &smbservername)) {
1322 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
1323 name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) ));