Make it clearer that the domain here is the domain of the user for
[Samba/gebeck_regimport.git] / source / libsmb / cliconnect.c
blob1dc46ab0e69a82bc70b1779952a10a4fbc2dfab4
1 /*
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.
22 #define NO_SYSLOG
24 #include "includes.h"
27 static const struct {
28 int prot;
29 const char *name;
30 } prots[] = {
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"},
40 {-1,NULL}
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)
50 fstring pword;
51 char *p;
53 if (passlen > sizeof(pword)-1)
54 return False;
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))
65 passlen = 0;
67 if (passlen > 0 && (cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen != 24) {
68 /* Encrypted mode needed, and non encrypted password supplied. */
69 passlen = 24;
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);
94 p += 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);
101 cli_send_smb(cli);
102 if (!cli_receive_smb(cli))
103 return False;
105 show_msg(cli->inbuf);
107 if (cli_is_error(cli))
108 return False;
110 /* use the returned vuid from now on */
111 cli->vuid = SVAL(cli->inbuf,smb_uid);
112 fstrcpy(cli->user_name, user);
114 return True;
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;
137 return capabilities;
140 /****************************************************************************
141 Do a NT1 guest session setup.
142 ****************************************************************************/
144 static BOOL cli_session_setup_guest(struct cli_state *cli)
146 char *p;
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);
168 cli_send_smb(cli);
169 if (!cli_receive_smb(cli))
170 return False;
172 show_msg(cli->inbuf);
174 if (cli_is_error(cli))
175 return False;
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, "");
186 return True;
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);
197 char *p;
198 fstring lanman;
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)));
221 else {
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);
232 cli_send_smb(cli);
233 if (!cli_receive_smb(cli))
234 return False;
236 show_msg(cli->inbuf);
238 if (cli_is_error(cli))
239 return False;
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);
248 return True;
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
265 is not negotiated.
266 @param cli client state to create do session setup on
267 @param user username
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);
282 BOOL ret = False;
283 char *p;
285 if (passlen == 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
295 dodgy...
297 names_blob = NTLMv2_generate_names_blob(cli->called.name, workgroup);
299 if (!SMBNTLMv2encrypt(user, workgroup, pass, &server_chal,
300 &names_blob,
301 &lm_response, &nt_response, &session_key)) {
302 data_blob_free(&names_blob);
303 data_blob_free(&server_chal);
304 return False;
306 data_blob_free(&names_blob);
307 data_blob_free(&server_chal);
309 } else {
310 uchar nt_hash[16];
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);
320 } else {
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);
329 } else {
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)) {
367 ret = False;
368 goto end;
371 /* show_msg(cli->inbuf); */
373 if (cli_is_error(cli)) {
374 ret = False;
375 goto end;
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);
393 ret = True;
394 end:
395 data_blob_free(&lm_response);
396 data_blob_free(&nt_response);
398 if (!ret)
399 data_blob_free(&session_key);
400 return ret;
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);
410 char *p;
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);
431 p += 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);
445 char *p;
446 size_t len;
448 if (!cli_receive_smb(cli))
449 return blob2;
451 show_msg(cli->inbuf);
453 if (cli_is_error(cli) && !NT_STATUS_EQUAL(cli_nt_error(cli),
454 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
455 return blob2;
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));
465 p += blob2.length;
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);
472 return blob2;
475 #ifdef HAVE_KRB5
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)) {
485 return blob2;
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;
517 #if 0
518 file_save("negTokenTarg.dat", negTokenTarg.data, negTokenTarg.length);
519 #endif
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;
537 return NT_STATUS_OK;
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;
550 NTSTATUS nt_status;
551 int turn = 1;
552 DATA_BLOB msg1;
553 DATA_BLOB blob;
554 DATA_BLOB blob_in = data_blob(NULL, 0);
555 DATA_BLOB blob_out;
557 cli_temp_set_signing(cli);
559 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_client_start(&ntlmssp_state))) {
560 return nt_status;
563 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, user))) {
564 return nt_status;
566 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, domain))) {
567 return nt_status;
569 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_password(ntlmssp_state, pass))) {
570 return nt_status;
573 do {
574 nt_status = ntlmssp_update(ntlmssp_state,
575 blob_in, &blob_out);
576 data_blob_free(&blob_in);
577 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
578 if (turn == 1) {
579 /* and wrap it in a SPNEGO wrapper */
580 msg1 = gen_negTokenInit(OID_NTLMSSP, blob_out);
581 } else {
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;
590 } else {
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;
599 } else {
600 nt_status = NT_STATUS_UNSUCCESSFUL;
606 if (!blob.length) {
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,
615 &tmp_blob)) {
616 DEBUG(3,("Failed to parse challenges\n"));
617 nt_status = NT_STATUS_INVALID_PARAMETER;
619 data_blob_free(&tmp_blob);
620 } else {
621 if (!spnego_parse_auth_response(blob, nt_status,
622 &blob_in)) {
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);
631 turn++;
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);
657 return nt_status;
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)
667 char *principal;
668 char *OIDs[ASN1_MAX_OIDS];
669 int i;
670 BOOL got_kerberos_mechanism = False;
671 DATA_BLOB blob;
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"));
678 goto ntlmssp;
681 #if 0
682 file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
683 #endif
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
689 reply */
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;
703 free(OIDs[i]);
705 DEBUG(3,("got principal=%s\n", principal));
707 fstrcpy(cli->user_name, user);
709 #ifdef HAVE_KRB5
710 /* If password is set we reauthenticate to kerberos server
711 * and do not store results */
713 if (got_kerberos_mechanism && cli->use_kerberos) {
714 if (pass && *pass) {
715 int ret;
717 use_in_memory_ccache();
718 ret = kerberos_kinit_password(user, pass, 0 /* no time correction for now */);
720 if (ret){
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);
728 #endif
730 free(principal);
732 ntlmssp:
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,
744 const char *user,
745 const char *pass, int passlen,
746 const char *ntpass, int ntpasslen,
747 const char *workgroup)
749 char *p;
750 fstring user2;
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()))) {
756 *p = 0;
757 user = p+1;
758 workgroup = user2;
761 if (cli->protocol < PROTOCOL_LANMAN1)
762 return True;
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'"
773 " is disabled\n"));
774 return False;
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'"
780 " is disabled\n"));
781 return False;
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 */
790 if (!user || !*user)
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
795 connect */
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'"
806 " is disabled\n"));
807 return False;
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) {
815 NTSTATUS nt_status;
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)));
818 return False;
820 return True;
823 /* otherwise do a NT1 style session setup */
825 return cli_session_setup_nt1(cli, user,
826 pass, passlen, ntpass, ntpasslen,
827 workgroup);
830 /****************************************************************************
831 Send a uloggoff.
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 */
843 cli_send_smb(cli);
844 if (!cli_receive_smb(cli))
845 return False;
847 return !cli_is_error(cli);
850 /****************************************************************************
851 Send a tconX.
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;
857 char *p;
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) {
865 passlen = 1;
866 pass = "";
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'"
872 " is disabled\n"));
873 return False;
877 * Non-encrypted passwords - convert to DOS codepage before encryption.
879 passlen = 24;
880 SMBencrypt(pass,cli->secblob.data,(uchar *)pword);
881 } else {
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'"
885 " is disabled\n"));
886 return False;
890 * Non-encrypted passwords - convert to DOS codepage before using.
892 passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
894 } else {
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);
911 p += 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);
917 cli_send_smb(cli);
918 if (!cli_receive_smb(cli))
919 return False;
921 if (cli_is_error(cli))
922 return False;
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 */
929 cli->win95 = True;
932 cli->cnum = SVAL(cli->inbuf,smb_tid);
933 return True;
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);
948 cli_send_smb(cli);
949 if (!cli_receive_smb(cli))
950 return False;
952 return !cli_is_error(cli);
955 /****************************************************************************
956 Send a negprot command.
957 ****************************************************************************/
959 void cli_negprot_send(struct cli_state *cli)
961 char *p;
962 int numprots;
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);
973 for (numprots=0;
974 prots[numprots].name && prots[numprots].prot<=cli->protocol;
975 numprots++) {
976 *p++ = 2;
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);
986 cli_send_smb(cli);
989 /****************************************************************************
990 Send a negprot command.
991 ****************************************************************************/
993 BOOL cli_negprot(struct cli_state *cli)
995 char *p;
996 int numprots;
997 int plength;
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;
1007 numprots++)
1008 plength += strlen(prots[numprots].name)+2;
1010 set_message(cli->outbuf,0,plength,True);
1012 p = smb_buf(cli->outbuf);
1013 for (numprots=0;
1014 prots[numprots].name && prots[numprots].prot<=cli->protocol;
1015 numprots++) {
1016 *p++ = 2;
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);
1025 cli_send_smb(cli);
1026 if (!cli_receive_smb(cli))
1027 return False;
1029 show_msg(cli->inbuf);
1031 if (cli_is_error(cli) ||
1032 ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
1033 return(False);
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"));
1040 return False;
1043 if (cli->protocol >= PROTOCOL_NT1) {
1044 /* NT protocol */
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"));
1076 return False;
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"));
1084 return False;
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));
1102 } else {
1103 /* the old core protocol */
1104 cli->use_spnego = False;
1105 cli->sec_mode = 0;
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;
1115 return True;
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)
1125 char *p;
1126 int len = 4;
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);
1135 len += name_len(p);
1137 /* and my name */
1138 p = cli->outbuf+len;
1139 name_mangle(cli->calling.name, p, cli->calling.name_type);
1140 len += name_len(p);
1142 /* 445 doesn't have session request */
1143 if (cli->port == 445)
1144 return True;
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.
1152 * CRH.
1154 len -= 4;
1155 _smb_setlen(cli->outbuf,len);
1156 SCVAL(cli->outbuf,0,0x81);
1158 cli_send_smb(cli);
1159 DEBUG(5,("Sent session request\n"));
1161 if (!cli_receive_smb(cli))
1162 return False;
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{
1169 unsigned char type;
1170 unsigned char flags;
1171 int16 length;
1172 int32 ip_addr;
1173 int16 port;
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);
1181 if (cli->fd == -1)
1182 return False;
1184 DEBUG(3,("Retargeted\n"));
1186 set_socket_options(cli->fd,user_socket_options);
1188 /* Try again */
1190 static int depth;
1191 BOOL ret;
1192 if (depth > 4) {
1193 DEBUG(0,("Retarget recursion - failing\n"));
1194 return False;
1196 depth++;
1197 ret = cli_session_request(cli, calling, called);
1198 depth--;
1199 return ret;
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);
1206 return False;
1208 return(True);
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;
1219 char *p;
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);
1229 *p = 0;
1232 if (!ip || is_zero_ip(*ip)) {
1233 if (!resolve_name(cli->desthost, &cli->dest_ip, name_type)) {
1234 return False;
1236 if (ip) *ip = cli->dest_ip;
1237 } else {
1238 cli->dest_ip = *ip;
1241 if (getenv("LIBSMB_PROG")) {
1242 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
1243 } else {
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) {
1249 port = 139;
1250 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
1251 port, cli->timeout);
1253 if (cli->fd != -1)
1254 cli->port = port;
1256 if (cli->fd == -1) {
1257 DEBUG(1,("Error connecting to %s (%s)\n",
1258 ip?inet_ntoa(*ip):host,strerror(errno)));
1259 return False;
1262 set_socket_options(cli->fd,user_socket_options);
1264 return True;
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);
1281 if (!*username) {
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,
1300 BOOL *retry)
1302 NTSTATUS nt_status;
1303 struct nmb_name calling;
1304 struct nmb_name called;
1305 struct cli_state *cli;
1306 struct in_addr ip;
1308 if (retry)
1309 *retry = False;
1311 if (!my_name)
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) {
1321 cli_shutdown(cli);
1322 return NT_STATUS_UNSUCCESSFUL;
1325 cli_set_timeout(cli, 10000); /* 10 seconds. */
1327 if (dest_ip)
1328 ip = *dest_ip;
1329 else
1330 ZERO_STRUCT(ip);
1332 again:
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)));
1339 cli_shutdown(cli);
1340 return NT_STATUS_UNSUCCESSFUL;
1343 if (retry)
1344 *retry = True;
1346 if (!cli_session_request(cli, &calling, &called)) {
1347 char *p;
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)) {
1351 *p = 0;
1352 goto again;
1354 if (strcmp(called.name, "*SMBSERVER")) {
1355 make_nmb_name(&called , "*SMBSERVER", 0x20);
1356 goto again;
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;
1371 cli_shutdown(cli);
1372 return nt_status;
1375 *output_cli = cli;
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,
1401 int signing_state,
1402 BOOL *retry)
1404 struct ntuser_creds creds;
1405 NTSTATUS nt_status;
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)) {
1412 return nt_status;
1415 if (!cli_session_setup(cli, user, password, strlen(password)+1,
1416 password, strlen(password)+1,
1417 domain)) {
1418 if ((flags & CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK)
1419 && cli_session_setup(cli, "", "", 0, "", 0, domain)) {
1420 } else {
1421 nt_status = cli_nt_error(cli);
1422 DEBUG(1,("failed session setup with %s\n", nt_errstr(nt_status)));
1423 cli_shutdown(cli);
1424 if (NT_STATUS_IS_OK(nt_status))
1425 nt_status = NT_STATUS_UNSUCCESSFUL;
1426 return nt_status;
1430 if (service) {
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)));
1435 cli_shutdown(cli);
1436 if (NT_STATUS_IS_OK(nt_status)) {
1437 nt_status = NT_STATUS_UNSUCCESSFUL;
1439 return nt_status;
1443 init_creds(&creds, user, domain, password);
1444 cli_init_creds(cli, &creds);
1446 *output_cli = cli;
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);
1468 else
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) ));
1489 return False;
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) ));
1505 return False;
1509 return True;
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)
1523 char *p;
1525 if (!lp_client_plaintext_auth() && (*pass)) {
1526 DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'"
1527 " is disabled\n"));
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);
1545 cli_send_smb(cli);
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;
1566 pstring myname;
1567 NTSTATUS nt_status;
1569 get_myname(myname);
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)) {
1576 return cli;
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);
1583 if (cli)
1584 return cli;
1587 return NULL;
1590 /* Return the IP address and workgroup of a master browser on the
1591 network. */
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;
1597 int i, count;
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)) {
1603 return False;
1606 for (i = 0; i < count; i++) {
1607 static fstring name;
1609 if (!name_status_find("*", 0, 0x1d, ip_list[i].ip, name))
1610 continue;
1612 if (!find_master_ip(name, &server_ip))
1613 continue;
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);
1622 if (!cli)
1623 continue;
1625 return cli;
1628 return NULL;