2 Unix SMB/CIFS implementation.
3 client connect/disconnect routines
4 Copyright (C) Andrew Tridgell 1994-1998
5 Copyright (C) Andrew Bartlett 2001-2003
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
, const char *user
,
48 const char *pass
, size_t passlen
, const char *workgroup
)
53 if (passlen
> sizeof(pword
)-1)
56 /* LANMAN servers predate NT status codes and Unicode and ignore those
57 smb flags so we must disable the corresponding default capabilities
58 that would otherwise cause the Unicode and NT Status flags to be
59 set (and even returned by the server) */
61 cli
->capabilities
&= ~(CAP_UNICODE
| CAP_STATUS32
);
63 /* if in share level security then don't send a password now */
64 if (!(cli
->sec_mode
& NEGOTIATE_SECURITY_USER_LEVEL
))
67 if (passlen
> 0 && (cli
->sec_mode
& NEGOTIATE_SECURITY_CHALLENGE_RESPONSE
) && passlen
!= 24) {
68 /* Encrypted mode needed, and non encrypted password supplied. */
70 SMBencrypt(pass
,cli
->secblob
.data
,(uchar
*)pword
);
71 } else if ((cli
->sec_mode
& NEGOTIATE_SECURITY_CHALLENGE_RESPONSE
) && passlen
== 24) {
72 /* Encrypted mode needed, and encrypted password supplied. */
73 memcpy(pword
, pass
, passlen
);
74 } else if (passlen
> 0) {
75 /* Plaintext mode needed, assume plaintext supplied. */
76 passlen
= clistr_push(cli
, pword
, pass
, sizeof(pword
), STR_TERMINATE
);
79 /* send a session setup command */
80 memset(cli
->outbuf
,'\0',smb_size
);
81 set_message(cli
->outbuf
,10, 0, True
);
82 SCVAL(cli
->outbuf
,smb_com
,SMBsesssetupX
);
83 cli_setup_packet(cli
);
85 SCVAL(cli
->outbuf
,smb_vwv0
,0xFF);
86 SSVAL(cli
->outbuf
,smb_vwv2
,cli
->max_xmit
);
87 SSVAL(cli
->outbuf
,smb_vwv3
,2);
88 SSVAL(cli
->outbuf
,smb_vwv4
,1);
89 SIVAL(cli
->outbuf
,smb_vwv5
,cli
->sesskey
);
90 SSVAL(cli
->outbuf
,smb_vwv7
,passlen
);
92 p
= smb_buf(cli
->outbuf
);
93 memcpy(p
,pword
,passlen
);
95 p
+= clistr_push(cli
, p
, user
, -1, STR_TERMINATE
|STR_UPPER
);
96 p
+= clistr_push(cli
, p
, workgroup
, -1, STR_TERMINATE
|STR_UPPER
);
97 p
+= clistr_push(cli
, p
, "Unix", -1, STR_TERMINATE
);
98 p
+= clistr_push(cli
, p
, "Samba", -1, STR_TERMINATE
);
99 cli_setup_bcc(cli
, p
);
102 if (!cli_receive_smb(cli
))
105 show_msg(cli
->inbuf
);
107 if (cli_is_error(cli
))
110 /* use the returned vuid from now on */
111 cli
->vuid
= SVAL(cli
->inbuf
,smb_uid
);
112 fstrcpy(cli
->user_name
, user
);
117 /****************************************************************************
118 Work out suitable capabilities to offer the server.
119 ****************************************************************************/
121 static uint32
cli_session_setup_capabilities(struct cli_state
*cli
)
123 uint32 capabilities
= CAP_NT_SMBS
;
125 if (!cli
->force_dos_errors
)
126 capabilities
|= CAP_STATUS32
;
128 if (cli
->use_level_II_oplocks
)
129 capabilities
|= CAP_LEVEL_II_OPLOCKS
;
131 if (cli
->capabilities
& CAP_UNICODE
)
132 capabilities
|= CAP_UNICODE
;
134 if (cli
->capabilities
& CAP_LARGE_FILES
)
135 capabilities
|= CAP_LARGE_FILES
;
140 /****************************************************************************
141 Do a NT1 guest session setup.
142 ****************************************************************************/
144 static BOOL
cli_session_setup_guest(struct cli_state
*cli
)
147 uint32 capabilities
= cli_session_setup_capabilities(cli
);
149 set_message(cli
->outbuf
,13,0,True
);
150 SCVAL(cli
->outbuf
,smb_com
,SMBsesssetupX
);
151 cli_setup_packet(cli
);
153 SCVAL(cli
->outbuf
,smb_vwv0
,0xFF);
154 SSVAL(cli
->outbuf
,smb_vwv2
,CLI_BUFFER_SIZE
);
155 SSVAL(cli
->outbuf
,smb_vwv3
,2);
156 SSVAL(cli
->outbuf
,smb_vwv4
,cli
->pid
);
157 SIVAL(cli
->outbuf
,smb_vwv5
,cli
->sesskey
);
158 SSVAL(cli
->outbuf
,smb_vwv7
,0);
159 SSVAL(cli
->outbuf
,smb_vwv8
,0);
160 SIVAL(cli
->outbuf
,smb_vwv11
,capabilities
);
161 p
= smb_buf(cli
->outbuf
);
162 p
+= clistr_push(cli
, p
, "", -1, STR_TERMINATE
); /* username */
163 p
+= clistr_push(cli
, p
, "", -1, STR_TERMINATE
); /* workgroup */
164 p
+= clistr_push(cli
, p
, "Unix", -1, STR_TERMINATE
);
165 p
+= clistr_push(cli
, p
, "Samba", -1, STR_TERMINATE
);
166 cli_setup_bcc(cli
, p
);
169 if (!cli_receive_smb(cli
))
172 show_msg(cli
->inbuf
);
174 if (cli_is_error(cli
))
177 cli
->vuid
= SVAL(cli
->inbuf
,smb_uid
);
179 p
= smb_buf(cli
->inbuf
);
180 p
+= clistr_pull(cli
, cli
->server_os
, p
, sizeof(fstring
), -1, STR_TERMINATE
);
181 p
+= clistr_pull(cli
, cli
->server_type
, p
, sizeof(fstring
), -1, STR_TERMINATE
);
182 p
+= clistr_pull(cli
, cli
->server_domain
, p
, sizeof(fstring
), -1, STR_TERMINATE
);
184 fstrcpy(cli
->user_name
, "");
189 /****************************************************************************
190 Do a NT1 plaintext session setup.
191 ****************************************************************************/
193 static BOOL
cli_session_setup_plaintext(struct cli_state
*cli
, const char *user
,
194 const char *pass
, const char *workgroup
)
196 uint32 capabilities
= cli_session_setup_capabilities(cli
);
200 fstr_sprintf( lanman
, "Samba %s", SAMBA_VERSION_STRING
);
202 set_message(cli
->outbuf
,13,0,True
);
203 SCVAL(cli
->outbuf
,smb_com
,SMBsesssetupX
);
204 cli_setup_packet(cli
);
206 SCVAL(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_vwv8
,0);
212 SIVAL(cli
->outbuf
,smb_vwv11
,capabilities
);
213 p
= smb_buf(cli
->outbuf
);
215 /* check wether to send the ASCII or UNICODE version of the password */
217 if ( (capabilities
& CAP_UNICODE
) == 0 ) {
218 p
+= clistr_push(cli
, p
, pass
, -1, STR_TERMINATE
); /* password */
219 SSVAL(cli
->outbuf
,smb_vwv7
,PTR_DIFF(p
, smb_buf(cli
->outbuf
)));
222 p
+= clistr_push(cli
, p
, pass
, -1, STR_UNICODE
|STR_TERMINATE
); /* unicode password */
223 SSVAL(cli
->outbuf
,smb_vwv8
,PTR_DIFF(p
, smb_buf(cli
->outbuf
)));
226 p
+= clistr_push(cli
, p
, user
, -1, STR_TERMINATE
); /* username */
227 p
+= clistr_push(cli
, p
, workgroup
, -1, STR_TERMINATE
); /* workgroup */
228 p
+= clistr_push(cli
, p
, "Unix", -1, STR_TERMINATE
);
229 p
+= clistr_push(cli
, p
, lanman
, -1, STR_TERMINATE
);
230 cli_setup_bcc(cli
, p
);
233 if (!cli_receive_smb(cli
))
236 show_msg(cli
->inbuf
);
238 if (cli_is_error(cli
))
241 cli
->vuid
= SVAL(cli
->inbuf
,smb_uid
);
242 p
= smb_buf(cli
->inbuf
);
243 p
+= clistr_pull(cli
, cli
->server_os
, p
, sizeof(fstring
), -1, STR_TERMINATE
);
244 p
+= clistr_pull(cli
, cli
->server_type
, p
, sizeof(fstring
), -1, STR_TERMINATE
);
245 p
+= clistr_pull(cli
, cli
->server_domain
, p
, sizeof(fstring
), -1, STR_TERMINATE
);
246 fstrcpy(cli
->user_name
, user
);
252 * Set the user session key for a connection
253 * @param cli The cli structure to add it too
254 * @param session_key The session key used. (A copy of this is taken for the cli struct)
258 static void cli_set_session_key (struct cli_state
*cli
, const DATA_BLOB session_key
)
260 cli
->user_session_key
= data_blob(session_key
.data
, session_key
.length
);
263 /****************************************************************************
264 do a NT1 NTLM/LM encrypted session setup - for when extended security
266 @param cli client state to create do session setup on
268 @param pass *either* cleartext password (passlen !=24) or LM response.
269 @param ntpass NT response, implies ntpasslen >=24, implies pass is not clear
270 @param workgroup The user's domain.
271 ****************************************************************************/
273 static BOOL
cli_session_setup_nt1(struct cli_state
*cli
, const char *user
,
274 const char *pass
, size_t passlen
,
275 const char *ntpass
, size_t ntpasslen
,
276 const char *workgroup
)
278 uint32 capabilities
= cli_session_setup_capabilities(cli
);
279 DATA_BLOB lm_response
= data_blob(NULL
, 0);
280 DATA_BLOB nt_response
= data_blob(NULL
, 0);
281 DATA_BLOB session_key
= data_blob(NULL
, 0);
286 /* do nothing - guest login */
287 } else if (passlen
!= 24) {
288 if (lp_client_ntlmv2_auth()) {
289 DATA_BLOB server_chal
;
290 DATA_BLOB names_blob
;
291 server_chal
= data_blob(cli
->secblob
.data
, MIN(cli
->secblob
.length
, 8));
293 /* note that the 'workgroup' here is a best guess - we don't know
294 the server's domain at this point. The 'server name' is also
297 names_blob
= NTLMv2_generate_names_blob(cli
->called
.name
, workgroup
);
299 if (!SMBNTLMv2encrypt(user
, workgroup
, pass
, &server_chal
,
301 &lm_response
, &nt_response
, &session_key
)) {
302 data_blob_free(&names_blob
);
303 data_blob_free(&server_chal
);
306 data_blob_free(&names_blob
);
307 data_blob_free(&server_chal
);
311 E_md4hash(pass
, nt_hash
);
313 nt_response
= data_blob(NULL
, 24);
314 SMBNTencrypt(pass
,cli
->secblob
.data
,nt_response
.data
);
316 /* non encrypted password supplied. Ignore ntpass. */
317 if (lp_client_lanman_auth()) {
318 lm_response
= data_blob(NULL
, 24);
319 SMBencrypt(pass
,cli
->secblob
.data
, lm_response
.data
);
321 /* LM disabled, place NT# in LM field instead */
322 lm_response
= data_blob(nt_response
.data
, nt_response
.length
);
325 session_key
= data_blob(NULL
, 16);
326 SMBsesskeygen_ntv1(nt_hash
, NULL
, session_key
.data
);
328 cli_simple_set_signing(cli
, session_key
, nt_response
, 0);
330 /* pre-encrypted password supplied. Only used for
331 security=server, can't do
332 signing because we don't have original key */
334 lm_response
= data_blob(pass
, passlen
);
335 nt_response
= data_blob(ntpass
, ntpasslen
);
338 /* send a session setup command */
339 memset(cli
->outbuf
,'\0',smb_size
);
341 set_message(cli
->outbuf
,13,0,True
);
342 SCVAL(cli
->outbuf
,smb_com
,SMBsesssetupX
);
343 cli_setup_packet(cli
);
345 SCVAL(cli
->outbuf
,smb_vwv0
,0xFF);
346 SSVAL(cli
->outbuf
,smb_vwv2
,CLI_BUFFER_SIZE
);
347 SSVAL(cli
->outbuf
,smb_vwv3
,2);
348 SSVAL(cli
->outbuf
,smb_vwv4
,cli
->pid
);
349 SIVAL(cli
->outbuf
,smb_vwv5
,cli
->sesskey
);
350 SSVAL(cli
->outbuf
,smb_vwv7
,lm_response
.length
);
351 SSVAL(cli
->outbuf
,smb_vwv8
,nt_response
.length
);
352 SIVAL(cli
->outbuf
,smb_vwv11
,capabilities
);
353 p
= smb_buf(cli
->outbuf
);
354 if (lm_response
.length
) {
355 memcpy(p
,lm_response
.data
, lm_response
.length
); p
+= lm_response
.length
;
357 if (nt_response
.length
) {
358 memcpy(p
,nt_response
.data
, nt_response
.length
); p
+= nt_response
.length
;
360 p
+= clistr_push(cli
, p
, user
, -1, STR_TERMINATE
);
361 p
+= clistr_push(cli
, p
, workgroup
, -1, STR_TERMINATE
);
362 p
+= clistr_push(cli
, p
, "Unix", -1, STR_TERMINATE
);
363 p
+= clistr_push(cli
, p
, "Samba", -1, STR_TERMINATE
);
364 cli_setup_bcc(cli
, p
);
366 if (!cli_send_smb(cli
) || !cli_receive_smb(cli
)) {
371 /* show_msg(cli->inbuf); */
373 if (cli_is_error(cli
)) {
378 /* use the returned vuid from now on */
379 cli
->vuid
= SVAL(cli
->inbuf
,smb_uid
);
381 p
= smb_buf(cli
->inbuf
);
382 p
+= clistr_pull(cli
, cli
->server_os
, p
, sizeof(fstring
), -1, STR_TERMINATE
);
383 p
+= clistr_pull(cli
, cli
->server_type
, p
, sizeof(fstring
), -1, STR_TERMINATE
);
384 p
+= clistr_pull(cli
, cli
->server_domain
, p
, sizeof(fstring
), -1, STR_TERMINATE
);
386 fstrcpy(cli
->user_name
, user
);
388 if (session_key
.data
) {
389 /* Have plaintext orginal */
390 cli_set_session_key(cli
, session_key
);
395 data_blob_free(&lm_response
);
396 data_blob_free(&nt_response
);
399 data_blob_free(&session_key
);
403 /****************************************************************************
404 Send a extended security session setup blob
405 ****************************************************************************/
407 static BOOL
cli_session_setup_blob_send(struct cli_state
*cli
, DATA_BLOB blob
)
409 uint32 capabilities
= cli_session_setup_capabilities(cli
);
412 capabilities
|= CAP_EXTENDED_SECURITY
;
414 /* send a session setup command */
415 memset(cli
->outbuf
,'\0',smb_size
);
417 set_message(cli
->outbuf
,12,0,True
);
418 SCVAL(cli
->outbuf
,smb_com
,SMBsesssetupX
);
420 cli_setup_packet(cli
);
422 SCVAL(cli
->outbuf
,smb_vwv0
,0xFF);
423 SSVAL(cli
->outbuf
,smb_vwv2
,CLI_BUFFER_SIZE
);
424 SSVAL(cli
->outbuf
,smb_vwv3
,2);
425 SSVAL(cli
->outbuf
,smb_vwv4
,1);
426 SIVAL(cli
->outbuf
,smb_vwv5
,0);
427 SSVAL(cli
->outbuf
,smb_vwv7
,blob
.length
);
428 SIVAL(cli
->outbuf
,smb_vwv10
,capabilities
);
429 p
= smb_buf(cli
->outbuf
);
430 memcpy(p
, blob
.data
, blob
.length
);
432 p
+= clistr_push(cli
, p
, "Unix", -1, STR_TERMINATE
);
433 p
+= clistr_push(cli
, p
, "Samba", -1, STR_TERMINATE
);
434 cli_setup_bcc(cli
, p
);
435 return cli_send_smb(cli
);
438 /****************************************************************************
439 Send a extended security session setup blob, returning a reply blob.
440 ****************************************************************************/
442 static DATA_BLOB
cli_session_setup_blob_receive(struct cli_state
*cli
)
444 DATA_BLOB blob2
= data_blob(NULL
, 0);
448 if (!cli_receive_smb(cli
))
451 show_msg(cli
->inbuf
);
453 if (cli_is_error(cli
) && !NT_STATUS_EQUAL(cli_nt_error(cli
),
454 NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
458 /* use the returned vuid from now on */
459 cli
->vuid
= SVAL(cli
->inbuf
,smb_uid
);
461 p
= smb_buf(cli
->inbuf
);
463 blob2
= data_blob(p
, SVAL(cli
->inbuf
, smb_vwv3
));
466 p
+= clistr_pull(cli
, cli
->server_os
, p
, sizeof(fstring
), -1, STR_TERMINATE
);
468 /* w2k with kerberos doesn't properly null terminate this field */
469 len
= smb_buflen(cli
->inbuf
) - PTR_DIFF(p
, smb_buf(cli
->inbuf
));
470 p
+= clistr_pull(cli
, cli
->server_type
, p
, sizeof(fstring
), len
, 0);
477 /****************************************************************************
478 Send a extended security session setup blob, returning a reply blob.
479 ****************************************************************************/
481 static DATA_BLOB
cli_session_setup_blob(struct cli_state
*cli
, DATA_BLOB blob
)
483 DATA_BLOB blob2
= data_blob(NULL
, 0);
484 if (!cli_session_setup_blob_send(cli
, blob
)) {
488 return cli_session_setup_blob_receive(cli
);
491 /****************************************************************************
492 Use in-memory credentials cache
493 ****************************************************************************/
495 static void use_in_memory_ccache(void) {
496 setenv(KRB5_ENV_CCNAME
, "MEMORY:cliconnect", 1);
499 /****************************************************************************
500 Do a spnego/kerberos encrypted session setup.
501 ****************************************************************************/
503 static NTSTATUS
cli_session_setup_kerberos(struct cli_state
*cli
, const char *principal
, const char *workgroup
)
505 DATA_BLOB blob2
, negTokenTarg
;
506 DATA_BLOB session_key_krb5
;
507 DATA_BLOB null_blob
= data_blob(NULL
, 0);
509 DEBUG(2,("Doing kerberos session setup\n"));
511 /* generate the encapsulated kerberos5 ticket */
512 negTokenTarg
= spnego_gen_negTokenTarg(principal
, 0, &session_key_krb5
);
514 if (!negTokenTarg
.data
)
515 return NT_STATUS_UNSUCCESSFUL
;
518 file_save("negTokenTarg.dat", negTokenTarg
.data
, negTokenTarg
.length
);
521 cli_simple_set_signing(cli
, session_key_krb5
, null_blob
, 0);
523 blob2
= cli_session_setup_blob(cli
, negTokenTarg
);
525 /* we don't need this blob for kerberos */
526 data_blob_free(&blob2
);
528 cli_set_session_key(cli
, session_key_krb5
);
530 data_blob_free(&negTokenTarg
);
532 if (cli_is_error(cli
)) {
533 if (NT_STATUS_IS_OK(cli_nt_error(cli
))) {
534 return NT_STATUS_UNSUCCESSFUL
;
539 #endif /* HAVE_KRB5 */
542 /****************************************************************************
543 Do a spnego/NTLMSSP encrypted session setup.
544 ****************************************************************************/
546 static NTSTATUS
cli_session_setup_ntlmssp(struct cli_state
*cli
, const char *user
,
547 const char *pass
, const char *domain
)
549 struct ntlmssp_state
*ntlmssp_state
;
554 DATA_BLOB blob_in
= data_blob(NULL
, 0);
557 cli_temp_set_signing(cli
);
559 if (!NT_STATUS_IS_OK(nt_status
= ntlmssp_client_start(&ntlmssp_state
))) {
563 if (!NT_STATUS_IS_OK(nt_status
= ntlmssp_set_username(ntlmssp_state
, user
))) {
566 if (!NT_STATUS_IS_OK(nt_status
= ntlmssp_set_domain(ntlmssp_state
, domain
))) {
569 if (!NT_STATUS_IS_OK(nt_status
= ntlmssp_set_password(ntlmssp_state
, pass
))) {
574 nt_status
= ntlmssp_update(ntlmssp_state
,
576 data_blob_free(&blob_in
);
577 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
579 /* and wrap it in a SPNEGO wrapper */
580 msg1
= gen_negTokenInit(OID_NTLMSSP
, blob_out
);
582 /* wrap it in SPNEGO */
583 msg1
= spnego_gen_auth(blob_out
);
586 /* now send that blob on its way */
587 if (!cli_session_setup_blob_send(cli
, msg1
)) {
588 DEBUG(3, ("Failed to send NTLMSSP/SPENGO blob to server!\n"));
589 nt_status
= NT_STATUS_UNSUCCESSFUL
;
591 data_blob_free(&msg1
);
593 blob
= cli_session_setup_blob_receive(cli
);
595 nt_status
= cli_nt_error(cli
);
596 if (cli_is_error(cli
) && NT_STATUS_IS_OK(nt_status
)) {
597 if (cli
->smb_rw_error
== READ_BAD_SIG
) {
598 nt_status
= NT_STATUS_ACCESS_DENIED
;
600 nt_status
= NT_STATUS_UNSUCCESSFUL
;
607 if (NT_STATUS_IS_OK(nt_status
)) {
608 nt_status
= NT_STATUS_UNSUCCESSFUL
;
610 } else if ((turn
== 1) &&
611 NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
612 DATA_BLOB tmp_blob
= data_blob(NULL
, 0);
613 /* the server might give us back two challenges */
614 if (!spnego_parse_challenge(blob
, &blob_in
,
616 DEBUG(3,("Failed to parse challenges\n"));
617 nt_status
= NT_STATUS_INVALID_PARAMETER
;
619 data_blob_free(&tmp_blob
);
621 if (!spnego_parse_auth_response(blob
, nt_status
,
623 DEBUG(3,("Failed to parse auth response\n"));
624 if (NT_STATUS_IS_OK(nt_status
)
625 || NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
))
626 nt_status
= NT_STATUS_INVALID_PARAMETER
;
629 data_blob_free(&blob
);
630 data_blob_free(&blob_out
);
632 } while (NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
));
634 if (NT_STATUS_IS_OK(nt_status
)) {
636 DATA_BLOB key
= data_blob(ntlmssp_state
->session_key
.data
,
637 ntlmssp_state
->session_key
.length
);
638 DATA_BLOB null_blob
= data_blob(NULL
, 0);
640 fstrcpy(cli
->server_domain
, ntlmssp_state
->server_domain
);
641 cli_set_session_key(cli
, ntlmssp_state
->session_key
);
643 /* Using NTLMSSP session setup, signing on the net only starts
644 * after a successful authentication and the session key has
645 * been determined, but with a sequence number of 2. This
646 * assumes that NTLMSSP needs exactly 2 roundtrips, for any
647 * other SPNEGO mechanism it needs adapting. */
649 cli_simple_set_signing(cli
, key
, null_blob
, 2);
652 /* we have a reference conter on ntlmssp_state, if we are signing
653 then the state will be kept by the signing engine */
655 ntlmssp_end(&ntlmssp_state
);
660 /****************************************************************************
661 Do a spnego encrypted session setup.
662 ****************************************************************************/
664 NTSTATUS
cli_session_setup_spnego(struct cli_state
*cli
, const char *user
,
665 const char *pass
, const char *domain
)
668 char *OIDs
[ASN1_MAX_OIDS
];
670 BOOL got_kerberos_mechanism
= False
;
673 DEBUG(2,("Doing spnego session setup (blob length=%lu)\n", (unsigned long)cli
->secblob
.length
));
675 /* the server might not even do spnego */
676 if (cli
->secblob
.length
<= 16) {
677 DEBUG(3,("server didn't supply a full spnego negprot\n"));
682 file_save("negprot.dat", cli
->secblob
.data
, cli
->secblob
.length
);
685 /* there is 16 bytes of GUID before the real spnego packet starts */
686 blob
= data_blob(cli
->secblob
.data
+16, cli
->secblob
.length
-16);
688 /* the server sent us the first part of the SPNEGO exchange in the negprot
690 if (!spnego_parse_negTokenInit(blob
, OIDs
, &principal
)) {
691 data_blob_free(&blob
);
692 return NT_STATUS_INVALID_PARAMETER
;
694 data_blob_free(&blob
);
696 /* make sure the server understands kerberos */
697 for (i
=0;OIDs
[i
];i
++) {
698 DEBUG(3,("got OID=%s\n", OIDs
[i
]));
699 if (strcmp(OIDs
[i
], OID_KERBEROS5_OLD
) == 0 ||
700 strcmp(OIDs
[i
], OID_KERBEROS5
) == 0) {
701 got_kerberos_mechanism
= True
;
705 DEBUG(3,("got principal=%s\n", principal
));
707 fstrcpy(cli
->user_name
, user
);
710 /* If password is set we reauthenticate to kerberos server
711 * and do not store results */
713 if (got_kerberos_mechanism
&& cli
->use_kerberos
) {
717 use_in_memory_ccache();
718 ret
= kerberos_kinit_password(user
, pass
, 0 /* no time correction for now */);
721 DEBUG(0, ("Kinit failed: %s\n", error_message(ret
)));
722 return NT_STATUS_LOGON_FAILURE
;
726 return cli_session_setup_kerberos(cli
, principal
, domain
);
734 return cli_session_setup_ntlmssp(cli
, user
, pass
, domain
);
737 /****************************************************************************
738 Send a session setup. The username and workgroup is in UNIX character
739 format and must be converted to DOS codepage format before sending. If the
740 password is in plaintext, the same should be done.
741 ****************************************************************************/
743 BOOL
cli_session_setup(struct cli_state
*cli
,
745 const char *pass
, int passlen
,
746 const char *ntpass
, int ntpasslen
,
747 const char *workgroup
)
752 /* allow for workgroups as part of the username */
753 fstrcpy(user2
, user
);
754 if ((p
=strchr_m(user2
,'\\')) || (p
=strchr_m(user2
,'/')) ||
755 (p
=strchr_m(user2
,*lp_winbind_separator()))) {
761 if (cli
->protocol
< PROTOCOL_LANMAN1
)
764 /* now work out what sort of session setup we are going to
765 do. I have split this into separate functions to make the
766 flow a bit easier to understand (tridge) */
768 /* if its an older server then we have to use the older request format */
770 if (cli
->protocol
< PROTOCOL_NT1
) {
771 if (!lp_client_lanman_auth() && passlen
!= 24 && (*pass
)) {
772 DEBUG(1, ("Server requested LM password but 'client lanman auth'"
777 if ((cli
->sec_mode
& NEGOTIATE_SECURITY_CHALLENGE_RESPONSE
) == 0 &&
778 !lp_client_plaintext_auth() && (*pass
)) {
779 DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'"
784 return cli_session_setup_lanman2(cli
, user
, pass
, passlen
, workgroup
);
787 /* if no user is supplied then we have to do an anonymous connection.
788 passwords are ignored */
791 return cli_session_setup_guest(cli
);
793 /* if the server is share level then send a plaintext null
794 password at this point. The password is sent in the tree
797 if ((cli
->sec_mode
& NEGOTIATE_SECURITY_USER_LEVEL
) == 0)
798 return cli_session_setup_plaintext(cli
, user
, "", workgroup
);
800 /* if the server doesn't support encryption then we have to use
801 plaintext. The second password is ignored */
803 if ((cli
->sec_mode
& NEGOTIATE_SECURITY_CHALLENGE_RESPONSE
) == 0) {
804 if (!lp_client_plaintext_auth() && (*pass
)) {
805 DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'"
809 return cli_session_setup_plaintext(cli
, user
, pass
, workgroup
);
812 /* if the server supports extended security then use SPNEGO */
814 if (cli
->capabilities
& CAP_EXTENDED_SECURITY
) {
816 if (!NT_STATUS_IS_OK(nt_status
= cli_session_setup_spnego(cli
, user
, pass
, workgroup
))) {
817 DEBUG(3, ("SPENGO login failed: %s\n", get_friendly_nt_error_msg(nt_status
)));
823 /* otherwise do a NT1 style session setup */
825 return cli_session_setup_nt1(cli
, user
,
826 pass
, passlen
, ntpass
, ntpasslen
,
830 /****************************************************************************
832 *****************************************************************************/
834 BOOL
cli_ulogoff(struct cli_state
*cli
)
836 memset(cli
->outbuf
,'\0',smb_size
);
837 set_message(cli
->outbuf
,2,0,True
);
838 SCVAL(cli
->outbuf
,smb_com
,SMBulogoffX
);
839 cli_setup_packet(cli
);
840 SSVAL(cli
->outbuf
,smb_vwv0
,0xFF);
841 SSVAL(cli
->outbuf
,smb_vwv2
,0); /* no additional info */
844 if (!cli_receive_smb(cli
))
847 return !cli_is_error(cli
);
850 /****************************************************************************
852 ****************************************************************************/
853 BOOL
cli_send_tconX(struct cli_state
*cli
,
854 const char *share
, const char *dev
, const char *pass
, int passlen
)
856 fstring fullshare
, pword
;
858 memset(cli
->outbuf
,'\0',smb_size
);
859 memset(cli
->inbuf
,'\0',smb_size
);
861 fstrcpy(cli
->share
, share
);
863 /* in user level security don't send a password now */
864 if (cli
->sec_mode
& NEGOTIATE_SECURITY_USER_LEVEL
) {
869 if ((cli
->sec_mode
& NEGOTIATE_SECURITY_CHALLENGE_RESPONSE
) && *pass
&& passlen
!= 24) {
870 if (!lp_client_lanman_auth()) {
871 DEBUG(1, ("Server requested LANMAN password but 'client use lanman auth'"
877 * Non-encrypted passwords - convert to DOS codepage before encryption.
880 SMBencrypt(pass
,cli
->secblob
.data
,(uchar
*)pword
);
882 if((cli
->sec_mode
& (NEGOTIATE_SECURITY_USER_LEVEL
|NEGOTIATE_SECURITY_CHALLENGE_RESPONSE
)) == 0) {
883 if (!lp_client_plaintext_auth() && (*pass
)) {
884 DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'"
890 * Non-encrypted passwords - convert to DOS codepage before using.
892 passlen
= clistr_push(cli
, pword
, pass
, sizeof(pword
), STR_TERMINATE
);
895 memcpy(pword
, pass
, passlen
);
899 slprintf(fullshare
, sizeof(fullshare
)-1,
900 "\\\\%s\\%s", cli
->desthost
, share
);
902 set_message(cli
->outbuf
,4, 0, True
);
903 SCVAL(cli
->outbuf
,smb_com
,SMBtconX
);
904 cli_setup_packet(cli
);
906 SSVAL(cli
->outbuf
,smb_vwv0
,0xFF);
907 SSVAL(cli
->outbuf
,smb_vwv3
,passlen
);
909 p
= smb_buf(cli
->outbuf
);
910 memcpy(p
,pword
,passlen
);
912 p
+= clistr_push(cli
, p
, fullshare
, -1, STR_TERMINATE
|STR_UPPER
);
913 p
+= clistr_push(cli
, p
, dev
, -1, STR_TERMINATE
|STR_UPPER
| STR_ASCII
);
915 cli_setup_bcc(cli
, p
);
918 if (!cli_receive_smb(cli
))
921 if (cli_is_error(cli
))
924 clistr_pull(cli
, cli
->dev
, smb_buf(cli
->inbuf
), sizeof(fstring
), -1, STR_TERMINATE
|STR_ASCII
);
926 if (cli
->protocol
>= PROTOCOL_NT1
&&
927 smb_buflen(cli
->inbuf
) == 3) {
928 /* almost certainly win95 - enable bug fixes */
932 cli
->cnum
= SVAL(cli
->inbuf
,smb_tid
);
936 /****************************************************************************
937 Send a tree disconnect.
938 ****************************************************************************/
940 BOOL
cli_tdis(struct cli_state
*cli
)
942 memset(cli
->outbuf
,'\0',smb_size
);
943 set_message(cli
->outbuf
,0,0,True
);
944 SCVAL(cli
->outbuf
,smb_com
,SMBtdis
);
945 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
946 cli_setup_packet(cli
);
949 if (!cli_receive_smb(cli
))
952 return !cli_is_error(cli
);
955 /****************************************************************************
956 Send a negprot command.
957 ****************************************************************************/
959 void cli_negprot_send(struct cli_state
*cli
)
964 if (cli
->protocol
< PROTOCOL_NT1
)
965 cli
->use_spnego
= False
;
967 memset(cli
->outbuf
,'\0',smb_size
);
969 /* setup the protocol strings */
970 set_message(cli
->outbuf
,0,0,True
);
972 p
= smb_buf(cli
->outbuf
);
974 prots
[numprots
].name
&& prots
[numprots
].prot
<=cli
->protocol
;
977 p
+= clistr_push(cli
, p
, prots
[numprots
].name
, -1, STR_TERMINATE
);
980 SCVAL(cli
->outbuf
,smb_com
,SMBnegprot
);
981 cli_setup_bcc(cli
, p
);
982 cli_setup_packet(cli
);
984 SCVAL(smb_buf(cli
->outbuf
),0,2);
989 /****************************************************************************
990 Send a negprot command.
991 ****************************************************************************/
993 BOOL
cli_negprot(struct cli_state
*cli
)
999 if (cli
->protocol
< PROTOCOL_NT1
)
1000 cli
->use_spnego
= False
;
1002 memset(cli
->outbuf
,'\0',smb_size
);
1004 /* setup the protocol strings */
1005 for (plength
=0,numprots
=0;
1006 prots
[numprots
].name
&& prots
[numprots
].prot
<=cli
->protocol
;
1008 plength
+= strlen(prots
[numprots
].name
)+2;
1010 set_message(cli
->outbuf
,0,plength
,True
);
1012 p
= smb_buf(cli
->outbuf
);
1014 prots
[numprots
].name
&& prots
[numprots
].prot
<=cli
->protocol
;
1017 p
+= clistr_push(cli
, p
, prots
[numprots
].name
, -1, STR_TERMINATE
);
1020 SCVAL(cli
->outbuf
,smb_com
,SMBnegprot
);
1021 cli_setup_packet(cli
);
1023 SCVAL(smb_buf(cli
->outbuf
),0,2);
1026 if (!cli_receive_smb(cli
))
1029 show_msg(cli
->inbuf
);
1031 if (cli_is_error(cli
) ||
1032 ((int)SVAL(cli
->inbuf
,smb_vwv0
) >= numprots
)) {
1036 cli
->protocol
= prots
[SVAL(cli
->inbuf
,smb_vwv0
)].prot
;
1038 if ((cli
->protocol
< PROTOCOL_NT1
) && cli
->sign_info
.mandatory_signing
) {
1039 DEBUG(0,("cli_negprot: SMB signing is mandatory and the selected protocol level doesn't support it.\n"));
1043 if (cli
->protocol
>= PROTOCOL_NT1
) {
1045 cli
->sec_mode
= CVAL(cli
->inbuf
,smb_vwv1
);
1046 cli
->max_mux
= SVAL(cli
->inbuf
, smb_vwv1
+1);
1047 cli
->max_xmit
= IVAL(cli
->inbuf
,smb_vwv3
+1);
1048 cli
->sesskey
= IVAL(cli
->inbuf
,smb_vwv7
+1);
1049 cli
->serverzone
= SVALS(cli
->inbuf
,smb_vwv15
+1);
1050 cli
->serverzone
*= 60;
1051 /* this time arrives in real GMT */
1052 cli
->servertime
= interpret_long_date(cli
->inbuf
+smb_vwv11
+1);
1053 cli
->secblob
= data_blob(smb_buf(cli
->inbuf
),smb_buflen(cli
->inbuf
));
1054 cli
->capabilities
= IVAL(cli
->inbuf
,smb_vwv9
+1);
1055 if (cli
->capabilities
& CAP_RAW_MODE
) {
1056 cli
->readbraw_supported
= True
;
1057 cli
->writebraw_supported
= True
;
1059 /* work out if they sent us a workgroup */
1060 if (!(cli
->capabilities
& CAP_EXTENDED_SECURITY
) &&
1061 smb_buflen(cli
->inbuf
) > 8) {
1062 clistr_pull(cli
, cli
->server_domain
,
1063 smb_buf(cli
->inbuf
)+8, sizeof(cli
->server_domain
),
1064 smb_buflen(cli
->inbuf
)-8, STR_UNICODE
|STR_NOALIGN
);
1068 * As signing is slow we only turn it on if either the client or
1069 * the server require it. JRA.
1072 if (cli
->sec_mode
& NEGOTIATE_SECURITY_SIGNATURES_REQUIRED
) {
1073 /* Fail if server says signing is mandatory and we don't want to support it. */
1074 if (!cli
->sign_info
.allow_smb_signing
) {
1075 DEBUG(0,("cli_negprot: SMB signing is mandatory and we have disabled it.\n"));
1078 cli
->sign_info
.negotiated_smb_signing
= True
;
1079 cli
->sign_info
.mandatory_signing
= True
;
1080 } else if (cli
->sign_info
.mandatory_signing
&& cli
->sign_info
.allow_smb_signing
) {
1081 /* Fail if client says signing is mandatory and the server doesn't support it. */
1082 if (!(cli
->sec_mode
& NEGOTIATE_SECURITY_SIGNATURES_ENABLED
)) {
1083 DEBUG(1,("cli_negprot: SMB signing is mandatory and the server doesn't support it.\n"));
1086 cli
->sign_info
.negotiated_smb_signing
= True
;
1087 cli
->sign_info
.mandatory_signing
= True
;
1090 } else if (cli
->protocol
>= PROTOCOL_LANMAN1
) {
1091 cli
->use_spnego
= False
;
1092 cli
->sec_mode
= SVAL(cli
->inbuf
,smb_vwv1
);
1093 cli
->max_xmit
= SVAL(cli
->inbuf
,smb_vwv2
);
1094 cli
->sesskey
= IVAL(cli
->inbuf
,smb_vwv6
);
1095 cli
->serverzone
= SVALS(cli
->inbuf
,smb_vwv10
);
1096 cli
->serverzone
*= 60;
1097 /* this time is converted to GMT by make_unix_date */
1098 cli
->servertime
= make_unix_date(cli
->inbuf
+smb_vwv8
);
1099 cli
->readbraw_supported
= ((SVAL(cli
->inbuf
,smb_vwv5
) & 0x1) != 0);
1100 cli
->writebraw_supported
= ((SVAL(cli
->inbuf
,smb_vwv5
) & 0x2) != 0);
1101 cli
->secblob
= data_blob(smb_buf(cli
->inbuf
),smb_buflen(cli
->inbuf
));
1103 /* the old core protocol */
1104 cli
->use_spnego
= False
;
1106 cli
->serverzone
= TimeDiff(time(NULL
));
1109 cli
->max_xmit
= MIN(cli
->max_xmit
, CLI_BUFFER_SIZE
);
1111 /* a way to force ascii SMB */
1112 if (getenv("CLI_FORCE_ASCII"))
1113 cli
->capabilities
&= ~CAP_UNICODE
;
1118 /****************************************************************************
1119 Send a session request. See rfc1002.txt 4.3 and 4.3.2.
1120 ****************************************************************************/
1122 BOOL
cli_session_request(struct cli_state
*cli
,
1123 struct nmb_name
*calling
, struct nmb_name
*called
)
1127 extern pstring user_socket_options
;
1129 memcpy(&(cli
->calling
), calling
, sizeof(*calling
));
1130 memcpy(&(cli
->called
), called
, sizeof(*called
));
1132 /* put in the destination name */
1133 p
= cli
->outbuf
+len
;
1134 name_mangle(cli
->called
.name
, p
, cli
->called
.name_type
);
1138 p
= cli
->outbuf
+len
;
1139 name_mangle(cli
->calling
.name
, p
, cli
->calling
.name_type
);
1142 /* 445 doesn't have session request */
1143 if (cli
->port
== 445)
1146 /* send a session request (RFC 1002) */
1147 /* setup the packet length
1148 * Remove four bytes from the length count, since the length
1149 * field in the NBT Session Service header counts the number
1150 * of bytes which follow. The cli_send_smb() function knows
1151 * about this and accounts for those four bytes.
1155 _smb_setlen(cli
->outbuf
,len
);
1156 SCVAL(cli
->outbuf
,0,0x81);
1159 DEBUG(5,("Sent session request\n"));
1161 if (!cli_receive_smb(cli
))
1164 if (CVAL(cli
->inbuf
,0) == 0x84) {
1165 /* C. Hoch 9/14/95 Start */
1166 /* For information, here is the response structure.
1167 * We do the byte-twiddling to for portability.
1168 struct RetargetResponse{
1170 unsigned char flags;
1176 int port
= (CVAL(cli
->inbuf
,8)<<8)+CVAL(cli
->inbuf
,9);
1177 /* SESSION RETARGET */
1178 putip((char *)&cli
->dest_ip
,cli
->inbuf
+4);
1180 cli
->fd
= open_socket_out(SOCK_STREAM
, &cli
->dest_ip
, port
, LONG_CONNECT_TIMEOUT
);
1184 DEBUG(3,("Retargeted\n"));
1186 set_socket_options(cli
->fd
,user_socket_options
);
1193 DEBUG(0,("Retarget recursion - failing\n"));
1197 ret
= cli_session_request(cli
, calling
, called
);
1201 } /* C. Hoch 9/14/95 End */
1203 if (CVAL(cli
->inbuf
,0) != 0x82) {
1204 /* This is the wrong place to put the error... JRA. */
1205 cli
->rap_error
= CVAL(cli
->inbuf
,4);
1211 /****************************************************************************
1212 Open the client sockets.
1213 ****************************************************************************/
1215 BOOL
cli_connect(struct cli_state
*cli
, const char *host
, struct in_addr
*ip
)
1217 extern pstring user_socket_options
;
1218 int name_type
= 0x20;
1221 /* reasonable default hostname */
1222 if (!host
) host
= "*SMBSERVER";
1224 fstrcpy(cli
->desthost
, host
);
1226 /* allow hostnames of the form NAME#xx and do a netbios lookup */
1227 if ((p
= strchr(cli
->desthost
, '#'))) {
1228 name_type
= strtol(p
+1, NULL
, 16);
1232 if (!ip
|| is_zero_ip(*ip
)) {
1233 if (!resolve_name(cli
->desthost
, &cli
->dest_ip
, name_type
)) {
1236 if (ip
) *ip
= cli
->dest_ip
;
1241 if (getenv("LIBSMB_PROG")) {
1242 cli
->fd
= sock_exec(getenv("LIBSMB_PROG"));
1244 /* try 445 first, then 139 */
1245 int port
= cli
->port
?cli
->port
:445;
1246 cli
->fd
= open_socket_out(SOCK_STREAM
, &cli
->dest_ip
,
1247 port
, cli
->timeout
);
1248 if (cli
->fd
== -1 && cli
->port
== 0) {
1250 cli
->fd
= open_socket_out(SOCK_STREAM
, &cli
->dest_ip
,
1251 port
, cli
->timeout
);
1256 if (cli
->fd
== -1) {
1257 DEBUG(1,("Error connecting to %s (%s)\n",
1258 ip
?inet_ntoa(*ip
):host
,strerror(errno
)));
1262 set_socket_options(cli
->fd
,user_socket_options
);
1267 /****************************************************************************
1268 Initialise client credentials for authenticated pipe access.
1269 ****************************************************************************/
1271 void init_creds(struct ntuser_creds
*creds
, const char* username
,
1272 const char* domain
, const char* password
)
1274 ZERO_STRUCTP(creds
);
1276 pwd_set_cleartext(&creds
->pwd
, password
);
1278 fstrcpy(creds
->user_name
, username
);
1279 fstrcpy(creds
->domain
, domain
);
1282 creds
->pwd
.null_pwd
= True
;
1287 establishes a connection to after the negprot.
1288 @param output_cli A fully initialised cli structure, non-null only on success
1289 @param dest_host The netbios name of the remote host
1290 @param dest_ip (optional) The the destination IP, NULL for name based lookup
1291 @param port (optional) The destination port (0 for default)
1292 @param retry BOOL. Did this connection fail with a retryable error ?
1295 NTSTATUS
cli_start_connection(struct cli_state
**output_cli
,
1296 const char *my_name
,
1297 const char *dest_host
,
1298 struct in_addr
*dest_ip
, int port
,
1299 int signing_state
, int flags
,
1303 struct nmb_name calling
;
1304 struct nmb_name called
;
1305 struct cli_state
*cli
;
1312 my_name
= global_myname();
1314 if (!(cli
= cli_initialise(NULL
)))
1315 return NT_STATUS_NO_MEMORY
;
1317 make_nmb_name(&calling
, my_name
, 0x0);
1318 make_nmb_name(&called
, dest_host
, 0x20);
1320 if (cli_set_port(cli
, port
) != port
) {
1322 return NT_STATUS_UNSUCCESSFUL
;
1325 cli_set_timeout(cli
, 10000); /* 10 seconds. */
1334 DEBUG(3,("Connecting to host=%s\n", dest_host
));
1336 if (!cli_connect(cli
, dest_host
, &ip
)) {
1337 DEBUG(1,("cli_full_connection: failed to connect to %s (%s)\n",
1338 nmb_namestr(&called
), inet_ntoa(ip
)));
1340 return NT_STATUS_UNSUCCESSFUL
;
1346 if (!cli_session_request(cli
, &calling
, &called
)) {
1348 DEBUG(1,("session request to %s failed (%s)\n",
1349 called
.name
, cli_errstr(cli
)));
1350 if ((p
=strchr(called
.name
, '.')) && !is_ipaddress(called
.name
)) {
1354 if (strcmp(called
.name
, "*SMBSERVER")) {
1355 make_nmb_name(&called
, "*SMBSERVER", 0x20);
1358 return NT_STATUS_UNSUCCESSFUL
;
1361 cli_setup_signing_state(cli
, signing_state
);
1363 if (flags
& CLI_FULL_CONNECTION_DONT_SPNEGO
)
1364 cli
->use_spnego
= False
;
1365 else if (flags
& CLI_FULL_CONNECTION_USE_KERBEROS
)
1366 cli
->use_kerberos
= True
;
1368 if (!cli_negprot(cli
)) {
1369 DEBUG(1,("failed negprot\n"));
1370 nt_status
= NT_STATUS_UNSUCCESSFUL
;
1376 return NT_STATUS_OK
;
1381 establishes a connection right up to doing tconX, password specified.
1382 @param output_cli A fully initialised cli structure, non-null only on success
1383 @param dest_host The netbios name of the remote host
1384 @param dest_ip (optional) The the destination IP, NULL for name based lookup
1385 @param port (optional) The destination port (0 for default)
1386 @param service (optional) The share to make the connection to. Should be 'unqualified' in any way.
1387 @param service_type The 'type' of serivice.
1388 @param user Username, unix string
1389 @param domain User's domain
1390 @param password User's password, unencrypted unix string.
1391 @param retry BOOL. Did this connection fail with a retryable error ?
1394 NTSTATUS
cli_full_connection(struct cli_state
**output_cli
,
1395 const char *my_name
,
1396 const char *dest_host
,
1397 struct in_addr
*dest_ip
, int port
,
1398 const char *service
, const char *service_type
,
1399 const char *user
, const char *domain
,
1400 const char *password
, int flags
,
1404 struct ntuser_creds creds
;
1406 struct cli_state
*cli
= NULL
;
1408 nt_status
= cli_start_connection(&cli
, my_name
, dest_host
,
1409 dest_ip
, port
, signing_state
, flags
, retry
);
1411 if (!NT_STATUS_IS_OK(nt_status
)) {
1415 if (!cli_session_setup(cli
, user
, password
, strlen(password
)+1,
1416 password
, strlen(password
)+1,
1418 if ((flags
& CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK
)
1419 && cli_session_setup(cli
, "", "", 0, "", 0, domain
)) {
1421 nt_status
= cli_nt_error(cli
);
1422 DEBUG(1,("failed session setup with %s\n", nt_errstr(nt_status
)));
1424 if (NT_STATUS_IS_OK(nt_status
))
1425 nt_status
= NT_STATUS_UNSUCCESSFUL
;
1431 if (!cli_send_tconX(cli
, service
, service_type
,
1432 password
, strlen(password
)+1)) {
1433 nt_status
= cli_nt_error(cli
);
1434 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(nt_status
)));
1436 if (NT_STATUS_IS_OK(nt_status
)) {
1437 nt_status
= NT_STATUS_UNSUCCESSFUL
;
1443 init_creds(&creds
, user
, domain
, password
);
1444 cli_init_creds(cli
, &creds
);
1447 return NT_STATUS_OK
;
1450 /****************************************************************************
1451 Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
1452 ****************************************************************************/
1454 BOOL
attempt_netbios_session_request(struct cli_state
*cli
, const char *srchost
, const char *desthost
,
1455 struct in_addr
*pdest_ip
)
1457 struct nmb_name calling
, called
;
1459 make_nmb_name(&calling
, srchost
, 0x0);
1462 * If the called name is an IP address
1463 * then use *SMBSERVER immediately.
1466 if(is_ipaddress(desthost
))
1467 make_nmb_name(&called
, "*SMBSERVER", 0x20);
1469 make_nmb_name(&called
, desthost
, 0x20);
1471 if (!cli_session_request(cli
, &calling
, &called
)) {
1472 struct nmb_name smbservername
;
1474 make_nmb_name(&smbservername
, "*SMBSERVER", 0x20);
1477 * If the name wasn't *SMBSERVER then
1478 * try with *SMBSERVER if the first name fails.
1481 if (nmb_name_equal(&called
, &smbservername
)) {
1484 * The name used was *SMBSERVER, don't bother with another name.
1487 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
1488 with error %s.\n", desthost
, cli_errstr(cli
) ));
1493 * We need to close the connection here but can't call cli_shutdown as
1494 * will free an allocated cli struct. cli_close_connection was invented
1495 * for this purpose. JRA. Based on work by "Kim R. Pedersen" <krp@filanet.dk>.
1498 cli_close_connection(cli
);
1500 if (!cli_initialise(cli
) ||
1501 !cli_connect(cli
, desthost
, pdest_ip
) ||
1502 !cli_session_request(cli
, &calling
, &smbservername
)) {
1503 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
1504 name *SMBSERVER with error %s\n", desthost
, cli_errstr(cli
) ));
1516 /****************************************************************************
1517 Send an old style tcon.
1518 ****************************************************************************/
1519 NTSTATUS
cli_raw_tcon(struct cli_state
*cli
,
1520 const char *service
, const char *pass
, const char *dev
,
1521 uint16
*max_xmit
, uint16
*tid
)
1525 if (!lp_client_plaintext_auth() && (*pass
)) {
1526 DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'"
1528 return NT_STATUS_ACCESS_DENIED
;
1531 memset(cli
->outbuf
,'\0',smb_size
);
1532 memset(cli
->inbuf
,'\0',smb_size
);
1534 set_message(cli
->outbuf
, 0, 0, True
);
1535 SCVAL(cli
->outbuf
,smb_com
,SMBtcon
);
1536 cli_setup_packet(cli
);
1538 p
= smb_buf(cli
->outbuf
);
1539 *p
++ = 4; p
+= clistr_push(cli
, p
, service
, -1, STR_TERMINATE
| STR_NOALIGN
);
1540 *p
++ = 4; p
+= clistr_push(cli
, p
, pass
, -1, STR_TERMINATE
| STR_NOALIGN
);
1541 *p
++ = 4; p
+= clistr_push(cli
, p
, dev
, -1, STR_TERMINATE
| STR_NOALIGN
);
1543 cli_setup_bcc(cli
, p
);
1546 if (!cli_receive_smb(cli
)) {
1547 return NT_STATUS_UNEXPECTED_NETWORK_ERROR
;
1550 if (cli_is_error(cli
)) {
1551 return cli_nt_error(cli
);
1554 *max_xmit
= SVAL(cli
->inbuf
, smb_vwv0
);
1555 *tid
= SVAL(cli
->inbuf
, smb_vwv1
);
1557 return NT_STATUS_OK
;
1560 /* Return a cli_state pointing at the IPC$ share for the given server */
1562 struct cli_state
*get_ipc_connect(char *server
, struct in_addr
*server_ip
,
1563 struct user_auth_info
*user_info
)
1565 struct cli_state
*cli
;
1571 nt_status
= cli_full_connection(&cli
, myname
, server
, server_ip
, 0, "IPC$", "IPC",
1572 user_info
->username
, lp_workgroup(), user_info
->password
,
1573 CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK
, Undefined
, NULL
);
1575 if (NT_STATUS_IS_OK(nt_status
)) {
1577 } else if (is_ipaddress(server
)) {
1578 /* windows 9* needs a correct NMB name for connections */
1579 fstring remote_name
;
1581 if (name_status_find("*", 0, 0, *server_ip
, remote_name
)) {
1582 cli
= get_ipc_connect(remote_name
, server_ip
, user_info
);
1590 /* Return the IP address and workgroup of a master browser on the
1593 struct cli_state
*get_ipc_connect_master_ip_bcast(pstring workgroup
, struct user_auth_info
*user_info
)
1595 struct ip_service
*ip_list
;
1596 struct cli_state
*cli
;
1598 struct in_addr server_ip
;
1600 /* Go looking for workgroups by broadcasting on the local network */
1602 if (!name_resolve_bcast(MSBROWSE
, 1, &ip_list
, &count
)) {
1606 for (i
= 0; i
< count
; i
++) {
1607 static fstring name
;
1609 if (!name_status_find("*", 0, 0x1d, ip_list
[i
].ip
, name
))
1612 if (!find_master_ip(name
, &server_ip
))
1615 pstrcpy(workgroup
, name
);
1617 DEBUG(4, ("found master browser %s, %s\n",
1618 name
, inet_ntoa(ip_list
[i
].ip
)));
1620 cli
= get_ipc_connect(inet_ntoa(server_ip
), &server_ip
, user_info
);