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,'/')) ||
580 (p=strchr_m(user2,*lp_winbind_separator()))) {
586 if (cli->protocol < PROTOCOL_LANMAN1)
589 /* now work out what sort of session setup we are going to
590 do. I have split this into separate functions to make the
591 flow a bit easier to understand (tridge) */
593 /* if its an older server then we have to use the older request format */
594 if (cli->protocol < PROTOCOL_NT1) {
595 return cli_session_setup_lanman2(cli, user, pass, passlen);
598 /* if no user is supplied then we have to do an anonymous connection.
599 passwords are ignored */
600 if (!user || !*user) {
601 return cli_session_setup_guest(cli);
604 /* if the server is share level then send a plaintext null
605 password at this point. The password is sent in the tree
607 if ((cli->sec_mode & 1) == 0) {
608 return cli_session_setup_plaintext(cli, user, "", workgroup);
611 /* if the server doesn't support encryption then we have to use plaintext. The
612 second password is ignored */
613 if ((cli->sec_mode & 2) == 0) {
614 return cli_session_setup_plaintext(cli, user, pass, workgroup);
617 /* if the server supports extended security then use SPNEGO */
618 if (cli->capabilities & CAP_EXTENDED_SECURITY) {
619 return cli_session_setup_spnego(cli, user, pass, workgroup);
622 /* otherwise do a NT1 style session setup */
623 return cli_session_setup_nt1(cli, user,
624 pass, passlen, ntpass, ntpasslen,
628 /****************************************************************************
630 *****************************************************************************/
632 BOOL cli_ulogoff(struct cli_state *cli)
634 memset(cli->outbuf,'\0',smb_size);
635 set_message(cli->outbuf,2,0,True);
636 CVAL(cli->outbuf,smb_com) = SMBulogoffX;
637 cli_setup_packet(cli);
638 SSVAL(cli->outbuf,smb_vwv0,0xFF);
639 SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
642 if (!cli_receive_smb(cli))
645 return !cli_is_error(cli);
648 /****************************************************************************
650 ****************************************************************************/
651 BOOL cli_send_tconX(struct cli_state *cli,
652 const char *share, const char *dev, const char *pass, int passlen)
654 fstring fullshare, pword, dos_pword;
656 memset(cli->outbuf,'\0',smb_size);
657 memset(cli->inbuf,'\0',smb_size);
659 fstrcpy(cli->share, share);
661 /* in user level security don't send a password now */
662 if (cli->sec_mode & 1) {
667 if ((cli->sec_mode & 2) && *pass && passlen != 24) {
669 * Non-encrypted passwords - convert to DOS codepage before encryption.
672 clistr_push(cli, dos_pword, pass, -1, STR_TERMINATE);
673 SMBencrypt((uchar *)dos_pword,cli->secblob.data,(uchar *)pword);
675 if((cli->sec_mode & 3) == 0) {
677 * Non-encrypted passwords - convert to DOS codepage before using.
679 passlen = clistr_push(cli, pword, pass, -1, STR_TERMINATE);
681 memcpy(pword, pass, passlen);
685 if (cli->port == 445) {
686 slprintf(fullshare, sizeof(fullshare)-1,
689 slprintf(fullshare, sizeof(fullshare)-1,
690 "\\\\%s\\%s", cli->desthost, share);
693 set_message(cli->outbuf,4, 0, True);
694 CVAL(cli->outbuf,smb_com) = SMBtconX;
695 cli_setup_packet(cli);
697 SSVAL(cli->outbuf,smb_vwv0,0xFF);
698 SSVAL(cli->outbuf,smb_vwv3,passlen);
700 p = smb_buf(cli->outbuf);
701 memcpy(p,pword,passlen);
703 p += clistr_push(cli, p, fullshare, -1, STR_TERMINATE |STR_UPPER);
704 fstrcpy(p, dev); p += strlen(dev)+1;
706 cli_setup_bcc(cli, p);
709 if (!cli_receive_smb(cli))
712 if (cli_is_error(cli)) {
716 clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE|STR_ASCII);
718 if (strcasecmp(share,"IPC$")==0) {
719 fstrcpy(cli->dev, "IPC");
722 if (cli->protocol >= PROTOCOL_NT1 &&
723 smb_buflen(cli->inbuf) == 3) {
724 /* almost certainly win95 - enable bug fixes */
728 cli->cnum = SVAL(cli->inbuf,smb_tid);
733 /****************************************************************************
734 send a tree disconnect
735 ****************************************************************************/
736 BOOL cli_tdis(struct cli_state *cli)
738 memset(cli->outbuf,'\0',smb_size);
739 set_message(cli->outbuf,0,0,True);
740 CVAL(cli->outbuf,smb_com) = SMBtdis;
741 SSVAL(cli->outbuf,smb_tid,cli->cnum);
742 cli_setup_packet(cli);
745 if (!cli_receive_smb(cli))
748 return !cli_is_error(cli);
752 /****************************************************************************
753 send a negprot command
754 ****************************************************************************/
755 void cli_negprot_send(struct cli_state *cli)
760 memset(cli->outbuf,'\0',smb_size);
762 /* setup the protocol strings */
763 set_message(cli->outbuf,0,0,True);
765 p = smb_buf(cli->outbuf);
767 prots[numprots].name && prots[numprots].prot<=cli->protocol;
770 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
773 CVAL(cli->outbuf,smb_com) = SMBnegprot;
774 cli_setup_bcc(cli, p);
775 cli_setup_packet(cli);
777 CVAL(smb_buf(cli->outbuf),0) = 2;
783 /****************************************************************************
784 send a negprot command
785 ****************************************************************************/
786 BOOL cli_negprot(struct cli_state *cli)
792 memset(cli->outbuf,'\0',smb_size);
794 /* setup the protocol strings */
795 for (plength=0,numprots=0;
796 prots[numprots].name && prots[numprots].prot<=cli->protocol;
798 plength += strlen(prots[numprots].name)+2;
800 set_message(cli->outbuf,0,plength,True);
802 p = smb_buf(cli->outbuf);
804 prots[numprots].name && prots[numprots].prot<=cli->protocol;
807 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
810 CVAL(cli->outbuf,smb_com) = SMBnegprot;
811 cli_setup_packet(cli);
813 CVAL(smb_buf(cli->outbuf),0) = 2;
816 if (!cli_receive_smb(cli))
819 show_msg(cli->inbuf);
821 if (cli_is_error(cli) ||
822 ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
826 cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
828 if (cli->protocol >= PROTOCOL_NT1) {
830 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
831 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
832 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
833 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
834 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1);
835 cli->serverzone *= 60;
836 /* this time arrives in real GMT */
837 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
838 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
839 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
840 if (cli->capabilities & CAP_RAW_MODE) {
841 cli->readbraw_supported = True;
842 cli->writebraw_supported = True;
844 /* work out if they sent us a workgroup */
845 if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
846 smb_buflen(cli->inbuf) > 8) {
847 clistr_pull(cli, cli->server_domain,
848 smb_buf(cli->inbuf)+8, sizeof(cli->server_domain),
849 smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
851 } else if (cli->protocol >= PROTOCOL_LANMAN1) {
852 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
853 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
854 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
855 cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
856 cli->serverzone *= 60;
857 /* this time is converted to GMT by make_unix_date */
858 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
859 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
860 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
861 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
863 /* the old core protocol */
865 cli->serverzone = TimeDiff(time(NULL));
868 cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
870 /* a way to force ascii SMB */
871 if (getenv("CLI_FORCE_ASCII")) {
872 cli->capabilities &= ~CAP_UNICODE;
879 /****************************************************************************
880 send a session request. see rfc1002.txt 4.3 and 4.3.2
881 ****************************************************************************/
882 BOOL cli_session_request(struct cli_state *cli,
883 struct nmb_name *calling, struct nmb_name *called)
887 extern pstring user_socket_options;
889 /* 445 doesn't have session request */
890 if (cli->port == 445) return True;
892 /* send a session request (RFC 1002) */
893 memcpy(&(cli->calling), calling, sizeof(*calling));
894 memcpy(&(cli->called ), called , sizeof(*called ));
896 /* put in the destination name */
898 name_mangle(cli->called .name, p, cli->called .name_type);
903 name_mangle(cli->calling.name, p, cli->calling.name_type);
906 /* setup the packet length */
907 _smb_setlen(cli->outbuf,len);
908 CVAL(cli->outbuf,0) = 0x81;
912 #endif /* WITH_SSL */
915 DEBUG(5,("Sent session request\n"));
917 if (!cli_receive_smb(cli))
920 if (CVAL(cli->inbuf,0) == 0x84) {
921 /* C. Hoch 9/14/95 Start */
922 /* For information, here is the response structure.
923 * We do the byte-twiddling to for portability.
924 struct RetargetResponse{
932 int port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
933 /* SESSION RETARGET */
934 putip((char *)&cli->dest_ip,cli->inbuf+4);
936 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
940 DEBUG(3,("Retargeted\n"));
942 set_socket_options(cli->fd,user_socket_options);
949 DEBUG(0,("Retarget recursion - failing\n"));
953 ret = cli_session_request(cli, calling, called);
957 } /* C. Hoch 9/14/95 End */
960 if (CVAL(cli->inbuf,0) == 0x83 && CVAL(cli->inbuf,4) == 0x8e){ /* use ssl */
961 if (!sslutil_fd_is_ssl(cli->fd)){
962 if (sslutil_connect(cli->fd) == 0)
966 #endif /* WITH_SSL */
968 if (CVAL(cli->inbuf,0) != 0x82) {
969 /* This is the wrong place to put the error... JRA. */
970 cli->rap_error = CVAL(cli->inbuf,4);
976 /****************************************************************************
977 open the client sockets
978 ****************************************************************************/
979 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
981 extern pstring user_socket_options;
982 int name_type = 0x20;
985 /* reasonable default hostname */
986 if (!host) host = "*SMBSERVER";
988 fstrcpy(cli->desthost, host);
990 /* allow hostnames of the form NAME#xx and do a netbios lookup */
991 if ((p = strchr(cli->desthost, '#'))) {
992 name_type = strtol(p+1, NULL, 16);
996 if (!ip || is_zero_ip(*ip)) {
997 if (!resolve_name(cli->desthost, &cli->dest_ip, name_type)) {
1000 if (ip) *ip = cli->dest_ip;
1005 if (getenv("LIBSMB_PROG")) {
1006 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
1008 /* try 445 first, then 139 */
1009 int port = cli->port?cli->port:445;
1010 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
1011 port, cli->timeout);
1012 if (cli->fd == -1 && cli->port == 0) {
1014 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
1015 port, cli->timeout);
1017 if (cli->fd != -1) cli->port = port;
1019 if (cli->fd == -1) {
1020 DEBUG(1,("Error connecting to %s (%s)\n",
1021 inet_ntoa(*ip),strerror(errno)));
1025 set_socket_options(cli->fd,user_socket_options);
1030 /****************************************************************************
1031 establishes a connection right up to doing tconX, password in cache.
1032 ****************************************************************************/
1033 BOOL cli_establish_connection(struct cli_state *cli,
1034 char *dest_host, struct in_addr *dest_ip,
1035 struct nmb_name *calling, struct nmb_name *called,
1036 char *service, char *service_type,
1037 BOOL do_shutdown, BOOL do_tcon)
1039 DEBUG(5,("cli_establish_connection: %s connecting to %s (%s) - %s [%s]\n",
1040 nmb_namestr(calling), nmb_namestr(called), inet_ntoa(*dest_ip),
1041 cli->user_name, cli->domain));
1043 /* establish connection */
1045 if ((!cli->initialised))
1050 /* cli_establish_connection() can't handle spnego yet. Once we get rid of
1051 pwd_cache and other horrors we can get rid of this */
1052 cli->use_spnego = False;
1056 if (!cli_connect(cli, dest_host, dest_ip))
1058 DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n",
1059 nmb_namestr(called), inet_ntoa(*dest_ip)));
1064 if (!cli_session_request(cli, calling, called))
1066 DEBUG(1,("failed session request\n"));
1072 if (!cli_negprot(cli))
1074 DEBUG(1,("failed negprot\n"));
1080 if (cli->pwd.cleartext || cli->pwd.null_pwd)
1085 if (cli->pwd.null_pwd)
1087 /* attempt null session */
1093 /* attempt clear-text session */
1094 pwd_get_cleartext(&(cli->pwd), passwd);
1095 pass_len = strlen(passwd);
1098 /* attempt clear-text session */
1099 if (!cli_session_setup(cli, cli->user_name,
1104 DEBUG(1,("failed session setup\n"));
1113 if (!cli_send_tconX(cli, service, service_type,
1114 (char*)passwd, strlen(passwd)))
1116 DEBUG(1,("failed tcon_X\n"));
1127 /* attempt encrypted session */
1128 unsigned char nt_sess_pwd[24];
1129 unsigned char lm_sess_pwd[24];
1131 /* creates (storing a copy of) and then obtains a 24 byte password OWF */
1132 pwd_make_lm_nt_owf(&(cli->pwd), cli->secblob.data);
1133 pwd_get_lm_nt_owf(&(cli->pwd), lm_sess_pwd, nt_sess_pwd);
1135 /* attempt encrypted session */
1136 if (!cli_session_setup(cli, cli->user_name,
1137 (char*)lm_sess_pwd, sizeof(lm_sess_pwd),
1138 (char*)nt_sess_pwd, sizeof(nt_sess_pwd),
1141 DEBUG(1,("failed session setup\n"));
1147 DEBUG(1,("session setup ok\n"));
1149 if (*cli->server_domain || *cli->server_os || *cli->server_type)
1151 DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",
1159 if (!cli_send_tconX(cli, service, service_type,
1160 (char*)nt_sess_pwd, sizeof(nt_sess_pwd)))
1162 DEBUG(1,("failed tcon_X\n"));
1176 /* Initialise client credentials for authenticated pipe access */
1178 static void init_creds(struct ntuser_creds *creds, char* username,
1179 char* domain, char* password, int pass_len)
1181 ZERO_STRUCTP(creds);
1183 pwd_set_cleartext(&creds->pwd, password);
1185 fstrcpy(creds->user_name, username);
1186 fstrcpy(creds->domain, domain);
1189 creds->pwd.null_pwd = True;
1193 /****************************************************************************
1194 establishes a connection right up to doing tconX, password specified.
1195 ****************************************************************************/
1196 NTSTATUS cli_full_connection(struct cli_state **output_cli,
1197 const char *my_name, const char *dest_host,
1198 struct in_addr *dest_ip, int port,
1199 char *service, char *service_type,
1200 char *user, char *domain,
1201 char *password, int pass_len)
1203 struct ntuser_creds creds;
1205 struct nmb_name calling;
1206 struct nmb_name called;
1207 struct cli_state *cli;
1211 DEBUG(0, ("output_cli is NULL!?!"));
1216 make_nmb_name(&calling, my_name, 0x0);
1217 make_nmb_name(&called , dest_host, 0x20);
1221 if (!(cli = cli_initialise(NULL))) {
1222 return NT_STATUS_NO_MEMORY;
1225 if (cli_set_port(cli, port) != port) {
1226 return NT_STATUS_UNSUCCESSFUL;
1231 DEBUG(3,("Connecting to host=%s share=%s\n\n",
1232 dest_host, service));
1234 if (!cli_connect(cli, dest_host, &ip))
1236 DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n",
1237 nmb_namestr(&called), inet_ntoa(*dest_ip)));
1238 return NT_STATUS_UNSUCCESSFUL;
1241 if (!cli_session_request(cli, &calling, &called)) {
1243 DEBUG(1,("session request to %s failed (%s)\n",
1244 called.name, cli_errstr(cli)));
1246 if ((p=strchr(called.name, '.'))) {
1250 if (strcmp(called.name, "*SMBSERVER")) {
1251 make_nmb_name(&called , "*SMBSERVER", 0x20);
1254 return NT_STATUS_UNSUCCESSFUL;
1257 if (!cli_negprot(cli))
1259 DEBUG(1,("failed negprot\n"));
1260 nt_status = NT_STATUS_UNSUCCESSFUL;
1265 if (!cli_session_setup(cli, user,
1270 DEBUG(1,("failed session setup\n"));
1271 nt_status = cli_nt_error(cli);
1278 if (!cli_send_tconX(cli, service, service_type,
1279 (char*)password, pass_len))
1281 DEBUG(1,("failed tcon_X\n"));
1282 nt_status = cli_nt_error(cli);
1288 init_creds(&creds, user, domain, password, pass_len);
1289 cli_init_creds(cli, &creds);
1292 return NT_STATUS_OK;
1295 /****************************************************************************
1296 Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
1297 ****************************************************************************/
1299 BOOL attempt_netbios_session_request(struct cli_state *cli, char *srchost, char *desthost,
1300 struct in_addr *pdest_ip)
1302 struct nmb_name calling, called;
1304 make_nmb_name(&calling, srchost, 0x0);
1307 * If the called name is an IP address
1308 * then use *SMBSERVER immediately.
1311 if(is_ipaddress(desthost))
1312 make_nmb_name(&called, "*SMBSERVER", 0x20);
1314 make_nmb_name(&called, desthost, 0x20);
1316 if (!cli_session_request(cli, &calling, &called)) {
1317 struct nmb_name smbservername;
1319 make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
1322 * If the name wasn't *SMBSERVER then
1323 * try with *SMBSERVER if the first name fails.
1326 if (nmb_name_equal(&called, &smbservername)) {
1329 * The name used was *SMBSERVER, don't bother with another name.
1332 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
1333 with error %s.\n", desthost, cli_errstr(cli) ));
1340 if (!cli_initialise(cli) ||
1341 !cli_connect(cli, desthost, pdest_ip) ||
1342 !cli_session_request(cli, &calling, &smbservername)) {
1343 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
1344 name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) ));