2 Unix SMB/CIFS implementation.
3 client connect/disconnect routines
4 Copyright (C) Andrew Tridgell 1994-1998
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32 {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"},
33 {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
34 {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
35 {PROTOCOL_LANMAN1,"LANMAN1.0"},
36 {PROTOCOL_LANMAN2,"LM1.2X002"},
37 {PROTOCOL_LANMAN2,"Samba"},
38 {PROTOCOL_NT1,"NT LANMAN 1.0"},
39 {PROTOCOL_NT1,"NT LM 0.12"},
44 /****************************************************************************
45 do an old lanman2 style session setup
46 ****************************************************************************/
47 static BOOL cli_session_setup_lanman2(struct cli_state *cli, char *user,
48 char *pass, int passlen)
53 if (passlen > sizeof(pword)-1) {
57 /* if in share level security then don't send a password now */
58 if (!(cli->sec_mode & 1)) {
62 if (passlen > 0 && (cli->sec_mode & 2) && passlen != 24) {
63 /* Encrypted mode needed, and non encrypted password supplied. */
65 clistr_push(cli, pword, pass, -1, STR_TERMINATE);
66 SMBencrypt((uchar *)pword,cli->secblob.data,(uchar *)pword);
67 } else if ((cli->sec_mode & 2) && passlen == 24) {
68 /* Encrypted mode needed, and encrypted password supplied. */
69 memcpy(pword, pass, passlen);
70 } else if (passlen > 0) {
71 /* Plaintext mode needed, assume plaintext supplied. */
72 passlen = clistr_push(cli, pword, pass, -1, STR_TERMINATE);
75 /* send a session setup command */
76 memset(cli->outbuf,'\0',smb_size);
77 set_message(cli->outbuf,10, 0, True);
78 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
79 cli_setup_packet(cli);
81 SCVAL(cli->outbuf,smb_vwv0,0xFF);
82 SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
83 SSVAL(cli->outbuf,smb_vwv3,2);
84 SSVAL(cli->outbuf,smb_vwv4,1);
85 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
86 SSVAL(cli->outbuf,smb_vwv7,passlen);
88 p = smb_buf(cli->outbuf);
89 memcpy(p,pword,passlen);
91 p += clistr_push(cli, p, user, -1, STR_TERMINATE);
92 cli_setup_bcc(cli, p);
95 if (!cli_receive_smb(cli))
100 if (cli_is_error(cli)) {
104 /* use the returned vuid from now on */
105 cli->vuid = SVAL(cli->inbuf,smb_uid);
106 fstrcpy(cli->user_name, user);
112 /****************************************************************************
113 work out suitable capabilities to offer the server
114 ****************************************************************************/
115 static uint32 cli_session_setup_capabilities(struct cli_state *cli)
117 uint32 capabilities = CAP_NT_SMBS;
119 if (!cli->force_dos_errors) {
120 capabilities |= CAP_STATUS32;
123 if (cli->use_level_II_oplocks) {
124 capabilities |= CAP_LEVEL_II_OPLOCKS;
127 if (cli->capabilities & CAP_UNICODE) {
128 capabilities |= CAP_UNICODE;
135 /****************************************************************************
136 do a NT1 guest session setup
137 ****************************************************************************/
138 static BOOL cli_session_setup_guest(struct cli_state *cli)
141 uint32 capabilities = cli_session_setup_capabilities(cli);
143 set_message(cli->outbuf,13,0,True);
144 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
145 cli_setup_packet(cli);
147 SCVAL(cli->outbuf,smb_vwv0,0xFF);
148 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
149 SSVAL(cli->outbuf,smb_vwv3,2);
150 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
151 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
152 SSVAL(cli->outbuf,smb_vwv7,0);
153 SSVAL(cli->outbuf,smb_vwv8,0);
154 SIVAL(cli->outbuf,smb_vwv11,capabilities);
155 p = smb_buf(cli->outbuf);
156 p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* username */
157 p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* workgroup */
158 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
159 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
160 cli_setup_bcc(cli, p);
163 if (!cli_receive_smb(cli))
166 show_msg(cli->inbuf);
168 if (cli_is_error(cli)) {
172 cli->vuid = SVAL(cli->inbuf,smb_uid);
174 p = smb_buf(cli->inbuf);
175 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
176 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
177 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
179 fstrcpy(cli->user_name, "");
185 /****************************************************************************
186 do a NT1 plaintext session setup
187 ****************************************************************************/
188 static BOOL cli_session_setup_plaintext(struct cli_state *cli, char *user,
189 char *pass, char *workgroup)
191 uint32 capabilities = cli_session_setup_capabilities(cli);
196 passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE|STR_ASCII);
198 set_message(cli->outbuf,13,0,True);
199 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
200 cli_setup_packet(cli);
202 SCVAL(cli->outbuf,smb_vwv0,0xFF);
203 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
204 SSVAL(cli->outbuf,smb_vwv3,2);
205 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
206 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
207 SSVAL(cli->outbuf,smb_vwv7,passlen);
208 SSVAL(cli->outbuf,smb_vwv8,0);
209 SIVAL(cli->outbuf,smb_vwv11,capabilities);
210 p = smb_buf(cli->outbuf);
211 memcpy(p, pword, passlen);
213 p += clistr_push(cli, p, user, -1, STR_TERMINATE); /* username */
214 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE); /* workgroup */
215 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
216 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
217 cli_setup_bcc(cli, p);
220 if (!cli_receive_smb(cli))
223 show_msg(cli->inbuf);
225 if (cli_is_error(cli)) {
229 cli->vuid = SVAL(cli->inbuf,smb_uid);
230 p = smb_buf(cli->inbuf);
231 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
232 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
233 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
234 fstrcpy(cli->user_name, user);
240 /****************************************************************************
241 do a NT1 NTLM/LM encrypted session setup
242 ****************************************************************************/
243 static BOOL cli_session_setup_nt1(struct cli_state *cli, char *user,
244 char *pass, int passlen,
245 char *ntpass, int ntpasslen,
248 uint32 capabilities = cli_session_setup_capabilities(cli);
249 fstring pword, ntpword;
252 if (passlen > sizeof(pword)-1 || ntpasslen > sizeof(ntpword)-1) {
257 /* non encrypted password supplied. Ignore ntpass. */
260 clistr_push(cli, pword,
261 pass?pass:"", sizeof(pword), STR_TERMINATE|STR_ASCII);
262 clistr_push(cli, ntpword,
263 pass?pass:"", sizeof(ntpword), STR_TERMINATE|STR_ASCII);
264 SMBencrypt((uchar *)pword,cli->secblob.data,(uchar *)pword);
265 SMBNTencrypt((uchar *)ntpword,cli->secblob.data,(uchar *)ntpword);
267 memcpy(pword, pass, passlen);
268 memcpy(ntpword, ntpass, ntpasslen);
271 /* send a session setup command */
272 memset(cli->outbuf,'\0',smb_size);
274 set_message(cli->outbuf,13,0,True);
275 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
276 cli_setup_packet(cli);
278 SCVAL(cli->outbuf,smb_vwv0,0xFF);
279 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
280 SSVAL(cli->outbuf,smb_vwv3,2);
281 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
282 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
283 SSVAL(cli->outbuf,smb_vwv7,passlen);
284 SSVAL(cli->outbuf,smb_vwv8,ntpasslen);
285 SIVAL(cli->outbuf,smb_vwv11,capabilities);
286 p = smb_buf(cli->outbuf);
287 memcpy(p,pword,passlen); p += passlen;
288 memcpy(p,ntpword,ntpasslen); p += ntpasslen;
289 p += clistr_push(cli, p, user, -1, STR_TERMINATE|STR_UPPER);
290 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
291 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
292 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
293 cli_setup_bcc(cli, p);
296 if (!cli_receive_smb(cli))
299 show_msg(cli->inbuf);
301 if (cli_is_error(cli)) {
305 /* use the returned vuid from now on */
306 cli->vuid = SVAL(cli->inbuf,smb_uid);
308 p = smb_buf(cli->inbuf);
309 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
310 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
311 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
313 fstrcpy(cli->user_name, user);
319 /****************************************************************************
320 send a extended security session setup blob, returning a reply blob
321 ****************************************************************************/
322 static DATA_BLOB cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob)
324 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 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
338 cli_setup_packet(cli);
340 SCVAL(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);
375 /* w2k with kerberos doesn't properly null terminate this field */
376 len = smb_buflen(cli->inbuf) - PTR_DIFF(p, smb_buf(cli->inbuf));
377 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), len, 0);
384 /****************************************************************************
385 do a spnego/kerberos encrypted session setup
386 ****************************************************************************/
387 static BOOL cli_session_setup_kerberos(struct cli_state *cli, char *principal, char *workgroup)
389 DATA_BLOB blob2, negTokenTarg;
391 DEBUG(2,("Doing kerberos session setup\n"));
393 /* generate the encapsulated kerberos5 ticket */
394 negTokenTarg = spnego_gen_negTokenTarg(cli, principal);
396 if (!negTokenTarg.data) return False;
399 file_save("negTokenTarg.dat", negTokenTarg.data, negTokenTarg.length);
402 blob2 = cli_session_setup_blob(cli, negTokenTarg);
404 /* we don't need this blob for kerberos */
405 data_blob_free(&blob2);
407 data_blob_free(&negTokenTarg);
409 return !cli_is_error(cli);
413 /****************************************************************************
414 do a spnego/NTLMSSP encrypted session setup
415 ****************************************************************************/
416 static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, char *user,
417 char *pass, char *workgroup)
419 const char *mechs[] = {OID_NTLMSSP, NULL};
421 DATA_BLOB blob, chal1, chal2, auth;
423 uint8 nthash[24], lmhash[24], sess_key[16];
426 neg_flags = NTLMSSP_NEGOTIATE_UNICODE |
427 NTLMSSP_NEGOTIATE_LM_KEY |
428 NTLMSSP_NEGOTIATE_NTLM;
430 memset(sess_key, 0, 16);
432 /* generate the ntlmssp negotiate packet */
433 msrpc_gen(&blob, "CddB",
439 /* and wrap it in a SPNEGO wrapper */
440 msg1 = gen_negTokenTarg(mechs, blob);
441 data_blob_free(&blob);
443 /* now send that blob on its way */
444 blob = cli_session_setup_blob(cli, msg1);
446 data_blob_free(&msg1);
448 if (!NT_STATUS_EQUAL(cli_nt_error(cli), NT_STATUS_MORE_PROCESSING_REQUIRED)) {
453 file_save("chal.dat", blob.data, blob.length);
456 /* the server gives us back two challenges */
457 if (!spnego_parse_challenge(blob, &chal1, &chal2)) {
458 DEBUG(3,("Failed to parse challenges\n"));
462 data_blob_free(&blob);
464 /* encrypt the password with the challenge */
465 memcpy(challenge, chal1.data + 24, 8);
466 SMBencrypt((unsigned char *)pass, challenge,lmhash);
467 SMBNTencrypt((unsigned char *)pass, challenge,nthash);
470 file_save("nthash.dat", nthash, 24);
471 file_save("lmhash.dat", lmhash, 24);
472 file_save("chal1.dat", chal1.data, chal1.length);
475 data_blob_free(&chal1);
476 data_blob_free(&chal2);
478 /* this generates the actual auth packet */
479 msrpc_gen(&blob, "CdBBUUUBd",
490 /* wrap it in SPNEGO */
491 auth = spnego_gen_auth(blob);
493 data_blob_free(&blob);
495 /* now send the auth packet and we should be done */
496 blob = cli_session_setup_blob(cli, auth);
498 data_blob_free(&auth);
499 data_blob_free(&blob);
501 return !cli_is_error(cli);
505 /****************************************************************************
506 do a spnego encrypted session setup
507 ****************************************************************************/
508 static BOOL cli_session_setup_spnego(struct cli_state *cli, char *user,
509 char *pass, char *workgroup)
512 char *OIDs[ASN1_MAX_OIDS];
515 BOOL got_kerberos_mechanism = False;
517 DEBUG(2,("Doing spnego session setup (blob length=%d)\n", cli->secblob.length));
519 /* the server might not even do spnego */
520 if (cli->secblob.length == 16) {
521 DEBUG(3,("server didn't supply a full spnego negprot\n"));
526 file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
529 /* the server sent us the first part of the SPNEGO exchange in the negprot
531 if (!spnego_parse_negTokenInit(cli->secblob, guid, OIDs, &principal)) {
535 /* make sure the server understands kerberos */
536 for (i=0;OIDs[i];i++) {
537 DEBUG(3,("got OID=%s\n", OIDs[i]));
538 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
539 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
540 got_kerberos_mechanism = True;
544 DEBUG(3,("got principal=%s\n", principal));
546 fstrcpy(cli->user_name, user);
549 if (got_kerberos_mechanism && cli->use_kerberos) {
550 return cli_session_setup_kerberos(cli, principal, workgroup);
558 return cli_session_setup_ntlmssp(cli, user, pass, workgroup);
562 /****************************************************************************
563 Send a session setup. The username and workgroup is in UNIX character
564 format and must be converted to DOS codepage format before sending. If the
565 password is in plaintext, the same should be done.
566 ****************************************************************************/
567 BOOL cli_session_setup(struct cli_state *cli,
569 char *pass, int passlen,
570 char *ntpass, int ntpasslen,
576 /* allow for workgroups as part of the username */
577 fstrcpy(user2, user);
578 if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/')) ||
579 (p=strchr_m(user2,*lp_winbind_separator()))) {
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 SCVAL(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 SCVAL(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 SCVAL(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 SCVAL(cli->outbuf,smb_com,SMBnegprot);
773 cli_setup_bcc(cli, p);
774 cli_setup_packet(cli);
776 SCVAL(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 SCVAL(cli->outbuf,smb_com,SMBnegprot);
810 cli_setup_packet(cli);
812 SCVAL(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 SCVAL(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) {
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)));
1239 return NT_STATUS_UNSUCCESSFUL;
1242 if (!cli_session_request(cli, &calling, &called)) {
1244 DEBUG(1,("session request to %s failed (%s)\n",
1245 called.name, cli_errstr(cli)));
1247 if ((p=strchr(called.name, '.'))) {
1251 if (strcmp(called.name, "*SMBSERVER")) {
1252 make_nmb_name(&called , "*SMBSERVER", 0x20);
1255 return NT_STATUS_UNSUCCESSFUL;
1258 if (!cli_negprot(cli))
1260 DEBUG(1,("failed negprot\n"));
1261 nt_status = NT_STATUS_UNSUCCESSFUL;
1266 if (!cli_session_setup(cli, user,
1271 DEBUG(1,("failed session setup\n"));
1272 nt_status = cli_nt_error(cli);
1274 if (NT_STATUS_IS_OK(nt_status)) nt_status = NT_STATUS_UNSUCCESSFUL;
1280 if (!cli_send_tconX(cli, service, service_type,
1281 (char*)password, pass_len))
1283 DEBUG(1,("failed tcon_X\n"));
1284 nt_status = cli_nt_error(cli);
1286 if (NT_STATUS_IS_OK(nt_status)) nt_status = NT_STATUS_UNSUCCESSFUL;
1291 init_creds(&creds, user, domain, password, pass_len);
1292 cli_init_creds(cli, &creds);
1295 return NT_STATUS_OK;
1298 /****************************************************************************
1299 Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
1300 ****************************************************************************/
1302 BOOL attempt_netbios_session_request(struct cli_state *cli, char *srchost, char *desthost,
1303 struct in_addr *pdest_ip)
1305 struct nmb_name calling, called;
1307 make_nmb_name(&calling, srchost, 0x0);
1310 * If the called name is an IP address
1311 * then use *SMBSERVER immediately.
1314 if(is_ipaddress(desthost))
1315 make_nmb_name(&called, "*SMBSERVER", 0x20);
1317 make_nmb_name(&called, desthost, 0x20);
1319 if (!cli_session_request(cli, &calling, &called)) {
1320 struct nmb_name smbservername;
1322 make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
1325 * If the name wasn't *SMBSERVER then
1326 * try with *SMBSERVER if the first name fails.
1329 if (nmb_name_equal(&called, &smbservername)) {
1332 * The name used was *SMBSERVER, don't bother with another name.
1335 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
1336 with error %s.\n", desthost, cli_errstr(cli) ));
1343 if (!cli_initialise(cli) ||
1344 !cli_connect(cli, desthost, pdest_ip) ||
1345 !cli_session_request(cli, &calling, &smbservername)) {
1346 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
1347 name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) ));