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 /* Set the CLI_FORCE_DOSERR environment variable to test
121 client routines using DOS errors instead of STATUS32
122 ones. This intended only as a temporary hack. */
123 if (!getenv("CLI_FORCE_DOSERR")) {
124 capabilities
|= CAP_STATUS32
;
127 if (cli
->use_level_II_oplocks
) {
128 capabilities
|= CAP_LEVEL_II_OPLOCKS
;
131 if (cli
->capabilities
& CAP_UNICODE
) {
132 capabilities
|= CAP_UNICODE
;
139 /****************************************************************************
140 do a NT1 guest session setup
141 ****************************************************************************/
142 static BOOL
cli_session_setup_guest(struct cli_state
*cli
)
145 uint32 capabilities
= cli_session_setup_capabilities(cli
);
147 set_message(cli
->outbuf
,13,0,True
);
148 CVAL(cli
->outbuf
,smb_com
) = SMBsesssetupX
;
149 cli_setup_packet(cli
);
151 CVAL(cli
->outbuf
,smb_vwv0
) = 0xFF;
152 SSVAL(cli
->outbuf
,smb_vwv2
,CLI_BUFFER_SIZE
);
153 SSVAL(cli
->outbuf
,smb_vwv3
,2);
154 SSVAL(cli
->outbuf
,smb_vwv4
,cli
->pid
);
155 SIVAL(cli
->outbuf
,smb_vwv5
,cli
->sesskey
);
156 SSVAL(cli
->outbuf
,smb_vwv7
,0);
157 SSVAL(cli
->outbuf
,smb_vwv8
,0);
158 SIVAL(cli
->outbuf
,smb_vwv11
,capabilities
);
159 p
= smb_buf(cli
->outbuf
);
160 p
+= clistr_push(cli
, p
, "", -1, STR_TERMINATE
); /* username */
161 p
+= clistr_push(cli
, p
, "", -1, STR_TERMINATE
); /* workgroup */
162 p
+= clistr_push(cli
, p
, "Unix", -1, STR_TERMINATE
);
163 p
+= clistr_push(cli
, p
, "Samba", -1, STR_TERMINATE
);
164 cli_setup_bcc(cli
, p
);
167 if (!cli_receive_smb(cli
))
170 show_msg(cli
->inbuf
);
172 if (cli_is_error(cli
)) {
176 cli
->vuid
= SVAL(cli
->inbuf
,smb_uid
);
178 p
= smb_buf(cli
->inbuf
);
179 p
+= clistr_pull(cli
, cli
->server_os
, p
, sizeof(fstring
), -1, STR_TERMINATE
);
180 p
+= clistr_pull(cli
, cli
->server_type
, p
, sizeof(fstring
), -1, STR_TERMINATE
);
181 p
+= clistr_pull(cli
, cli
->server_domain
, p
, sizeof(fstring
), -1, STR_TERMINATE
);
183 fstrcpy(cli
->user_name
, "");
189 /****************************************************************************
190 do a NT1 plaintext session setup
191 ****************************************************************************/
192 static BOOL
cli_session_setup_plaintext(struct cli_state
*cli
, char *user
,
193 char *pass
, char *workgroup
)
195 uint32 capabilities
= cli_session_setup_capabilities(cli
);
200 passlen
= clistr_push(cli
, pword
, pass
, sizeof(pword
), STR_TERMINATE
);
202 set_message(cli
->outbuf
,13,0,True
);
203 CVAL(cli
->outbuf
,smb_com
) = SMBsesssetupX
;
204 cli_setup_packet(cli
);
206 CVAL(cli
->outbuf
,smb_vwv0
) = 0xFF;
207 SSVAL(cli
->outbuf
,smb_vwv2
,CLI_BUFFER_SIZE
);
208 SSVAL(cli
->outbuf
,smb_vwv3
,2);
209 SSVAL(cli
->outbuf
,smb_vwv4
,cli
->pid
);
210 SIVAL(cli
->outbuf
,smb_vwv5
,cli
->sesskey
);
211 SSVAL(cli
->outbuf
,smb_vwv7
,passlen
);
212 SSVAL(cli
->outbuf
,smb_vwv8
,0);
213 SIVAL(cli
->outbuf
,smb_vwv11
,capabilities
);
214 p
= smb_buf(cli
->outbuf
);
215 memcpy(p
, pword
, passlen
);
217 p
+= clistr_push(cli
, p
, user
, -1, STR_TERMINATE
); /* username */
218 p
+= clistr_push(cli
, p
, workgroup
, -1, STR_TERMINATE
); /* workgroup */
219 p
+= clistr_push(cli
, p
, "Unix", -1, STR_TERMINATE
);
220 p
+= clistr_push(cli
, p
, "Samba", -1, STR_TERMINATE
);
221 cli_setup_bcc(cli
, p
);
224 if (!cli_receive_smb(cli
))
227 show_msg(cli
->inbuf
);
229 if (cli_is_error(cli
)) {
233 cli
->vuid
= SVAL(cli
->inbuf
,smb_uid
);
234 p
= smb_buf(cli
->inbuf
);
235 p
+= clistr_pull(cli
, cli
->server_os
, p
, sizeof(fstring
), -1, STR_TERMINATE
);
236 p
+= clistr_pull(cli
, cli
->server_type
, p
, sizeof(fstring
), -1, STR_TERMINATE
);
237 p
+= clistr_pull(cli
, cli
->server_domain
, p
, sizeof(fstring
), -1, STR_TERMINATE
);
238 fstrcpy(cli
->user_name
, user
);
244 /****************************************************************************
245 do a NT1 NTLM/LM encrypted session setup
246 ****************************************************************************/
247 static BOOL
cli_session_setup_nt1(struct cli_state
*cli
, char *user
,
248 char *pass
, int passlen
,
249 char *ntpass
, int ntpasslen
,
252 uint32 capabilities
= cli_session_setup_capabilities(cli
);
253 fstring pword
, ntpword
;
256 if (passlen
> sizeof(pword
)-1 || ntpasslen
> sizeof(ntpword
)-1) {
261 /* non encrypted password supplied. */
264 clistr_push(cli
, pword
, pass
, sizeof(pword
), STR_TERMINATE
);
265 clistr_push(cli
, ntpword
, ntpass
, sizeof(ntpword
), STR_TERMINATE
);
266 SMBencrypt((uchar
*)pword
,cli
->secblob
.data
,(uchar
*)pword
);
267 SMBNTencrypt((uchar
*)ntpword
,cli
->secblob
.data
,(uchar
*)ntpword
);
269 memcpy(pword
, pass
, passlen
);
270 memcpy(ntpword
, ntpass
, ntpasslen
);
273 /* send a session setup command */
274 memset(cli
->outbuf
,'\0',smb_size
);
276 set_message(cli
->outbuf
,13,0,True
);
277 CVAL(cli
->outbuf
,smb_com
) = SMBsesssetupX
;
278 cli_setup_packet(cli
);
280 CVAL(cli
->outbuf
,smb_vwv0
) = 0xFF;
281 SSVAL(cli
->outbuf
,smb_vwv2
,CLI_BUFFER_SIZE
);
282 SSVAL(cli
->outbuf
,smb_vwv3
,2);
283 SSVAL(cli
->outbuf
,smb_vwv4
,cli
->pid
);
284 SIVAL(cli
->outbuf
,smb_vwv5
,cli
->sesskey
);
285 SSVAL(cli
->outbuf
,smb_vwv7
,passlen
);
286 SSVAL(cli
->outbuf
,smb_vwv8
,ntpasslen
);
287 SIVAL(cli
->outbuf
,smb_vwv11
,capabilities
);
288 p
= smb_buf(cli
->outbuf
);
289 memcpy(p
,pword
,passlen
); p
+= passlen
;
290 memcpy(p
,ntpword
,ntpasslen
); p
+= ntpasslen
;
291 p
+= clistr_push(cli
, p
, user
, -1, STR_TERMINATE
|STR_UPPER
);
292 p
+= clistr_push(cli
, p
, workgroup
, -1, STR_TERMINATE
|STR_UPPER
);
293 p
+= clistr_push(cli
, p
, "Unix", -1, STR_TERMINATE
);
294 p
+= clistr_push(cli
, p
, "Samba", -1, STR_TERMINATE
);
295 cli_setup_bcc(cli
, p
);
298 if (!cli_receive_smb(cli
))
301 show_msg(cli
->inbuf
);
303 if (cli_is_error(cli
)) {
307 /* use the returned vuid from now on */
308 cli
->vuid
= SVAL(cli
->inbuf
,smb_uid
);
310 p
= smb_buf(cli
->inbuf
);
311 p
+= clistr_pull(cli
, cli
->server_os
, p
, sizeof(fstring
), -1, STR_TERMINATE
);
312 p
+= clistr_pull(cli
, cli
->server_type
, p
, sizeof(fstring
), -1, STR_TERMINATE
);
313 p
+= clistr_pull(cli
, cli
->server_domain
, p
, sizeof(fstring
), -1, STR_TERMINATE
);
315 fstrcpy(cli
->user_name
, user
);
321 /****************************************************************************
322 send a extended security session setup blob, returning a reply blob
323 ****************************************************************************/
324 static DATA_BLOB
cli_session_setup_blob(struct cli_state
*cli
, DATA_BLOB blob
)
326 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
,0);
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
);
375 p
+= clistr_pull(cli
, cli
->server_type
, p
, sizeof(fstring
), -1, STR_TERMINATE
);
376 p
+= clistr_pull(cli
, cli
->server_domain
, p
, sizeof(fstring
), -1, STR_TERMINATE
);
383 /****************************************************************************
384 do a spnego/kerberos encrypted session setup
385 ****************************************************************************/
386 static BOOL
cli_session_setup_kerberos(struct cli_state
*cli
, char *principal
, char *workgroup
)
388 DATA_BLOB blob2
, negTokenTarg
;
390 d_printf("Doing kerberos session setup\n");
392 /* generate the encapsulated kerberos5 ticket */
393 negTokenTarg
= spnego_gen_negTokenTarg(cli
, principal
);
395 if (!negTokenTarg
.data
) return False
;
398 file_save("negTokenTarg.dat", negTokenTarg
.data
, negTokenTarg
.length
);
401 blob2
= cli_session_setup_blob(cli
, negTokenTarg
);
403 /* we don't need this blob for kerberos */
404 data_blob_free(&blob2
);
406 return !cli_is_error(cli
);
410 /****************************************************************************
411 do a spnego/NTLMSSP encrypted session setup
412 ****************************************************************************/
413 static BOOL
cli_session_setup_ntlmssp(struct cli_state
*cli
, char *user
,
414 char *pass
, char *workgroup
)
416 const char *mechs
[] = {OID_NTLMSSP
, NULL
};
418 DATA_BLOB blob
, chal1
, chal2
, auth
;
420 uint8 nthash
[24], lmhash
[24], sess_key
[16];
423 neg_flags
= NTLMSSP_NEGOTIATE_UNICODE
|
424 NTLMSSP_NEGOTIATE_LM_KEY
|
425 NTLMSSP_NEGOTIATE_NTLM
;
427 memset(sess_key
, 0, 16);
429 /* generate the ntlmssp negotiate packet */
430 msrpc_gen(&blob
, "CddB",
436 /* and wrap it in a SPNEGO wrapper */
437 msg1
= gen_negTokenTarg(mechs
, blob
);
438 data_blob_free(&blob
);
440 /* now send that blob on its way */
441 blob
= cli_session_setup_blob(cli
, msg1
);
443 data_blob_free(&msg1
);
445 if (!NT_STATUS_EQUAL(cli_nt_error(cli
), NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
450 file_save("chal.dat", blob
.data
, blob
.length
);
453 /* the server gives us back two challenges */
454 if (!spnego_parse_challenge(blob
, &chal1
, &chal2
)) {
455 DEBUG(3,("Failed to parse challenges\n"));
459 data_blob_free(&blob
);
461 /* encrypt the password with the challenge */
462 memcpy(challenge
, chal1
.data
+ 24, 8);
463 SMBencrypt((unsigned char *)pass
, challenge
,lmhash
);
464 SMBNTencrypt((unsigned char *)pass
, challenge
,nthash
);
467 file_save("nthash.dat", nthash
, 24);
468 file_save("lmhash.dat", lmhash
, 24);
469 file_save("chal1.dat", chal1
.data
, chal1
.length
);
472 data_blob_free(&chal1
);
473 data_blob_free(&chal2
);
475 /* this generates the actual auth packet */
476 msrpc_gen(&blob
, "CdBBUUUBd",
487 /* wrap it in SPNEGO */
488 auth
= spnego_gen_auth(blob
);
490 data_blob_free(&blob
);
492 /* now send the auth packet and we should be done */
493 blob
= cli_session_setup_blob(cli
, auth
);
495 data_blob_free(&auth
);
496 data_blob_free(&blob
);
498 return !cli_is_error(cli
);
502 /****************************************************************************
503 do a spnego encrypted session setup
504 ****************************************************************************/
505 static BOOL
cli_session_setup_spnego(struct cli_state
*cli
, char *user
,
506 char *pass
, char *workgroup
)
509 char *OIDs
[ASN1_MAX_OIDS
];
512 BOOL got_kerberos_mechanism
= False
;
514 d_printf("Doing spnego session setup\n");
516 /* the server might not even do spnego */
517 if (cli
->secblob
.length
== 16) {
518 DEBUG(3,("server didn't supply a full spnego negprot\n"));
523 file_save("negprot.dat", cli
->secblob
.data
, cli
->secblob
.length
);
526 /* the server sent us the first part of the SPNEGO exchange in the negprot
528 if (!spnego_parse_negTokenInit(cli
->secblob
, guid
, OIDs
, &principal
)) {
532 /* make sure the server understands kerberos */
533 for (i
=0;OIDs
[i
];i
++) {
534 DEBUG(3,("got OID=%s\n", OIDs
[i
]));
535 if (strcmp(OIDs
[i
], OID_KERBEROS5_OLD
) == 0 ||
536 strcmp(OIDs
[i
], OID_KERBEROS5
) == 0) {
537 got_kerberos_mechanism
= True
;
541 DEBUG(3,("got principal=%s\n", principal
));
543 fstrcpy(cli
->user_name
, user
);
546 if (got_kerberos_mechanism
&& cli
->use_kerberos
) {
547 return cli_session_setup_kerberos(cli
, principal
, workgroup
);
555 return cli_session_setup_ntlmssp(cli
, user
, pass
, workgroup
);
559 /****************************************************************************
560 Send a session setup. The username and workgroup is in UNIX character
561 format and must be converted to DOS codepage format before sending. If the
562 password is in plaintext, the same should be done.
563 ****************************************************************************/
564 BOOL
cli_session_setup(struct cli_state
*cli
,
566 char *pass
, int passlen
,
567 char *ntpass
, int ntpasslen
,
573 /* allow for workgroups as part of the username */
574 fstrcpy(user2
, user
);
575 if ((p
=strchr_m(user2
,'\\')) || (p
=strchr_m(user2
,'/'))) {
581 if (cli
->protocol
< PROTOCOL_LANMAN1
)
584 /* now work out what sort of session setup we are going to
585 do. I have split this into separate functions to make the
586 flow a bit easier to understand (tridge) */
588 /* if its an older server then we have to use the older request format */
589 if (cli
->protocol
< PROTOCOL_NT1
) {
590 return cli_session_setup_lanman2(cli
, user
, pass
, passlen
);
593 /* if no user is supplied then we have to do an anonymous connection.
594 passwords are ignored */
595 if (!user
|| !*user
) {
596 return cli_session_setup_guest(cli
);
599 /* if the server is share level then send a plaintext null
600 password at this point. The password is sent in the tree
602 if ((cli
->sec_mode
& 1) == 0) {
603 return cli_session_setup_plaintext(cli
, user
, "", workgroup
);
606 /* if the server doesn't support encryption then we have to use plaintext. The
607 second password is ignored */
608 if ((cli
->sec_mode
& 2) == 0) {
609 return cli_session_setup_plaintext(cli
, user
, pass
, workgroup
);
612 /* if the server supports extended security then use SPNEGO */
613 if (cli
->capabilities
& CAP_EXTENDED_SECURITY
) {
614 return cli_session_setup_spnego(cli
, user
, pass
, workgroup
);
617 /* otherwise do a NT1 style session setup */
618 return cli_session_setup_nt1(cli
, user
,
619 pass
, passlen
, ntpass
, ntpasslen
,
623 /****************************************************************************
625 *****************************************************************************/
627 BOOL
cli_ulogoff(struct cli_state
*cli
)
629 memset(cli
->outbuf
,'\0',smb_size
);
630 set_message(cli
->outbuf
,2,0,True
);
631 CVAL(cli
->outbuf
,smb_com
) = SMBulogoffX
;
632 cli_setup_packet(cli
);
633 SSVAL(cli
->outbuf
,smb_vwv0
,0xFF);
634 SSVAL(cli
->outbuf
,smb_vwv2
,0); /* no additional info */
637 if (!cli_receive_smb(cli
))
640 return !cli_is_error(cli
);
643 /****************************************************************************
645 ****************************************************************************/
646 BOOL
cli_send_tconX(struct cli_state
*cli
,
647 const char *share
, const char *dev
, const char *pass
, int passlen
)
649 fstring fullshare
, pword
, dos_pword
;
651 memset(cli
->outbuf
,'\0',smb_size
);
652 memset(cli
->inbuf
,'\0',smb_size
);
654 fstrcpy(cli
->share
, share
);
656 /* in user level security don't send a password now */
657 if (cli
->sec_mode
& 1) {
662 if ((cli
->sec_mode
& 2) && *pass
&& passlen
!= 24) {
664 * Non-encrypted passwords - convert to DOS codepage before encryption.
667 clistr_push(cli
, dos_pword
, pass
, -1, STR_TERMINATE
);
668 SMBencrypt((uchar
*)dos_pword
,cli
->secblob
.data
,(uchar
*)pword
);
670 if((cli
->sec_mode
& 3) == 0) {
672 * Non-encrypted passwords - convert to DOS codepage before using.
674 passlen
= clistr_push(cli
, pword
, pass
, -1, STR_TERMINATE
);
676 memcpy(pword
, pass
, passlen
);
680 if (cli
->port
== 445) {
681 slprintf(fullshare
, sizeof(fullshare
)-1,
684 slprintf(fullshare
, sizeof(fullshare
)-1,
685 "\\\\%s\\%s", cli
->desthost
, share
);
688 set_message(cli
->outbuf
,4, 0, True
);
689 CVAL(cli
->outbuf
,smb_com
) = SMBtconX
;
690 cli_setup_packet(cli
);
692 SSVAL(cli
->outbuf
,smb_vwv0
,0xFF);
693 SSVAL(cli
->outbuf
,smb_vwv3
,passlen
);
695 p
= smb_buf(cli
->outbuf
);
696 memcpy(p
,pword
,passlen
);
698 p
+= clistr_push(cli
, p
, fullshare
, -1, STR_TERMINATE
|STR_UPPER
);
699 fstrcpy(p
, dev
); p
+= strlen(dev
)+1;
701 cli_setup_bcc(cli
, p
);
704 if (!cli_receive_smb(cli
))
707 if (cli_is_error(cli
)) {
711 fstrcpy(cli
->dev
, "A:");
713 if (cli
->protocol
>= PROTOCOL_NT1
) {
714 clistr_pull(cli
, cli
->dev
, smb_buf(cli
->inbuf
), sizeof(fstring
), -1, STR_TERMINATE
);
717 if (strcasecmp(share
,"IPC$")==0) {
718 fstrcpy(cli
->dev
, "IPC");
721 /* only grab the device if we have a recent protocol level */
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 (smb_buflen(cli
->inbuf
) > 8) {
846 clistr_pull(cli
, cli
->server_domain
,
847 smb_buf(cli
->inbuf
)+8, sizeof(cli
->server_domain
),
848 smb_buflen(cli
->inbuf
)-8, STR_UNICODE
|STR_NOALIGN
);
850 } else if (cli
->protocol
>= PROTOCOL_LANMAN1
) {
851 cli
->sec_mode
= SVAL(cli
->inbuf
,smb_vwv1
);
852 cli
->max_xmit
= SVAL(cli
->inbuf
,smb_vwv2
);
853 cli
->sesskey
= IVAL(cli
->inbuf
,smb_vwv6
);
854 cli
->serverzone
= SVALS(cli
->inbuf
,smb_vwv10
);
855 cli
->serverzone
*= 60;
856 /* this time is converted to GMT by make_unix_date */
857 cli
->servertime
= make_unix_date(cli
->inbuf
+smb_vwv8
);
858 cli
->readbraw_supported
= ((SVAL(cli
->inbuf
,smb_vwv5
) & 0x1) != 0);
859 cli
->writebraw_supported
= ((SVAL(cli
->inbuf
,smb_vwv5
) & 0x2) != 0);
860 cli
->secblob
= data_blob(smb_buf(cli
->inbuf
),smb_buflen(cli
->inbuf
));
862 /* the old core protocol */
864 cli
->serverzone
= TimeDiff(time(NULL
));
867 cli
->max_xmit
= MIN(cli
->max_xmit
, CLI_BUFFER_SIZE
);
869 /* a way to force ascii SMB */
870 if (getenv("CLI_FORCE_ASCII")) {
871 cli
->capabilities
&= ~CAP_UNICODE
;
878 /****************************************************************************
879 send a session request. see rfc1002.txt 4.3 and 4.3.2
880 ****************************************************************************/
881 BOOL
cli_session_request(struct cli_state
*cli
,
882 struct nmb_name
*calling
, struct nmb_name
*called
)
886 extern pstring user_socket_options
;
888 /* 445 doesn't have session request */
889 if (cli
->port
== 445) return True
;
891 /* send a session request (RFC 1002) */
892 memcpy(&(cli
->calling
), calling
, sizeof(*calling
));
893 memcpy(&(cli
->called
), called
, sizeof(*called
));
895 /* put in the destination name */
897 name_mangle(cli
->called
.name
, p
, cli
->called
.name_type
);
902 name_mangle(cli
->calling
.name
, p
, cli
->calling
.name_type
);
905 /* setup the packet length */
906 _smb_setlen(cli
->outbuf
,len
);
907 CVAL(cli
->outbuf
,0) = 0x81;
911 #endif /* WITH_SSL */
914 DEBUG(5,("Sent session request\n"));
916 if (!cli_receive_smb(cli
))
919 if (CVAL(cli
->inbuf
,0) == 0x84) {
920 /* C. Hoch 9/14/95 Start */
921 /* For information, here is the response structure.
922 * We do the byte-twiddling to for portability.
923 struct RetargetResponse{
931 int port
= (CVAL(cli
->inbuf
,8)<<8)+CVAL(cli
->inbuf
,9);
932 /* SESSION RETARGET */
933 putip((char *)&cli
->dest_ip
,cli
->inbuf
+4);
935 cli
->fd
= open_socket_out(SOCK_STREAM
, &cli
->dest_ip
, port
, LONG_CONNECT_TIMEOUT
);
939 DEBUG(3,("Retargeted\n"));
941 set_socket_options(cli
->fd
,user_socket_options
);
948 DEBUG(0,("Retarget recursion - failing\n"));
952 ret
= cli_session_request(cli
, calling
, called
);
956 } /* C. Hoch 9/14/95 End */
959 if (CVAL(cli
->inbuf
,0) == 0x83 && CVAL(cli
->inbuf
,4) == 0x8e){ /* use ssl */
960 if (!sslutil_fd_is_ssl(cli
->fd
)){
961 if (sslutil_connect(cli
->fd
) == 0)
965 #endif /* WITH_SSL */
967 if (CVAL(cli
->inbuf
,0) != 0x82) {
968 /* This is the wrong place to put the error... JRA. */
969 cli
->rap_error
= CVAL(cli
->inbuf
,4);
975 /****************************************************************************
976 open the client sockets
977 ****************************************************************************/
978 BOOL
cli_connect(struct cli_state
*cli
, const char *host
, struct in_addr
*ip
)
980 extern struct in_addr ipzero
;
981 extern pstring user_socket_options
;
983 fstrcpy(cli
->desthost
, host
);
985 if (!ip
|| ip_equal(*ip
, ipzero
)) {
986 if (!resolve_name( cli
->desthost
, &cli
->dest_ip
, 0x20)) {
989 if (ip
) *ip
= cli
->dest_ip
;
994 if (getenv("LIBSMB_PROG")) {
995 cli
->fd
= sock_exec(getenv("LIBSMB_PROG"));
997 /* try 445 first, then 139 */
998 int port
= cli
->port
?cli
->port
:445;
999 cli
->fd
= open_socket_out(SOCK_STREAM
, &cli
->dest_ip
,
1000 port
, cli
->timeout
);
1001 if (cli
->fd
== -1 && cli
->port
== 0) {
1003 cli
->fd
= open_socket_out(SOCK_STREAM
, &cli
->dest_ip
,
1004 port
, cli
->timeout
);
1006 if (cli
->fd
!= -1) cli
->port
= port
;
1008 if (cli
->fd
== -1) {
1009 DEBUG(1,("Error connecting to %s (%s)\n",
1010 inet_ntoa(*ip
),strerror(errno
)));
1014 set_socket_options(cli
->fd
,user_socket_options
);
1019 /****************************************************************************
1020 re-establishes a connection
1021 ****************************************************************************/
1022 BOOL
cli_reestablish_connection(struct cli_state
*cli
)
1024 struct nmb_name calling
;
1025 struct nmb_name called
;
1029 BOOL do_tcon
= False
;
1030 int oldfd
= cli
->fd
;
1032 if (!cli
->initialised
|| cli
->fd
== -1)
1034 DEBUG(3,("cli_reestablish_connection: not connected\n"));
1038 /* copy the parameters necessary to re-establish the connection */
1042 fstrcpy(share
, cli
->share
);
1043 fstrcpy(dev
, cli
->dev
);
1047 memcpy(&called
, &(cli
->called
), sizeof(called
));
1048 memcpy(&calling
, &(cli
->calling
), sizeof(calling
));
1049 fstrcpy(dest_host
, cli
->full_dest_host_name
);
1051 DEBUG(5,("cli_reestablish_connection: %s connecting to %s (ip %s) - %s [%s]\n",
1052 nmb_namestr(&calling
), nmb_namestr(&called
),
1053 inet_ntoa(cli
->dest_ip
),
1054 cli
->user_name
, cli
->domain
));
1058 if (cli_establish_connection(cli
,
1059 dest_host
, &cli
->dest_ip
,
1061 share
, dev
, False
, do_tcon
)) {
1062 if ((cli
->fd
!= oldfd
) && (oldfd
!= -1)) {
1070 /****************************************************************************
1071 establishes a connection right up to doing tconX, reading in a password.
1072 ****************************************************************************/
1073 BOOL
cli_establish_connection(struct cli_state
*cli
,
1074 char *dest_host
, struct in_addr
*dest_ip
,
1075 struct nmb_name
*calling
, struct nmb_name
*called
,
1076 char *service
, char *service_type
,
1077 BOOL do_shutdown
, BOOL do_tcon
)
1079 DEBUG(5,("cli_establish_connection: %s connecting to %s (%s) - %s [%s]\n",
1080 nmb_namestr(calling
), nmb_namestr(called
), inet_ntoa(*dest_ip
),
1081 cli
->user_name
, cli
->domain
));
1083 /* establish connection */
1085 if ((!cli
->initialised
))
1090 /* cli_establish_connection() can't handle spnego yet. Once we get rid of
1091 pwd_cache and other horrors we can get rid of this */
1092 cli
->use_spnego
= False
;
1096 if (!cli_connect(cli
, dest_host
, dest_ip
))
1098 DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n",
1099 nmb_namestr(called
), inet_ntoa(*dest_ip
)));
1104 if (!cli_session_request(cli
, calling
, called
))
1106 DEBUG(1,("failed session request\n"));
1112 if (!cli_negprot(cli
))
1114 DEBUG(1,("failed negprot\n"));
1120 if (cli
->pwd
.cleartext
|| cli
->pwd
.null_pwd
)
1125 if (cli
->pwd
.null_pwd
)
1127 /* attempt null session */
1133 /* attempt clear-text session */
1134 pwd_get_cleartext(&(cli
->pwd
), passwd
);
1135 pass_len
= strlen(passwd
);
1138 /* attempt clear-text session */
1139 if (!cli_session_setup(cli
, cli
->user_name
,
1144 DEBUG(1,("failed session setup\n"));
1153 if (!cli_send_tconX(cli
, service
, service_type
,
1154 (char*)passwd
, strlen(passwd
)))
1156 DEBUG(1,("failed tcon_X\n"));
1167 /* attempt encrypted session */
1168 unsigned char nt_sess_pwd
[24];
1169 unsigned char lm_sess_pwd
[24];
1171 /* creates (storing a copy of) and then obtains a 24 byte password OWF */
1172 pwd_make_lm_nt_owf(&(cli
->pwd
), cli
->secblob
.data
);
1173 pwd_get_lm_nt_owf(&(cli
->pwd
), lm_sess_pwd
, nt_sess_pwd
);
1175 /* attempt encrypted session */
1176 if (!cli_session_setup(cli
, cli
->user_name
,
1177 (char*)lm_sess_pwd
, sizeof(lm_sess_pwd
),
1178 (char*)nt_sess_pwd
, sizeof(nt_sess_pwd
),
1181 DEBUG(1,("failed session setup\n"));
1187 DEBUG(1,("session setup ok\n"));
1189 if (*cli
->server_domain
|| *cli
->server_os
|| *cli
->server_type
)
1191 DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",
1199 if (!cli_send_tconX(cli
, service
, service_type
,
1200 (char*)nt_sess_pwd
, sizeof(nt_sess_pwd
)))
1202 DEBUG(1,("failed tcon_X\n"));
1217 /****************************************************************************
1218 Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
1219 ****************************************************************************/
1221 BOOL
attempt_netbios_session_request(struct cli_state
*cli
, char *srchost
, char *desthost
,
1222 struct in_addr
*pdest_ip
)
1224 struct nmb_name calling
, called
;
1226 make_nmb_name(&calling
, srchost
, 0x0);
1229 * If the called name is an IP address
1230 * then use *SMBSERVER immediately.
1233 if(is_ipaddress(desthost
))
1234 make_nmb_name(&called
, "*SMBSERVER", 0x20);
1236 make_nmb_name(&called
, desthost
, 0x20);
1238 if (!cli_session_request(cli
, &calling
, &called
)) {
1239 struct nmb_name smbservername
;
1241 make_nmb_name(&smbservername
, "*SMBSERVER", 0x20);
1244 * If the name wasn't *SMBSERVER then
1245 * try with *SMBSERVER if the first name fails.
1248 if (nmb_name_equal(&called
, &smbservername
)) {
1251 * The name used was *SMBSERVER, don't bother with another name.
1254 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
1255 with error %s.\n", desthost
, cli_errstr(cli
) ));
1262 if (!cli_initialise(cli
) ||
1263 !cli_connect(cli
, desthost
, pdest_ip
) ||
1264 !cli_session_request(cli
, &calling
, &smbservername
)) {
1265 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
1266 name *SMBSERVER with error %s\n", desthost
, cli_errstr(cli
) ));