2 Unix SMB/CIFS implementation.
3 client connect/disconnect routines
4 Copyright (C) Andrew Tridgell 1994-1998
5 Copyright (C) Andrew Barteltt 2001-2002
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.
31 {PROTOCOL_CORE
,"PC NETWORK PROGRAM 1.0"},
32 {PROTOCOL_COREPLUS
,"MICROSOFT NETWORKS 1.03"},
33 {PROTOCOL_LANMAN1
,"MICROSOFT NETWORKS 3.0"},
34 {PROTOCOL_LANMAN1
,"LANMAN1.0"},
35 {PROTOCOL_LANMAN2
,"LM1.2X002"},
36 {PROTOCOL_LANMAN2
,"DOS LANMAN2.1"},
37 {PROTOCOL_LANMAN2
,"Samba"},
38 {PROTOCOL_NT1
,"NT LANMAN 1.0"},
39 {PROTOCOL_NT1
,"NT LM 0.12"},
43 /****************************************************************************
44 Do an old lanman2 style session setup.
45 ****************************************************************************/
47 static BOOL
cli_session_setup_lanman2(struct cli_state
*cli
, char *user
,
48 char *pass
, int passlen
, const char *workgroup
)
53 if (passlen
> sizeof(pword
)-1) {
57 /* if in share level security then don't send a password now */
58 if (!(cli
->sec_mode
& NEGOTIATE_SECURITY_USER_LEVEL
)) {
62 if (passlen
> 0 && (cli
->sec_mode
& NEGOTIATE_SECURITY_CHALLENGE_RESPONSE
) && passlen
!= 24) {
63 /* Encrypted mode needed, and non encrypted password supplied. */
65 SMBencrypt(pass
,cli
->secblob
.data
,(uchar
*)pword
);
66 } else if ((cli
->sec_mode
& NEGOTIATE_SECURITY_CHALLENGE_RESPONSE
) && passlen
== 24) {
67 /* Encrypted mode needed, and encrypted password supplied. */
68 memcpy(pword
, pass
, passlen
);
69 } else if (passlen
> 0) {
70 /* Plaintext mode needed, assume plaintext supplied. */
71 passlen
= clistr_push(cli
, pword
, pass
, -1, STR_TERMINATE
);
74 /* send a session setup command */
75 memset(cli
->outbuf
,'\0',smb_size
);
76 set_message(cli
->outbuf
,10, 0, True
);
77 SCVAL(cli
->outbuf
,smb_com
,SMBsesssetupX
);
78 cli_setup_packet(cli
);
80 SCVAL(cli
->outbuf
,smb_vwv0
,0xFF);
81 SSVAL(cli
->outbuf
,smb_vwv2
,cli
->max_xmit
);
82 SSVAL(cli
->outbuf
,smb_vwv3
,2);
83 SSVAL(cli
->outbuf
,smb_vwv4
,1);
84 SIVAL(cli
->outbuf
,smb_vwv5
,cli
->sesskey
);
85 SSVAL(cli
->outbuf
,smb_vwv7
,passlen
);
87 p
= smb_buf(cli
->outbuf
);
88 memcpy(p
,pword
,passlen
);
90 p
+= clistr_push(cli
, p
, user
, -1, STR_TERMINATE
|STR_UPPER
);
91 p
+= clistr_push(cli
, p
, workgroup
, -1, STR_TERMINATE
|STR_UPPER
);
92 p
+= clistr_push(cli
, p
, "Unix", -1, STR_TERMINATE
);
93 p
+= clistr_push(cli
, p
, "Samba", -1, STR_TERMINATE
);
94 cli_setup_bcc(cli
, p
);
97 if (!cli_receive_smb(cli
))
100 show_msg(cli
->inbuf
);
102 if (cli_is_error(cli
)) {
106 /* use the returned vuid from now on */
107 cli
->vuid
= SVAL(cli
->inbuf
,smb_uid
);
108 fstrcpy(cli
->user_name
, user
);
113 /****************************************************************************
114 Work out suitable capabilities to offer the server.
115 ****************************************************************************/
117 static uint32
cli_session_setup_capabilities(struct cli_state
*cli
)
119 uint32 capabilities
= CAP_NT_SMBS
;
121 if (!cli
->force_dos_errors
) {
122 capabilities
|= CAP_STATUS32
;
125 if (cli
->use_level_II_oplocks
) {
126 capabilities
|= CAP_LEVEL_II_OPLOCKS
;
129 if (cli
->capabilities
& CAP_UNICODE
) {
130 capabilities
|= CAP_UNICODE
;
136 /****************************************************************************
137 Do a NT1 guest session setup.
138 ****************************************************************************/
140 static BOOL
cli_session_setup_guest(struct cli_state
*cli
)
143 uint32 capabilities
= cli_session_setup_capabilities(cli
);
145 set_message(cli
->outbuf
,13,0,True
);
146 SCVAL(cli
->outbuf
,smb_com
,SMBsesssetupX
);
147 cli_setup_packet(cli
);
149 SCVAL(cli
->outbuf
,smb_vwv0
,0xFF);
150 SSVAL(cli
->outbuf
,smb_vwv2
,CLI_BUFFER_SIZE
);
151 SSVAL(cli
->outbuf
,smb_vwv3
,2);
152 SSVAL(cli
->outbuf
,smb_vwv4
,cli
->pid
);
153 SIVAL(cli
->outbuf
,smb_vwv5
,cli
->sesskey
);
154 SSVAL(cli
->outbuf
,smb_vwv7
,0);
155 SSVAL(cli
->outbuf
,smb_vwv8
,0);
156 SIVAL(cli
->outbuf
,smb_vwv11
,capabilities
);
157 p
= smb_buf(cli
->outbuf
);
158 p
+= clistr_push(cli
, p
, "", -1, STR_TERMINATE
); /* username */
159 p
+= clistr_push(cli
, p
, "", -1, STR_TERMINATE
); /* workgroup */
160 p
+= clistr_push(cli
, p
, "Unix", -1, STR_TERMINATE
);
161 p
+= clistr_push(cli
, p
, "Samba", -1, STR_TERMINATE
);
162 cli_setup_bcc(cli
, p
);
165 if (!cli_receive_smb(cli
))
168 show_msg(cli
->inbuf
);
170 if (cli_is_error(cli
)) {
174 cli
->vuid
= SVAL(cli
->inbuf
,smb_uid
);
176 p
= smb_buf(cli
->inbuf
);
177 p
+= clistr_pull(cli
, cli
->server_os
, p
, sizeof(fstring
), -1, STR_TERMINATE
);
178 p
+= clistr_pull(cli
, cli
->server_type
, p
, sizeof(fstring
), -1, STR_TERMINATE
);
179 p
+= clistr_pull(cli
, cli
->server_domain
, p
, sizeof(fstring
), -1, STR_TERMINATE
);
181 fstrcpy(cli
->user_name
, "");
186 /****************************************************************************
187 Do a NT1 plaintext session setup.
188 ****************************************************************************/
190 static BOOL
cli_session_setup_plaintext(struct cli_state
*cli
, char *user
,
191 char *pass
, char *workgroup
)
193 uint32 capabilities
= cli_session_setup_capabilities(cli
);
198 passlen
= clistr_push(cli
, pword
, pass
, sizeof(pword
), STR_TERMINATE
|STR_ASCII
);
200 set_message(cli
->outbuf
,13,0,True
);
201 SCVAL(cli
->outbuf
,smb_com
,SMBsesssetupX
);
202 cli_setup_packet(cli
);
204 SCVAL(cli
->outbuf
,smb_vwv0
,0xFF);
205 SSVAL(cli
->outbuf
,smb_vwv2
,CLI_BUFFER_SIZE
);
206 SSVAL(cli
->outbuf
,smb_vwv3
,2);
207 SSVAL(cli
->outbuf
,smb_vwv4
,cli
->pid
);
208 SIVAL(cli
->outbuf
,smb_vwv5
,cli
->sesskey
);
209 SSVAL(cli
->outbuf
,smb_vwv8
,0);
210 SIVAL(cli
->outbuf
,smb_vwv11
,capabilities
);
211 p
= smb_buf(cli
->outbuf
);
212 p
+= clistr_push(cli
, p
, pword
, -1, STR_TERMINATE
); /* password */
213 SSVAL(cli
->outbuf
,smb_vwv7
,PTR_DIFF(p
, smb_buf(cli
->outbuf
)));
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
);
242 do a NT1 NTLM/LM encrypted session setup
243 @param cli client state to create do session setup on
245 @param pass *either* cleartext password (passlen !=24) or LM response.
246 @param ntpass NT response, implies ntpasslen >=24, implies pass is not clear
247 @param workgroup The user's domain.
250 static BOOL
cli_session_setup_nt1(struct cli_state
*cli
, char *user
,
251 char *pass
, int passlen
,
252 char *ntpass
, int ntpasslen
,
255 uint32 capabilities
= cli_session_setup_capabilities(cli
);
259 BOOL tried_signing
= False
;
261 if (passlen
> sizeof(pword
) || ntpasslen
> sizeof(ntpword
)) {
266 /* non encrypted password supplied. Ignore ntpass. */
269 SMBencrypt(pass
,cli
->secblob
.data
,pword
);
270 SMBNTencrypt(pass
,cli
->secblob
.data
,ntpword
);
271 if (!cli
->sign_info
.use_smb_signing
&& cli
->sign_info
.negotiated_smb_signing
) {
272 cli_calculate_mac_key(cli
, pass
, ntpword
);
273 tried_signing
= True
;
276 /* pre-encrypted password supplied. Only used for security=server, can't do
277 signing becouse we don't have oringial key */
278 memcpy(pword
, pass
, 24);
279 if (ntpasslen
== 24) {
280 memcpy(ntpword
, ntpass
, 24);
282 ZERO_STRUCT(ntpword
);
286 /* send a session setup command */
287 memset(cli
->outbuf
,'\0',smb_size
);
289 set_message(cli
->outbuf
,13,0,True
);
290 SCVAL(cli
->outbuf
,smb_com
,SMBsesssetupX
);
291 cli_setup_packet(cli
);
293 SCVAL(cli
->outbuf
,smb_vwv0
,0xFF);
294 SSVAL(cli
->outbuf
,smb_vwv2
,CLI_BUFFER_SIZE
);
295 SSVAL(cli
->outbuf
,smb_vwv3
,2);
296 SSVAL(cli
->outbuf
,smb_vwv4
,cli
->pid
);
297 SIVAL(cli
->outbuf
,smb_vwv5
,cli
->sesskey
);
298 SSVAL(cli
->outbuf
,smb_vwv7
,passlen
);
299 SSVAL(cli
->outbuf
,smb_vwv8
,ntpasslen
);
300 SIVAL(cli
->outbuf
,smb_vwv11
,capabilities
);
301 p
= smb_buf(cli
->outbuf
);
302 memcpy(p
,pword
,passlen
); p
+= passlen
;
303 memcpy(p
,ntpword
,ntpasslen
); p
+= ntpasslen
;
304 p
+= clistr_push(cli
, p
, user
, -1, STR_TERMINATE
|STR_UPPER
);
305 p
+= clistr_push(cli
, p
, workgroup
, -1, STR_TERMINATE
|STR_UPPER
);
306 p
+= clistr_push(cli
, p
, "Unix", -1, STR_TERMINATE
);
307 p
+= clistr_push(cli
, p
, "Samba", -1, STR_TERMINATE
);
308 cli_setup_bcc(cli
, p
);
311 if (!cli_receive_smb(cli
)) {
313 /* We only use it if we have a successful non-guest connect */
314 cli
->sign_info
.use_smb_signing
= False
;
319 show_msg(cli
->inbuf
);
321 if (tried_signing
&& (cli_is_error(cli
) || SVAL(cli
->inbuf
,smb_vwv2
) /* guest */)) {
322 /* We only use it if we have a successful non-guest connect */
323 cli
->sign_info
.use_smb_signing
= False
;
326 if (cli_is_error(cli
)) {
330 /* use the returned vuid from now on */
331 cli
->vuid
= SVAL(cli
->inbuf
,smb_uid
);
333 p
= smb_buf(cli
->inbuf
);
334 p
+= clistr_pull(cli
, cli
->server_os
, p
, sizeof(fstring
), -1, STR_TERMINATE
);
335 p
+= clistr_pull(cli
, cli
->server_type
, p
, sizeof(fstring
), -1, STR_TERMINATE
);
336 p
+= clistr_pull(cli
, cli
->server_domain
, p
, sizeof(fstring
), -1, STR_TERMINATE
);
338 fstrcpy(cli
->user_name
, user
);
343 /****************************************************************************
344 Send a extended security session setup blob, returning a reply blob.
345 ****************************************************************************/
347 static DATA_BLOB
cli_session_setup_blob(struct cli_state
*cli
, DATA_BLOB blob
)
349 uint32 capabilities
= cli_session_setup_capabilities(cli
);
354 blob2
= data_blob(NULL
, 0);
356 capabilities
|= CAP_EXTENDED_SECURITY
;
358 /* send a session setup command */
359 memset(cli
->outbuf
,'\0',smb_size
);
361 set_message(cli
->outbuf
,12,0,True
);
362 SCVAL(cli
->outbuf
,smb_com
,SMBsesssetupX
);
363 cli_setup_packet(cli
);
365 SCVAL(cli
->outbuf
,smb_vwv0
,0xFF);
366 SSVAL(cli
->outbuf
,smb_vwv2
,CLI_BUFFER_SIZE
);
367 SSVAL(cli
->outbuf
,smb_vwv3
,2);
368 SSVAL(cli
->outbuf
,smb_vwv4
,1);
369 SIVAL(cli
->outbuf
,smb_vwv5
,0);
370 SSVAL(cli
->outbuf
,smb_vwv7
,blob
.length
);
371 SIVAL(cli
->outbuf
,smb_vwv10
,capabilities
);
372 p
= smb_buf(cli
->outbuf
);
373 memcpy(p
, blob
.data
, blob
.length
);
375 p
+= clistr_push(cli
, p
, "Unix", -1, STR_TERMINATE
);
376 p
+= clistr_push(cli
, p
, "Samba", -1, STR_TERMINATE
);
377 cli_setup_bcc(cli
, p
);
380 if (!cli_receive_smb(cli
))
383 show_msg(cli
->inbuf
);
385 if (cli_is_error(cli
) && !NT_STATUS_EQUAL(cli_nt_error(cli
),
386 NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
390 /* use the returned vuid from now on */
391 cli
->vuid
= SVAL(cli
->inbuf
,smb_uid
);
393 p
= smb_buf(cli
->inbuf
);
395 blob2
= data_blob(p
, SVAL(cli
->inbuf
, smb_vwv3
));
398 p
+= clistr_pull(cli
, cli
->server_os
, p
, sizeof(fstring
), -1, STR_TERMINATE
);
400 /* w2k with kerberos doesn't properly null terminate this field */
401 len
= smb_buflen(cli
->inbuf
) - PTR_DIFF(p
, smb_buf(cli
->inbuf
));
402 p
+= clistr_pull(cli
, cli
->server_type
, p
, sizeof(fstring
), len
, 0);
409 /****************************************************************************
410 Do a spnego/kerberos encrypted session setup.
411 ****************************************************************************/
413 static BOOL
cli_session_setup_kerberos(struct cli_state
*cli
, char *principal
, char *workgroup
)
415 DATA_BLOB blob2
, negTokenTarg
;
417 DEBUG(2,("Doing kerberos session setup\n"));
419 /* generate the encapsulated kerberos5 ticket */
420 negTokenTarg
= spnego_gen_negTokenTarg(cli
, principal
);
422 if (!negTokenTarg
.data
) return False
;
425 file_save("negTokenTarg.dat", negTokenTarg
.data
, negTokenTarg
.length
);
428 blob2
= cli_session_setup_blob(cli
, negTokenTarg
);
430 /* we don't need this blob for kerberos */
431 data_blob_free(&blob2
);
433 data_blob_free(&negTokenTarg
);
435 return !cli_is_error(cli
);
439 /****************************************************************************
440 Do a spnego/NTLMSSP encrypted session setup.
441 ****************************************************************************/
443 static BOOL
cli_session_setup_ntlmssp(struct cli_state
*cli
, char *user
,
444 char *pass
, char *workgroup
)
446 const char *mechs
[] = {OID_NTLMSSP
, NULL
};
448 DATA_BLOB blob
, chal1
, chal2
, auth
;
450 uint8 nthash
[24], lmhash
[24], sess_key
[16];
453 neg_flags
= NTLMSSP_NEGOTIATE_UNICODE
|
454 NTLMSSP_NEGOTIATE_LM_KEY
|
455 NTLMSSP_NEGOTIATE_NTLM
;
457 memset(sess_key
, 0, 16);
459 /* generate the ntlmssp negotiate packet */
460 msrpc_gen(&blob
, "CddB",
466 /* and wrap it in a SPNEGO wrapper */
467 msg1
= gen_negTokenTarg(mechs
, blob
);
468 data_blob_free(&blob
);
470 /* now send that blob on its way */
471 blob
= cli_session_setup_blob(cli
, msg1
);
473 data_blob_free(&msg1
);
475 if (!NT_STATUS_EQUAL(cli_nt_error(cli
), NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
480 file_save("chal.dat", blob
.data
, blob
.length
);
483 /* the server gives us back two challenges */
484 if (!spnego_parse_challenge(blob
, &chal1
, &chal2
)) {
485 DEBUG(3,("Failed to parse challenges\n"));
489 data_blob_free(&blob
);
491 /* encrypt the password with the challenge */
492 memcpy(challenge
, chal1
.data
+ 24, 8);
493 SMBencrypt(pass
, challenge
,lmhash
);
494 SMBNTencrypt(pass
, challenge
,nthash
);
497 file_save("nthash.dat", nthash
, 24);
498 file_save("lmhash.dat", lmhash
, 24);
499 file_save("chal1.dat", chal1
.data
, chal1
.length
);
502 data_blob_free(&chal1
);
503 data_blob_free(&chal2
);
505 /* this generates the actual auth packet */
506 msrpc_gen(&blob
, "CdBBUUUBd",
517 /* wrap it in SPNEGO */
518 auth
= spnego_gen_auth(blob
);
520 data_blob_free(&blob
);
522 /* now send the auth packet and we should be done */
523 blob
= cli_session_setup_blob(cli
, auth
);
525 data_blob_free(&auth
);
526 data_blob_free(&blob
);
528 return !cli_is_error(cli
);
531 /****************************************************************************
532 Do a spnego encrypted session setup.
533 ****************************************************************************/
535 static BOOL
cli_session_setup_spnego(struct cli_state
*cli
, char *user
,
536 char *pass
, char *workgroup
)
539 char *OIDs
[ASN1_MAX_OIDS
];
542 BOOL got_kerberos_mechanism
= False
;
544 /* spnego security cannot use SMB signing (for now). */
545 cli
->sign_info
.use_smb_signing
= False
;
547 DEBUG(2,("Doing spnego session setup (blob length=%d)\n", cli
->secblob
.length
));
549 /* the server might not even do spnego */
550 if (cli
->secblob
.length
== 16) {
551 DEBUG(3,("server didn't supply a full spnego negprot\n"));
556 file_save("negprot.dat", cli
->secblob
.data
, cli
->secblob
.length
);
559 /* the server sent us the first part of the SPNEGO exchange in the negprot
561 if (!spnego_parse_negTokenInit(cli
->secblob
, guid
, OIDs
, &principal
)) {
565 /* make sure the server understands kerberos */
566 for (i
=0;OIDs
[i
];i
++) {
567 DEBUG(3,("got OID=%s\n", OIDs
[i
]));
568 if (strcmp(OIDs
[i
], OID_KERBEROS5_OLD
) == 0 ||
569 strcmp(OIDs
[i
], OID_KERBEROS5
) == 0) {
570 got_kerberos_mechanism
= True
;
574 DEBUG(3,("got principal=%s\n", principal
));
576 fstrcpy(cli
->user_name
, user
);
579 if (got_kerberos_mechanism
&& cli
->use_kerberos
) {
580 return cli_session_setup_kerberos(cli
, principal
, workgroup
);
588 return cli_session_setup_ntlmssp(cli
, user
, pass
, workgroup
);
591 /****************************************************************************
592 Send a session setup. The username and workgroup is in UNIX character
593 format and must be converted to DOS codepage format before sending. If the
594 password is in plaintext, the same should be done.
595 ****************************************************************************/
597 BOOL
cli_session_setup(struct cli_state
*cli
,
599 char *pass
, int passlen
,
600 char *ntpass
, int ntpasslen
,
606 /* allow for workgroups as part of the username */
607 fstrcpy(user2
, user
);
608 if ((p
=strchr_m(user2
,'\\')) || (p
=strchr_m(user2
,'/')) ||
609 (p
=strchr_m(user2
,*lp_winbind_separator()))) {
615 if (cli
->protocol
< PROTOCOL_LANMAN1
)
618 /* now work out what sort of session setup we are going to
619 do. I have split this into separate functions to make the
620 flow a bit easier to understand (tridge) */
622 /* if its an older server then we have to use the older request format */
623 if (cli
->protocol
< PROTOCOL_NT1
) {
624 return cli_session_setup_lanman2(cli
, user
, pass
, passlen
, workgroup
);
627 /* if no user is supplied then we have to do an anonymous connection.
628 passwords are ignored */
629 if (!user
|| !*user
) {
630 return cli_session_setup_guest(cli
);
633 /* if the server is share level then send a plaintext null
634 password at this point. The password is sent in the tree
636 if ((cli
->sec_mode
& NEGOTIATE_SECURITY_USER_LEVEL
) == 0) {
637 return cli_session_setup_plaintext(cli
, user
, "", workgroup
);
640 /* if the server doesn't support encryption then we have to use
641 plaintext. The second password is ignored */
642 if ((cli
->sec_mode
& NEGOTIATE_SECURITY_CHALLENGE_RESPONSE
) == 0) {
643 return cli_session_setup_plaintext(cli
, user
, pass
, workgroup
);
646 /* if the server supports extended security then use SPNEGO */
647 if (cli
->capabilities
& CAP_EXTENDED_SECURITY
) {
648 return cli_session_setup_spnego(cli
, user
, pass
, workgroup
);
651 /* otherwise do a NT1 style session setup */
652 return cli_session_setup_nt1(cli
, user
,
653 pass
, passlen
, ntpass
, ntpasslen
,
657 /****************************************************************************
659 *****************************************************************************/
661 BOOL
cli_ulogoff(struct cli_state
*cli
)
663 memset(cli
->outbuf
,'\0',smb_size
);
664 set_message(cli
->outbuf
,2,0,True
);
665 SCVAL(cli
->outbuf
,smb_com
,SMBulogoffX
);
666 cli_setup_packet(cli
);
667 SSVAL(cli
->outbuf
,smb_vwv0
,0xFF);
668 SSVAL(cli
->outbuf
,smb_vwv2
,0); /* no additional info */
671 if (!cli_receive_smb(cli
))
674 return !cli_is_error(cli
);
677 /****************************************************************************
679 ****************************************************************************/
681 BOOL
cli_send_tconX(struct cli_state
*cli
,
682 const char *share
, const char *dev
, const char *pass
, int passlen
)
684 fstring fullshare
, pword
;
686 memset(cli
->outbuf
,'\0',smb_size
);
687 memset(cli
->inbuf
,'\0',smb_size
);
689 fstrcpy(cli
->share
, share
);
691 /* in user level security don't send a password now */
692 if (cli
->sec_mode
& NEGOTIATE_SECURITY_USER_LEVEL
) {
697 if ((cli
->sec_mode
& NEGOTIATE_SECURITY_CHALLENGE_RESPONSE
) && *pass
&& passlen
!= 24) {
699 * Non-encrypted passwords - convert to DOS codepage before encryption.
702 SMBencrypt(pass
,cli
->secblob
.data
,(uchar
*)pword
);
704 if((cli
->sec_mode
& (NEGOTIATE_SECURITY_USER_LEVEL
|NEGOTIATE_SECURITY_CHALLENGE_RESPONSE
)) == 0) {
706 * Non-encrypted passwords - convert to DOS codepage before using.
708 passlen
= clistr_push(cli
, pword
, pass
, -1, STR_TERMINATE
);
710 memcpy(pword
, pass
, passlen
);
714 if (cli
->port
== 445) {
715 slprintf(fullshare
, sizeof(fullshare
)-1,
718 slprintf(fullshare
, sizeof(fullshare
)-1,
719 "\\\\%s\\%s", cli
->desthost
, share
);
722 set_message(cli
->outbuf
,4, 0, True
);
723 SCVAL(cli
->outbuf
,smb_com
,SMBtconX
);
724 cli_setup_packet(cli
);
726 SSVAL(cli
->outbuf
,smb_vwv0
,0xFF);
727 SSVAL(cli
->outbuf
,smb_vwv3
,passlen
);
729 p
= smb_buf(cli
->outbuf
);
730 memcpy(p
,pword
,passlen
);
732 p
+= clistr_push(cli
, p
, fullshare
, -1, STR_TERMINATE
|STR_UPPER
);
733 fstrcpy(p
, dev
); p
+= strlen(dev
)+1;
735 cli_setup_bcc(cli
, p
);
738 if (!cli_receive_smb(cli
))
741 if (cli_is_error(cli
)) {
745 clistr_pull(cli
, cli
->dev
, smb_buf(cli
->inbuf
), sizeof(fstring
), -1, STR_TERMINATE
|STR_ASCII
);
747 if (strcasecmp(share
,"IPC$")==0) {
748 fstrcpy(cli
->dev
, "IPC");
751 if (cli
->protocol
>= PROTOCOL_NT1
&&
752 smb_buflen(cli
->inbuf
) == 3) {
753 /* almost certainly win95 - enable bug fixes */
757 cli
->cnum
= SVAL(cli
->inbuf
,smb_tid
);
761 /****************************************************************************
762 Send a tree disconnect.
763 ****************************************************************************/
765 BOOL
cli_tdis(struct cli_state
*cli
)
767 memset(cli
->outbuf
,'\0',smb_size
);
768 set_message(cli
->outbuf
,0,0,True
);
769 SCVAL(cli
->outbuf
,smb_com
,SMBtdis
);
770 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
771 cli_setup_packet(cli
);
774 if (!cli_receive_smb(cli
))
777 return !cli_is_error(cli
);
780 /****************************************************************************
781 Send a negprot command.
782 ****************************************************************************/
784 void cli_negprot_send(struct cli_state
*cli
)
789 if (cli
->protocol
< PROTOCOL_NT1
) {
790 cli
->use_spnego
= False
;
793 memset(cli
->outbuf
,'\0',smb_size
);
795 /* setup the protocol strings */
796 set_message(cli
->outbuf
,0,0,True
);
798 p
= smb_buf(cli
->outbuf
);
800 prots
[numprots
].name
&& prots
[numprots
].prot
<=cli
->protocol
;
803 p
+= clistr_push(cli
, p
, prots
[numprots
].name
, -1, STR_TERMINATE
);
806 SCVAL(cli
->outbuf
,smb_com
,SMBnegprot
);
807 cli_setup_bcc(cli
, p
);
808 cli_setup_packet(cli
);
810 SCVAL(smb_buf(cli
->outbuf
),0,2);
815 /****************************************************************************
816 Send a negprot command.
817 ****************************************************************************/
819 BOOL
cli_negprot(struct cli_state
*cli
)
825 if (cli
->sign_info
.use_smb_signing
) {
826 DEBUG(0, ("Cannot send negprot again, particularly after setting up SMB Signing\n"));
830 if (cli
->protocol
< PROTOCOL_NT1
) {
831 cli
->use_spnego
= False
;
834 memset(cli
->outbuf
,'\0',smb_size
);
836 /* setup the protocol strings */
837 for (plength
=0,numprots
=0;
838 prots
[numprots
].name
&& prots
[numprots
].prot
<=cli
->protocol
;
840 plength
+= strlen(prots
[numprots
].name
)+2;
842 set_message(cli
->outbuf
,0,plength
,True
);
844 p
= smb_buf(cli
->outbuf
);
846 prots
[numprots
].name
&& prots
[numprots
].prot
<=cli
->protocol
;
849 p
+= clistr_push(cli
, p
, prots
[numprots
].name
, -1, STR_TERMINATE
);
852 SCVAL(cli
->outbuf
,smb_com
,SMBnegprot
);
853 cli_setup_packet(cli
);
855 SCVAL(smb_buf(cli
->outbuf
),0,2);
858 if (!cli_receive_smb(cli
))
861 show_msg(cli
->inbuf
);
863 if (cli_is_error(cli
) ||
864 ((int)SVAL(cli
->inbuf
,smb_vwv0
) >= numprots
)) {
868 cli
->protocol
= prots
[SVAL(cli
->inbuf
,smb_vwv0
)].prot
;
870 if (cli
->protocol
>= PROTOCOL_NT1
) {
872 cli
->sec_mode
= CVAL(cli
->inbuf
,smb_vwv1
);
873 cli
->max_mux
= SVAL(cli
->inbuf
, smb_vwv1
+1);
874 cli
->max_xmit
= IVAL(cli
->inbuf
,smb_vwv3
+1);
875 cli
->sesskey
= IVAL(cli
->inbuf
,smb_vwv7
+1);
876 cli
->serverzone
= SVALS(cli
->inbuf
,smb_vwv15
+1);
877 cli
->serverzone
*= 60;
878 /* this time arrives in real GMT */
879 cli
->servertime
= interpret_long_date(cli
->inbuf
+smb_vwv11
+1);
880 cli
->secblob
= data_blob(smb_buf(cli
->inbuf
),smb_buflen(cli
->inbuf
));
881 cli
->capabilities
= IVAL(cli
->inbuf
,smb_vwv9
+1);
882 if (cli
->capabilities
& CAP_RAW_MODE
) {
883 cli
->readbraw_supported
= True
;
884 cli
->writebraw_supported
= True
;
886 /* work out if they sent us a workgroup */
887 if (!(cli
->capabilities
& CAP_EXTENDED_SECURITY
) &&
888 smb_buflen(cli
->inbuf
) > 8) {
889 clistr_pull(cli
, cli
->server_domain
,
890 smb_buf(cli
->inbuf
)+8, sizeof(cli
->server_domain
),
891 smb_buflen(cli
->inbuf
)-8, STR_UNICODE
|STR_NOALIGN
);
894 /* A way to attempt to force SMB signing */
895 if (getenv("CLI_FORCE_SMB_SIGNING"))
896 cli
->sign_info
.negotiated_smb_signing
= True
;
898 if (cli
->sign_info
.negotiated_smb_signing
&& !(cli
->sec_mode
& NEGOTIATE_SECURITY_SIGNATURES_ENABLED
))
899 cli
->sign_info
.negotiated_smb_signing
= False
;
901 } else if (cli
->protocol
>= PROTOCOL_LANMAN1
) {
902 cli
->use_spnego
= False
;
903 cli
->sec_mode
= SVAL(cli
->inbuf
,smb_vwv1
);
904 cli
->max_xmit
= SVAL(cli
->inbuf
,smb_vwv2
);
905 cli
->sesskey
= IVAL(cli
->inbuf
,smb_vwv6
);
906 cli
->serverzone
= SVALS(cli
->inbuf
,smb_vwv10
);
907 cli
->serverzone
*= 60;
908 /* this time is converted to GMT by make_unix_date */
909 cli
->servertime
= make_unix_date(cli
->inbuf
+smb_vwv8
);
910 cli
->readbraw_supported
= ((SVAL(cli
->inbuf
,smb_vwv5
) & 0x1) != 0);
911 cli
->writebraw_supported
= ((SVAL(cli
->inbuf
,smb_vwv5
) & 0x2) != 0);
912 cli
->secblob
= data_blob(smb_buf(cli
->inbuf
),smb_buflen(cli
->inbuf
));
914 /* the old core protocol */
915 cli
->use_spnego
= False
;
917 cli
->serverzone
= TimeDiff(time(NULL
));
920 cli
->max_xmit
= MIN(cli
->max_xmit
, CLI_BUFFER_SIZE
);
922 /* a way to force ascii SMB */
923 if (getenv("CLI_FORCE_ASCII")) {
924 cli
->capabilities
&= ~CAP_UNICODE
;
930 /****************************************************************************
931 Send a session request. See rfc1002.txt 4.3 and 4.3.2.
932 ****************************************************************************/
934 BOOL
cli_session_request(struct cli_state
*cli
,
935 struct nmb_name
*calling
, struct nmb_name
*called
)
939 extern pstring user_socket_options
;
941 /* 445 doesn't have session request */
942 if (cli
->port
== 445) return True
;
944 if (cli
->sign_info
.use_smb_signing
) {
945 DEBUG(0, ("Cannot send session resquest again, particularly after setting up SMB Signing\n"));
949 /* send a session request (RFC 1002) */
950 memcpy(&(cli
->calling
), calling
, sizeof(*calling
));
951 memcpy(&(cli
->called
), called
, sizeof(*called
));
953 /* put in the destination name */
955 name_mangle(cli
->called
.name
, p
, cli
->called
.name_type
);
960 name_mangle(cli
->calling
.name
, p
, cli
->calling
.name_type
);
963 /* setup the packet length
964 * Remove four bytes from the length count, since the length
965 * field in the NBT Session Service header counts the number
966 * of bytes which follow. The cli_send_smb() function knows
967 * about this and accounts for those four bytes.
971 _smb_setlen(cli
->outbuf
,len
);
972 SCVAL(cli
->outbuf
,0,0x81);
975 DEBUG(5,("Sent session request\n"));
977 if (!cli_receive_smb(cli
))
980 if (CVAL(cli
->inbuf
,0) == 0x84) {
981 /* C. Hoch 9/14/95 Start */
982 /* For information, here is the response structure.
983 * We do the byte-twiddling to for portability.
984 struct RetargetResponse{
992 int port
= (CVAL(cli
->inbuf
,8)<<8)+CVAL(cli
->inbuf
,9);
993 /* SESSION RETARGET */
994 putip((char *)&cli
->dest_ip
,cli
->inbuf
+4);
996 cli
->fd
= open_socket_out(SOCK_STREAM
, &cli
->dest_ip
, port
, LONG_CONNECT_TIMEOUT
);
1000 DEBUG(3,("Retargeted\n"));
1002 set_socket_options(cli
->fd
,user_socket_options
);
1009 DEBUG(0,("Retarget recursion - failing\n"));
1013 ret
= cli_session_request(cli
, calling
, called
);
1017 } /* C. Hoch 9/14/95 End */
1019 if (CVAL(cli
->inbuf
,0) != 0x82) {
1020 /* This is the wrong place to put the error... JRA. */
1021 cli
->rap_error
= CVAL(cli
->inbuf
,4);
1027 /****************************************************************************
1028 Open the client sockets.
1029 ****************************************************************************/
1031 BOOL
cli_connect(struct cli_state
*cli
, const char *host
, struct in_addr
*ip
)
1033 extern pstring user_socket_options
;
1034 int name_type
= 0x20;
1037 /* reasonable default hostname */
1038 if (!host
) host
= "*SMBSERVER";
1040 fstrcpy(cli
->desthost
, host
);
1042 /* allow hostnames of the form NAME#xx and do a netbios lookup */
1043 if ((p
= strchr(cli
->desthost
, '#'))) {
1044 name_type
= strtol(p
+1, NULL
, 16);
1048 if (!ip
|| is_zero_ip(*ip
)) {
1049 if (!resolve_name(cli
->desthost
, &cli
->dest_ip
, name_type
)) {
1052 if (ip
) *ip
= cli
->dest_ip
;
1057 if (getenv("LIBSMB_PROG")) {
1058 cli
->fd
= sock_exec(getenv("LIBSMB_PROG"));
1060 /* try 445 first, then 139 */
1061 int port
= cli
->port
?cli
->port
:445;
1062 cli
->fd
= open_socket_out(SOCK_STREAM
, &cli
->dest_ip
,
1063 port
, cli
->timeout
);
1064 if (cli
->fd
== -1 && cli
->port
== 0) {
1066 cli
->fd
= open_socket_out(SOCK_STREAM
, &cli
->dest_ip
,
1067 port
, cli
->timeout
);
1069 if (cli
->fd
!= -1) cli
->port
= port
;
1071 if (cli
->fd
== -1) {
1072 DEBUG(1,("Error connecting to %s (%s)\n",
1073 ip
?inet_ntoa(*ip
):host
,strerror(errno
)));
1077 set_socket_options(cli
->fd
,user_socket_options
);
1082 /****************************************************************************
1083 Initialise client credentials for authenticated pipe access.
1084 ****************************************************************************/
1086 static void init_creds(struct ntuser_creds
*creds
, char* username
,
1087 char* domain
, char* password
)
1089 ZERO_STRUCTP(creds
);
1091 pwd_set_cleartext(&creds
->pwd
, password
);
1093 fstrcpy(creds
->user_name
, username
);
1094 fstrcpy(creds
->domain
, domain
);
1097 creds
->pwd
.null_pwd
= True
;
1102 establishes a connection right up to doing tconX, password specified.
1103 @param output_cli A fully initialised cli structure, non-null only on success
1104 @param dest_host The netbios name of the remote host
1105 @param dest_ip (optional) The the destination IP, NULL for name based lookup
1106 @param port (optional) The destination port (0 for default)
1107 @param service (optional) The share to make the connection to. Should be 'unqualified' in any way.
1108 @param service_type The 'type' of serivice.
1109 @param user Username, unix string
1110 @param domain User's domain
1111 @param password User's password, unencrypted unix string.
1114 NTSTATUS
cli_full_connection(struct cli_state
**output_cli
,
1115 const char *my_name
,
1116 const char *dest_host
,
1117 struct in_addr
*dest_ip
, int port
,
1118 char *service
, char *service_type
,
1119 char *user
, char *domain
,
1120 char *password
, int flags
)
1122 struct ntuser_creds creds
;
1124 struct nmb_name calling
;
1125 struct nmb_name called
;
1126 struct cli_state
*cli
;
1128 extern pstring global_myname
;
1131 my_name
= global_myname
;
1133 if (!(cli
= cli_initialise(NULL
)))
1134 return NT_STATUS_NO_MEMORY
;
1136 make_nmb_name(&calling
, my_name
, 0x0);
1137 make_nmb_name(&called
, dest_host
, 0x20);
1139 if (cli_set_port(cli
, port
) != port
) {
1141 return NT_STATUS_UNSUCCESSFUL
;
1152 DEBUG(3,("Connecting to host=%s share=%s\n", dest_host
, service
));
1154 if (!cli_connect(cli
, dest_host
, &ip
)) {
1155 DEBUG(1,("cli_full_connection: failed to connect to %s (%s)\n",
1156 nmb_namestr(&called
), inet_ntoa(ip
)));
1158 return NT_STATUS_UNSUCCESSFUL
;
1161 if (!cli_session_request(cli
, &calling
, &called
)) {
1163 DEBUG(1,("session request to %s failed (%s)\n",
1164 called
.name
, cli_errstr(cli
)));
1166 if ((p
=strchr(called
.name
, '.'))) {
1170 if (strcmp(called
.name
, "*SMBSERVER")) {
1171 make_nmb_name(&called
, "*SMBSERVER", 0x20);
1174 return NT_STATUS_UNSUCCESSFUL
;
1177 if (flags
& CLI_FULL_CONNECTION_DONT_SPNEGO
) {
1178 cli
->use_spnego
= False
;
1179 } else if (flags
& CLI_FULL_CONNECTION_USE_KERBEROS
) {
1180 cli
->use_kerberos
= True
;
1183 if (!cli_negprot(cli
)) {
1184 DEBUG(1,("failed negprot\n"));
1185 nt_status
= NT_STATUS_UNSUCCESSFUL
;
1190 if (!cli_session_setup(cli
, user
, password
, strlen(password
)+1,
1191 password
, strlen(password
)+1,
1193 if ((flags
& CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK
)
1194 && cli_session_setup(cli
, "", "", 0, "", 0, domain
)) {
1196 nt_status
= cli_nt_error(cli
);
1197 DEBUG(1,("failed session setup with %s\n", nt_errstr(nt_status
)));
1199 if (NT_STATUS_IS_OK(nt_status
))
1200 nt_status
= NT_STATUS_UNSUCCESSFUL
;
1206 if (!cli_send_tconX(cli
, service
, service_type
,
1207 (char*)password
, strlen(password
)+1)) {
1208 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(nt_status
)));
1209 nt_status
= cli_nt_error(cli
);
1211 if (NT_STATUS_IS_OK(nt_status
)) {
1212 nt_status
= NT_STATUS_UNSUCCESSFUL
;
1218 init_creds(&creds
, user
, domain
, password
);
1219 cli_init_creds(cli
, &creds
);
1222 return NT_STATUS_OK
;
1225 /****************************************************************************
1226 Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
1227 ****************************************************************************/
1229 BOOL
attempt_netbios_session_request(struct cli_state
*cli
, char *srchost
, char *desthost
,
1230 struct in_addr
*pdest_ip
)
1232 struct nmb_name calling
, called
;
1234 make_nmb_name(&calling
, srchost
, 0x0);
1237 * If the called name is an IP address
1238 * then use *SMBSERVER immediately.
1241 if(is_ipaddress(desthost
))
1242 make_nmb_name(&called
, "*SMBSERVER", 0x20);
1244 make_nmb_name(&called
, desthost
, 0x20);
1246 if (!cli_session_request(cli
, &calling
, &called
)) {
1247 struct nmb_name smbservername
;
1249 make_nmb_name(&smbservername
, "*SMBSERVER", 0x20);
1252 * If the name wasn't *SMBSERVER then
1253 * try with *SMBSERVER if the first name fails.
1256 if (nmb_name_equal(&called
, &smbservername
)) {
1259 * The name used was *SMBSERVER, don't bother with another name.
1262 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
1263 with error %s.\n", desthost
, cli_errstr(cli
) ));
1270 if (!cli_initialise(cli
) ||
1271 !cli_connect(cli
, desthost
, pdest_ip
) ||
1272 !cli_session_request(cli
, &calling
, &smbservername
)) {
1273 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
1274 name *SMBSERVER with error %s\n", desthost
, cli_errstr(cli
) ));