Fix array size of a memmber of struct cli_ulogoff_state
[Samba/gbeck.git] / source3 / libsmb / cliconnect.c
blobebfc98b179539c74682b1a56be7ad7fbeec2944c
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 3 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, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
22 #include "popt_common.h"
23 #include "../libcli/auth/libcli_auth.h"
24 #include "../libcli/auth/spnego.h"
25 #include "smb_krb5.h"
26 #include "../libcli/auth/ntlmssp.h"
27 #include "libads/kerberos_proto.h"
28 #include "krb5_env.h"
30 static const struct {
31 int prot;
32 const char name[24];
33 } prots[10] = {
34 {PROTOCOL_CORE, "PC NETWORK PROGRAM 1.0"},
35 {PROTOCOL_COREPLUS, "MICROSOFT NETWORKS 1.03"},
36 {PROTOCOL_LANMAN1, "MICROSOFT NETWORKS 3.0"},
37 {PROTOCOL_LANMAN1, "LANMAN1.0"},
38 {PROTOCOL_LANMAN2, "LM1.2X002"},
39 {PROTOCOL_LANMAN2, "DOS LANMAN2.1"},
40 {PROTOCOL_LANMAN2, "LANMAN2.1"},
41 {PROTOCOL_LANMAN2, "Samba"},
42 {PROTOCOL_NT1, "NT LANMAN 1.0"},
43 {PROTOCOL_NT1, "NT LM 0.12"},
46 #define STAR_SMBSERVER "*SMBSERVER"
48 /**
49 * Set the user session key for a connection
50 * @param cli The cli structure to add it too
51 * @param session_key The session key used. (A copy of this is taken for the cli struct)
55 static void cli_set_session_key (struct cli_state *cli, const DATA_BLOB session_key)
57 cli->user_session_key = data_blob(session_key.data, session_key.length);
60 /****************************************************************************
61 Do an old lanman2 style session setup.
62 ****************************************************************************/
64 static NTSTATUS cli_session_setup_lanman2(struct cli_state *cli,
65 const char *user,
66 const char *pass, size_t passlen,
67 const char *workgroup)
69 DATA_BLOB session_key = data_blob_null;
70 DATA_BLOB lm_response = data_blob_null;
71 NTSTATUS status;
72 fstring pword;
73 char *p;
75 if (passlen > sizeof(pword)-1) {
76 return NT_STATUS_INVALID_PARAMETER;
79 /* LANMAN servers predate NT status codes and Unicode and ignore those
80 smb flags so we must disable the corresponding default capabilities
81 that would otherwise cause the Unicode and NT Status flags to be
82 set (and even returned by the server) */
84 cli->capabilities &= ~(CAP_UNICODE | CAP_STATUS32);
86 /* if in share level security then don't send a password now */
87 if (!(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL))
88 passlen = 0;
90 if (passlen > 0 && (cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen != 24) {
91 /* Encrypted mode needed, and non encrypted password supplied. */
92 lm_response = data_blob(NULL, 24);
93 if (!SMBencrypt(pass, cli->secblob.data,(uchar *)lm_response.data)) {
94 DEBUG(1, ("Password is > 14 chars in length, and is therefore incompatible with Lanman authentication\n"));
95 return NT_STATUS_ACCESS_DENIED;
97 } else if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen == 24) {
98 /* Encrypted mode needed, and encrypted password supplied. */
99 lm_response = data_blob(pass, passlen);
100 } else if (passlen > 0) {
101 /* Plaintext mode needed, assume plaintext supplied. */
102 passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
103 lm_response = data_blob(pass, passlen);
106 /* send a session setup command */
107 memset(cli->outbuf,'\0',smb_size);
108 cli_set_message(cli->outbuf,10, 0, True);
109 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
110 cli_setup_packet(cli);
112 SCVAL(cli->outbuf,smb_vwv0,0xFF);
113 SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
114 SSVAL(cli->outbuf,smb_vwv3,2);
115 SSVAL(cli->outbuf,smb_vwv4,1);
116 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
117 SSVAL(cli->outbuf,smb_vwv7,lm_response.length);
119 p = smb_buf(cli->outbuf);
120 memcpy(p,lm_response.data,lm_response.length);
121 p += lm_response.length;
122 p += clistr_push(cli, p, user, -1, STR_TERMINATE|STR_UPPER);
123 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
124 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
125 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
126 cli_setup_bcc(cli, p);
128 if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
129 return cli_nt_error(cli);
132 show_msg(cli->inbuf);
134 if (cli_is_error(cli)) {
135 return cli_nt_error(cli);
138 /* use the returned vuid from now on */
139 cli->vuid = SVAL(cli->inbuf,smb_uid);
140 status = cli_set_username(cli, user);
141 if (!NT_STATUS_IS_OK(status)) {
142 return status;
145 if (session_key.data) {
146 /* Have plaintext orginal */
147 cli_set_session_key(cli, session_key);
150 return NT_STATUS_OK;
153 /****************************************************************************
154 Work out suitable capabilities to offer the server.
155 ****************************************************************************/
157 static uint32 cli_session_setup_capabilities(struct cli_state *cli)
159 uint32 capabilities = CAP_NT_SMBS;
161 if (!cli->force_dos_errors)
162 capabilities |= CAP_STATUS32;
164 if (cli->use_level_II_oplocks)
165 capabilities |= CAP_LEVEL_II_OPLOCKS;
167 capabilities |= (cli->capabilities & (CAP_UNICODE|CAP_LARGE_FILES|CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_DFS));
168 return capabilities;
171 /****************************************************************************
172 Do a NT1 guest session setup.
173 ****************************************************************************/
175 struct cli_session_setup_guest_state {
176 struct cli_state *cli;
177 uint16_t vwv[16];
178 struct iovec bytes;
181 static void cli_session_setup_guest_done(struct tevent_req *subreq);
183 struct tevent_req *cli_session_setup_guest_create(TALLOC_CTX *mem_ctx,
184 struct event_context *ev,
185 struct cli_state *cli,
186 struct tevent_req **psmbreq)
188 struct tevent_req *req, *subreq;
189 struct cli_session_setup_guest_state *state;
190 uint16_t *vwv;
191 uint8_t *bytes;
193 req = tevent_req_create(mem_ctx, &state,
194 struct cli_session_setup_guest_state);
195 if (req == NULL) {
196 return NULL;
198 state->cli = cli;
199 vwv = state->vwv;
201 SCVAL(vwv+0, 0, 0xFF);
202 SCVAL(vwv+0, 1, 0);
203 SSVAL(vwv+1, 0, 0);
204 SSVAL(vwv+2, 0, CLI_BUFFER_SIZE);
205 SSVAL(vwv+3, 0, 2);
206 SSVAL(vwv+4, 0, cli->pid);
207 SIVAL(vwv+5, 0, cli->sesskey);
208 SSVAL(vwv+7, 0, 0);
209 SSVAL(vwv+8, 0, 0);
210 SSVAL(vwv+9, 0, 0);
211 SSVAL(vwv+10, 0, 0);
212 SIVAL(vwv+11, 0, cli_session_setup_capabilities(cli));
214 bytes = talloc_array(state, uint8_t, 0);
216 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "", 1, /* username */
217 NULL);
218 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "", 1, /* workgroup */
219 NULL);
220 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "Unix", 5, NULL);
221 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "Samba", 6, NULL);
223 if (bytes == NULL) {
224 TALLOC_FREE(req);
225 return NULL;
228 state->bytes.iov_base = (void *)bytes;
229 state->bytes.iov_len = talloc_get_size(bytes);
231 subreq = cli_smb_req_create(state, ev, cli, SMBsesssetupX, 0, 13, vwv,
232 1, &state->bytes);
233 if (subreq == NULL) {
234 TALLOC_FREE(req);
235 return NULL;
237 tevent_req_set_callback(subreq, cli_session_setup_guest_done, req);
238 *psmbreq = subreq;
239 return req;
242 struct tevent_req *cli_session_setup_guest_send(TALLOC_CTX *mem_ctx,
243 struct event_context *ev,
244 struct cli_state *cli)
246 struct tevent_req *req, *subreq;
247 NTSTATUS status;
249 req = cli_session_setup_guest_create(mem_ctx, ev, cli, &subreq);
250 if (req == NULL) {
251 return NULL;
254 status = cli_smb_req_send(subreq);
255 if (NT_STATUS_IS_OK(status)) {
256 tevent_req_nterror(req, status);
257 return tevent_req_post(req, ev);
259 return req;
262 static void cli_session_setup_guest_done(struct tevent_req *subreq)
264 struct tevent_req *req = tevent_req_callback_data(
265 subreq, struct tevent_req);
266 struct cli_session_setup_guest_state *state = tevent_req_data(
267 req, struct cli_session_setup_guest_state);
268 struct cli_state *cli = state->cli;
269 uint32_t num_bytes;
270 uint8_t *in;
271 char *inbuf;
272 uint8_t *bytes;
273 uint8_t *p;
274 NTSTATUS status;
276 status = cli_smb_recv(subreq, state, &in, 0, NULL, NULL,
277 &num_bytes, &bytes);
278 TALLOC_FREE(subreq);
279 if (!NT_STATUS_IS_OK(status)) {
280 tevent_req_nterror(req, status);
281 return;
284 inbuf = (char *)in;
285 p = bytes;
287 cli->vuid = SVAL(inbuf, smb_uid);
289 p += clistr_pull(inbuf, cli->server_os, (char *)p, sizeof(fstring),
290 bytes+num_bytes-p, STR_TERMINATE);
291 p += clistr_pull(inbuf, cli->server_type, (char *)p, sizeof(fstring),
292 bytes+num_bytes-p, STR_TERMINATE);
293 p += clistr_pull(inbuf, cli->server_domain, (char *)p, sizeof(fstring),
294 bytes+num_bytes-p, STR_TERMINATE);
296 if (strstr(cli->server_type, "Samba")) {
297 cli->is_samba = True;
300 status = cli_set_username(cli, "");
301 if (!NT_STATUS_IS_OK(status)) {
302 tevent_req_nterror(req, status);
303 return;
305 tevent_req_done(req);
308 NTSTATUS cli_session_setup_guest_recv(struct tevent_req *req)
310 return tevent_req_simple_recv_ntstatus(req);
313 static NTSTATUS cli_session_setup_guest(struct cli_state *cli)
315 TALLOC_CTX *frame = talloc_stackframe();
316 struct event_context *ev;
317 struct tevent_req *req;
318 NTSTATUS status = NT_STATUS_OK;
320 if (cli_has_async_calls(cli)) {
322 * Can't use sync call while an async call is in flight
324 status = NT_STATUS_INVALID_PARAMETER;
325 goto fail;
328 ev = event_context_init(frame);
329 if (ev == NULL) {
330 status = NT_STATUS_NO_MEMORY;
331 goto fail;
334 req = cli_session_setup_guest_send(frame, ev, cli);
335 if (req == NULL) {
336 status = NT_STATUS_NO_MEMORY;
337 goto fail;
340 if (!tevent_req_poll(req, ev)) {
341 status = map_nt_error_from_unix(errno);
342 goto fail;
345 status = cli_session_setup_guest_recv(req);
346 fail:
347 TALLOC_FREE(frame);
348 if (!NT_STATUS_IS_OK(status)) {
349 cli_set_error(cli, status);
351 return status;
354 /****************************************************************************
355 Do a NT1 plaintext session setup.
356 ****************************************************************************/
358 static NTSTATUS cli_session_setup_plaintext(struct cli_state *cli,
359 const char *user, const char *pass,
360 const char *workgroup)
362 uint32 capabilities = cli_session_setup_capabilities(cli);
363 char *p;
364 NTSTATUS status;
365 fstring lanman;
367 fstr_sprintf( lanman, "Samba %s", samba_version_string());
369 memset(cli->outbuf, '\0', smb_size);
370 cli_set_message(cli->outbuf,13,0,True);
371 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
372 cli_setup_packet(cli);
374 SCVAL(cli->outbuf,smb_vwv0,0xFF);
375 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
376 SSVAL(cli->outbuf,smb_vwv3,2);
377 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
378 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
379 SSVAL(cli->outbuf,smb_vwv8,0);
380 SIVAL(cli->outbuf,smb_vwv11,capabilities);
381 p = smb_buf(cli->outbuf);
383 /* check wether to send the ASCII or UNICODE version of the password */
385 if ( (capabilities & CAP_UNICODE) == 0 ) {
386 p += clistr_push(cli, p, pass, -1, STR_TERMINATE); /* password */
387 SSVAL(cli->outbuf,smb_vwv7,PTR_DIFF(p, smb_buf(cli->outbuf)));
389 else {
390 /* For ucs2 passwords clistr_push calls ucs2_align, which causes
391 * the space taken by the unicode password to be one byte too
392 * long (as we're on an odd byte boundary here). Reduce the
393 * count by 1 to cope with this. Fixes smbclient against NetApp
394 * servers which can't cope. Fix from
395 * bryan.kolodziej@allenlund.com in bug #3840.
397 p += clistr_push(cli, p, pass, -1, STR_UNICODE|STR_TERMINATE); /* unicode password */
398 SSVAL(cli->outbuf,smb_vwv8,PTR_DIFF(p, smb_buf(cli->outbuf))-1);
401 p += clistr_push(cli, p, user, -1, STR_TERMINATE); /* username */
402 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE); /* workgroup */
403 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
404 p += clistr_push(cli, p, lanman, -1, STR_TERMINATE);
405 cli_setup_bcc(cli, p);
407 if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
408 return cli_nt_error(cli);
411 show_msg(cli->inbuf);
413 if (cli_is_error(cli)) {
414 return cli_nt_error(cli);
417 cli->vuid = SVAL(cli->inbuf,smb_uid);
418 p = smb_buf(cli->inbuf);
419 p += clistr_pull(cli->inbuf, cli->server_os, p, sizeof(fstring),
420 -1, STR_TERMINATE);
421 p += clistr_pull(cli->inbuf, cli->server_type, p, sizeof(fstring),
422 -1, STR_TERMINATE);
423 p += clistr_pull(cli->inbuf, cli->server_domain, p, sizeof(fstring),
424 -1, STR_TERMINATE);
425 status = cli_set_username(cli, user);
426 if (!NT_STATUS_IS_OK(status)) {
427 return status;
429 if (strstr(cli->server_type, "Samba")) {
430 cli->is_samba = True;
433 return NT_STATUS_OK;
436 /****************************************************************************
437 do a NT1 NTLM/LM encrypted session setup - for when extended security
438 is not negotiated.
439 @param cli client state to create do session setup on
440 @param user username
441 @param pass *either* cleartext password (passlen !=24) or LM response.
442 @param ntpass NT response, implies ntpasslen >=24, implies pass is not clear
443 @param workgroup The user's domain.
444 ****************************************************************************/
446 static NTSTATUS cli_session_setup_nt1(struct cli_state *cli, const char *user,
447 const char *pass, size_t passlen,
448 const char *ntpass, size_t ntpasslen,
449 const char *workgroup)
451 uint32 capabilities = cli_session_setup_capabilities(cli);
452 DATA_BLOB lm_response = data_blob_null;
453 DATA_BLOB nt_response = data_blob_null;
454 DATA_BLOB session_key = data_blob_null;
455 NTSTATUS result;
456 char *p;
457 bool ok;
459 if (passlen == 0) {
460 /* do nothing - guest login */
461 } else if (passlen != 24) {
462 if (lp_client_ntlmv2_auth()) {
463 DATA_BLOB server_chal;
464 DATA_BLOB names_blob;
465 server_chal = data_blob(cli->secblob.data, MIN(cli->secblob.length, 8));
467 /* note that the 'workgroup' here is a best guess - we don't know
468 the server's domain at this point. The 'server name' is also
469 dodgy...
471 names_blob = NTLMv2_generate_names_blob(NULL, cli->called.name, workgroup);
473 if (!SMBNTLMv2encrypt(NULL, user, workgroup, pass, &server_chal,
474 &names_blob,
475 &lm_response, &nt_response, NULL, &session_key)) {
476 data_blob_free(&names_blob);
477 data_blob_free(&server_chal);
478 return NT_STATUS_ACCESS_DENIED;
480 data_blob_free(&names_blob);
481 data_blob_free(&server_chal);
483 } else {
484 uchar nt_hash[16];
485 E_md4hash(pass, nt_hash);
487 #ifdef LANMAN_ONLY
488 nt_response = data_blob_null;
489 #else
490 nt_response = data_blob(NULL, 24);
491 SMBNTencrypt(pass,cli->secblob.data,nt_response.data);
492 #endif
493 /* non encrypted password supplied. Ignore ntpass. */
494 if (lp_client_lanman_auth()) {
495 lm_response = data_blob(NULL, 24);
496 if (!SMBencrypt(pass,cli->secblob.data, lm_response.data)) {
497 /* Oops, the LM response is invalid, just put
498 the NT response there instead */
499 data_blob_free(&lm_response);
500 lm_response = data_blob(nt_response.data, nt_response.length);
502 } else {
503 /* LM disabled, place NT# in LM field instead */
504 lm_response = data_blob(nt_response.data, nt_response.length);
507 session_key = data_blob(NULL, 16);
508 #ifdef LANMAN_ONLY
509 E_deshash(pass, session_key.data);
510 memset(&session_key.data[8], '\0', 8);
511 #else
512 SMBsesskeygen_ntv1(nt_hash, session_key.data);
513 #endif
515 cli_temp_set_signing(cli);
516 } else {
517 /* pre-encrypted password supplied. Only used for
518 security=server, can't do
519 signing because we don't have original key */
521 lm_response = data_blob(pass, passlen);
522 nt_response = data_blob(ntpass, ntpasslen);
525 /* send a session setup command */
526 memset(cli->outbuf,'\0',smb_size);
528 cli_set_message(cli->outbuf,13,0,True);
529 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
530 cli_setup_packet(cli);
532 SCVAL(cli->outbuf,smb_vwv0,0xFF);
533 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
534 SSVAL(cli->outbuf,smb_vwv3,2);
535 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
536 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
537 SSVAL(cli->outbuf,smb_vwv7,lm_response.length);
538 SSVAL(cli->outbuf,smb_vwv8,nt_response.length);
539 SIVAL(cli->outbuf,smb_vwv11,capabilities);
540 p = smb_buf(cli->outbuf);
541 if (lm_response.length) {
542 memcpy(p,lm_response.data, lm_response.length); p += lm_response.length;
544 if (nt_response.length) {
545 memcpy(p,nt_response.data, nt_response.length); p += nt_response.length;
547 p += clistr_push(cli, p, user, -1, STR_TERMINATE);
549 /* Upper case here might help some NTLMv2 implementations */
550 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
551 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
552 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
553 cli_setup_bcc(cli, p);
555 if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
556 result = cli_nt_error(cli);
557 goto end;
560 /* show_msg(cli->inbuf); */
562 if (cli_is_error(cli)) {
563 result = cli_nt_error(cli);
564 goto end;
567 #ifdef LANMAN_ONLY
568 ok = cli_simple_set_signing(cli, session_key, lm_response);
569 #else
570 ok = cli_simple_set_signing(cli, session_key, nt_response);
571 #endif
572 if (ok) {
573 if (!cli_check_sign_mac(cli, cli->inbuf, 1)) {
574 result = NT_STATUS_ACCESS_DENIED;
575 goto end;
579 /* use the returned vuid from now on */
580 cli->vuid = SVAL(cli->inbuf,smb_uid);
582 p = smb_buf(cli->inbuf);
583 p += clistr_pull(cli->inbuf, cli->server_os, p, sizeof(fstring),
584 -1, STR_TERMINATE);
585 p += clistr_pull(cli->inbuf, cli->server_type, p, sizeof(fstring),
586 -1, STR_TERMINATE);
587 p += clistr_pull(cli->inbuf, cli->server_domain, p, sizeof(fstring),
588 -1, STR_TERMINATE);
590 if (strstr(cli->server_type, "Samba")) {
591 cli->is_samba = True;
594 result = cli_set_username(cli, user);
595 if (!NT_STATUS_IS_OK(result)) {
596 goto end;
599 if (session_key.data) {
600 /* Have plaintext orginal */
601 cli_set_session_key(cli, session_key);
604 result = NT_STATUS_OK;
605 end:
606 data_blob_free(&lm_response);
607 data_blob_free(&nt_response);
608 data_blob_free(&session_key);
609 return result;
612 /* The following is calculated from :
613 * (smb_size-4) = 35
614 * (smb_wcnt * 2) = 24 (smb_wcnt == 12 in cli_session_setup_blob_send() )
615 * (strlen("Unix") + 1 + strlen("Samba") + 1) * 2 = 22 (unicode strings at
616 * end of packet.
619 #define BASE_SESSSETUP_BLOB_PACKET_SIZE (35 + 24 + 22)
621 struct cli_sesssetup_blob_state {
622 struct tevent_context *ev;
623 struct cli_state *cli;
624 DATA_BLOB blob;
625 uint16_t max_blob_size;
626 uint16_t vwv[12];
627 uint8_t *buf;
629 NTSTATUS status;
630 char *inbuf;
631 DATA_BLOB ret_blob;
634 static bool cli_sesssetup_blob_next(struct cli_sesssetup_blob_state *state,
635 struct tevent_req **psubreq);
636 static void cli_sesssetup_blob_done(struct tevent_req *subreq);
638 static struct tevent_req *cli_sesssetup_blob_send(TALLOC_CTX *mem_ctx,
639 struct tevent_context *ev,
640 struct cli_state *cli,
641 DATA_BLOB blob)
643 struct tevent_req *req, *subreq;
644 struct cli_sesssetup_blob_state *state;
646 req = tevent_req_create(mem_ctx, &state,
647 struct cli_sesssetup_blob_state);
648 if (req == NULL) {
649 return NULL;
651 state->ev = ev;
652 state->blob = blob;
653 state->cli = cli;
655 if (cli->max_xmit < BASE_SESSSETUP_BLOB_PACKET_SIZE + 1) {
656 DEBUG(1, ("cli_session_setup_blob: cli->max_xmit too small "
657 "(was %u, need minimum %u)\n",
658 (unsigned int)cli->max_xmit,
659 BASE_SESSSETUP_BLOB_PACKET_SIZE));
660 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
661 return tevent_req_post(req, ev);
663 state->max_blob_size =
664 MIN(cli->max_xmit - BASE_SESSSETUP_BLOB_PACKET_SIZE, 0xFFFF);
666 if (!cli_sesssetup_blob_next(state, &subreq)) {
667 tevent_req_nomem(NULL, req);
668 return tevent_req_post(req, ev);
670 tevent_req_set_callback(subreq, cli_sesssetup_blob_done, req);
671 return req;
674 static bool cli_sesssetup_blob_next(struct cli_sesssetup_blob_state *state,
675 struct tevent_req **psubreq)
677 struct tevent_req *subreq;
678 uint16_t thistime;
680 SCVAL(state->vwv+0, 0, 0xFF);
681 SCVAL(state->vwv+0, 1, 0);
682 SSVAL(state->vwv+1, 0, 0);
683 SSVAL(state->vwv+2, 0, CLI_BUFFER_SIZE);
684 SSVAL(state->vwv+3, 0, 2);
685 SSVAL(state->vwv+4, 0, 1);
686 SIVAL(state->vwv+5, 0, 0);
688 thistime = MIN(state->blob.length, state->max_blob_size);
689 SSVAL(state->vwv+7, 0, thistime);
691 SSVAL(state->vwv+8, 0, 0);
692 SSVAL(state->vwv+9, 0, 0);
693 SIVAL(state->vwv+10, 0,
694 cli_session_setup_capabilities(state->cli)
695 | CAP_EXTENDED_SECURITY);
697 state->buf = (uint8_t *)talloc_memdup(state, state->blob.data,
698 thistime);
699 if (state->buf == NULL) {
700 return false;
702 state->blob.data += thistime;
703 state->blob.length -= thistime;
705 state->buf = smb_bytes_push_str(state->buf, cli_ucs2(state->cli),
706 "Unix", 5, NULL);
707 state->buf = smb_bytes_push_str(state->buf, cli_ucs2(state->cli),
708 "Samba", 6, NULL);
709 if (state->buf == NULL) {
710 return false;
712 subreq = cli_smb_send(state, state->ev, state->cli, SMBsesssetupX, 0,
713 12, state->vwv,
714 talloc_get_size(state->buf), state->buf);
715 if (subreq == NULL) {
716 return false;
718 *psubreq = subreq;
719 return true;
722 static void cli_sesssetup_blob_done(struct tevent_req *subreq)
724 struct tevent_req *req = tevent_req_callback_data(
725 subreq, struct tevent_req);
726 struct cli_sesssetup_blob_state *state = tevent_req_data(
727 req, struct cli_sesssetup_blob_state);
728 struct cli_state *cli = state->cli;
729 uint8_t wct;
730 uint16_t *vwv;
731 uint32_t num_bytes;
732 uint8_t *bytes;
733 NTSTATUS status;
734 uint8_t *p;
735 uint16_t blob_length;
736 uint8_t *inbuf;
738 status = cli_smb_recv(subreq, state, &inbuf, 1, &wct, &vwv,
739 &num_bytes, &bytes);
740 TALLOC_FREE(subreq);
741 if (!NT_STATUS_IS_OK(status)
742 && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
743 tevent_req_nterror(req, status);
744 return;
747 state->status = status;
748 TALLOC_FREE(state->buf);
750 state->inbuf = (char *)inbuf;
751 cli->vuid = SVAL(state->inbuf, smb_uid);
753 blob_length = SVAL(vwv+3, 0);
754 if (blob_length > num_bytes) {
755 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
756 return;
758 state->ret_blob = data_blob_const(bytes, blob_length);
760 p = bytes + blob_length;
762 p += clistr_pull(state->inbuf, cli->server_os,
763 (char *)p, sizeof(fstring),
764 bytes+num_bytes-p, STR_TERMINATE);
765 p += clistr_pull(state->inbuf, cli->server_type,
766 (char *)p, sizeof(fstring),
767 bytes+num_bytes-p, STR_TERMINATE);
768 p += clistr_pull(state->inbuf, cli->server_domain,
769 (char *)p, sizeof(fstring),
770 bytes+num_bytes-p, STR_TERMINATE);
772 if (strstr(cli->server_type, "Samba")) {
773 cli->is_samba = True;
776 if (state->blob.length != 0) {
778 * More to send
780 if (!cli_sesssetup_blob_next(state, &subreq)) {
781 tevent_req_nomem(NULL, req);
782 return;
784 tevent_req_set_callback(subreq, cli_sesssetup_blob_done, req);
785 return;
787 tevent_req_done(req);
790 static NTSTATUS cli_sesssetup_blob_recv(struct tevent_req *req,
791 TALLOC_CTX *mem_ctx,
792 DATA_BLOB *pblob,
793 char **pinbuf)
795 struct cli_sesssetup_blob_state *state = tevent_req_data(
796 req, struct cli_sesssetup_blob_state);
797 NTSTATUS status;
798 char *inbuf;
800 if (tevent_req_is_nterror(req, &status)) {
801 state->cli->vuid = 0;
802 return status;
805 inbuf = talloc_move(mem_ctx, &state->inbuf);
806 if (pblob != NULL) {
807 *pblob = state->ret_blob;
809 if (pinbuf != NULL) {
810 *pinbuf = inbuf;
812 /* could be NT_STATUS_MORE_PROCESSING_REQUIRED */
813 return state->status;
816 #ifdef HAVE_KRB5
818 /****************************************************************************
819 Use in-memory credentials cache
820 ****************************************************************************/
822 static void use_in_memory_ccache(void) {
823 setenv(KRB5_ENV_CCNAME, "MEMORY:cliconnect", 1);
826 /****************************************************************************
827 Do a spnego/kerberos encrypted session setup.
828 ****************************************************************************/
830 struct cli_session_setup_kerberos_state {
831 struct cli_state *cli;
832 DATA_BLOB negTokenTarg;
833 DATA_BLOB session_key_krb5;
834 ADS_STATUS ads_status;
837 static void cli_session_setup_kerberos_done(struct tevent_req *subreq);
839 static struct tevent_req *cli_session_setup_kerberos_send(
840 TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
841 const char *principal, const char *workgroup)
843 struct tevent_req *req, *subreq;
844 struct cli_session_setup_kerberos_state *state;
845 int rc;
847 DEBUG(2,("Doing kerberos session setup\n"));
849 req = tevent_req_create(mem_ctx, &state,
850 struct cli_session_setup_kerberos_state);
851 if (req == NULL) {
852 return NULL;
854 state->cli = cli;
855 state->ads_status = ADS_SUCCESS;
857 cli_temp_set_signing(cli);
860 * Ok, this is cheating: spnego_gen_krb5_negTokenInit can block if
861 * we have to acquire a ticket. To be fixed later :-)
863 rc = spnego_gen_krb5_negTokenInit(state, principal, 0, &state->negTokenTarg,
864 &state->session_key_krb5, 0, NULL);
865 if (rc) {
866 DEBUG(1, ("cli_session_setup_kerberos: "
867 "spnego_gen_krb5_negTokenInit failed: %s\n",
868 error_message(rc)));
869 state->ads_status = ADS_ERROR_KRB5(rc);
870 tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
871 return tevent_req_post(req, ev);
874 #if 0
875 file_save("negTokenTarg.dat", state->negTokenTarg.data,
876 state->negTokenTarg.length);
877 #endif
879 subreq = cli_sesssetup_blob_send(state, ev, cli, state->negTokenTarg);
880 if (tevent_req_nomem(subreq, req)) {
881 return tevent_req_post(req, ev);
883 tevent_req_set_callback(subreq, cli_session_setup_kerberos_done, req);
884 return req;
887 static void cli_session_setup_kerberos_done(struct tevent_req *subreq)
889 struct tevent_req *req = tevent_req_callback_data(
890 subreq, struct tevent_req);
891 struct cli_session_setup_kerberos_state *state = tevent_req_data(
892 req, struct cli_session_setup_kerberos_state);
893 char *inbuf = NULL;
894 NTSTATUS status;
896 status = cli_sesssetup_blob_recv(subreq, talloc_tos(), NULL, &inbuf);
897 if (!NT_STATUS_IS_OK(status)) {
898 TALLOC_FREE(subreq);
899 tevent_req_nterror(req, status);
900 return;
903 cli_set_session_key(state->cli, state->session_key_krb5);
905 if (cli_simple_set_signing(state->cli, state->session_key_krb5,
906 data_blob_null)
907 && !cli_check_sign_mac(state->cli, inbuf, 1)) {
908 TALLOC_FREE(subreq);
909 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
910 return;
912 TALLOC_FREE(subreq);
913 tevent_req_done(req);
916 static ADS_STATUS cli_session_setup_kerberos_recv(struct tevent_req *req)
918 struct cli_session_setup_kerberos_state *state = tevent_req_data(
919 req, struct cli_session_setup_kerberos_state);
920 NTSTATUS status;
922 if (tevent_req_is_nterror(req, &status)) {
923 return ADS_ERROR_NT(status);
925 return state->ads_status;
928 static ADS_STATUS cli_session_setup_kerberos(struct cli_state *cli,
929 const char *principal,
930 const char *workgroup)
932 struct tevent_context *ev;
933 struct tevent_req *req;
934 ADS_STATUS status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
936 if (cli_has_async_calls(cli)) {
937 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
939 ev = tevent_context_init(talloc_tos());
940 if (ev == NULL) {
941 goto fail;
943 req = cli_session_setup_kerberos_send(ev, ev, cli, principal,
944 workgroup);
945 if (req == NULL) {
946 goto fail;
948 if (!tevent_req_poll(req, ev)) {
949 status = ADS_ERROR_SYSTEM(errno);
950 goto fail;
952 status = cli_session_setup_kerberos_recv(req);
953 fail:
954 TALLOC_FREE(ev);
955 return status;
957 #endif /* HAVE_KRB5 */
959 /****************************************************************************
960 Do a spnego/NTLMSSP encrypted session setup.
961 ****************************************************************************/
963 struct cli_session_setup_ntlmssp_state {
964 struct tevent_context *ev;
965 struct cli_state *cli;
966 struct ntlmssp_state *ntlmssp_state;
967 int turn;
968 DATA_BLOB blob_out;
971 static int cli_session_setup_ntlmssp_state_destructor(
972 struct cli_session_setup_ntlmssp_state *state)
974 if (state->ntlmssp_state != NULL) {
975 TALLOC_FREE(state->ntlmssp_state);
977 return 0;
980 static void cli_session_setup_ntlmssp_done(struct tevent_req *req);
982 static struct tevent_req *cli_session_setup_ntlmssp_send(
983 TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
984 const char *user, const char *pass, const char *domain)
986 struct tevent_req *req, *subreq;
987 struct cli_session_setup_ntlmssp_state *state;
988 NTSTATUS status;
989 DATA_BLOB blob_out;
990 const char *OIDs_ntlm[] = {OID_NTLMSSP, NULL};
992 req = tevent_req_create(mem_ctx, &state,
993 struct cli_session_setup_ntlmssp_state);
994 if (req == NULL) {
995 return NULL;
997 state->ev = ev;
998 state->cli = cli;
999 state->turn = 1;
1001 state->ntlmssp_state = NULL;
1002 talloc_set_destructor(
1003 state, cli_session_setup_ntlmssp_state_destructor);
1005 cli_temp_set_signing(cli);
1007 status = ntlmssp_client_start(state,
1008 global_myname(),
1009 lp_workgroup(),
1010 lp_client_ntlmv2_auth(),
1011 &state->ntlmssp_state);
1012 if (!NT_STATUS_IS_OK(status)) {
1013 goto fail;
1015 ntlmssp_want_feature(state->ntlmssp_state,
1016 NTLMSSP_FEATURE_SESSION_KEY);
1017 if (cli->use_ccache) {
1018 ntlmssp_want_feature(state->ntlmssp_state,
1019 NTLMSSP_FEATURE_CCACHE);
1021 status = ntlmssp_set_username(state->ntlmssp_state, user);
1022 if (!NT_STATUS_IS_OK(status)) {
1023 goto fail;
1025 status = ntlmssp_set_domain(state->ntlmssp_state, domain);
1026 if (!NT_STATUS_IS_OK(status)) {
1027 goto fail;
1029 status = ntlmssp_set_password(state->ntlmssp_state, pass);
1030 if (!NT_STATUS_IS_OK(status)) {
1031 goto fail;
1033 status = ntlmssp_update(state->ntlmssp_state, data_blob_null,
1034 &blob_out);
1035 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1036 goto fail;
1039 state->blob_out = spnego_gen_negTokenInit(state, OIDs_ntlm, &blob_out, NULL);
1040 data_blob_free(&blob_out);
1042 subreq = cli_sesssetup_blob_send(state, ev, cli, state->blob_out);
1043 if (tevent_req_nomem(subreq, req)) {
1044 return tevent_req_post(req, ev);
1046 tevent_req_set_callback(subreq, cli_session_setup_ntlmssp_done, req);
1047 return req;
1048 fail:
1049 tevent_req_nterror(req, status);
1050 return tevent_req_post(req, ev);
1053 static void cli_session_setup_ntlmssp_done(struct tevent_req *subreq)
1055 struct tevent_req *req = tevent_req_callback_data(
1056 subreq, struct tevent_req);
1057 struct cli_session_setup_ntlmssp_state *state = tevent_req_data(
1058 req, struct cli_session_setup_ntlmssp_state);
1059 DATA_BLOB blob_in, msg_in, blob_out;
1060 char *inbuf = NULL;
1061 bool parse_ret;
1062 NTSTATUS status;
1064 status = cli_sesssetup_blob_recv(subreq, talloc_tos(), &blob_in,
1065 &inbuf);
1066 TALLOC_FREE(subreq);
1067 data_blob_free(&state->blob_out);
1069 if (NT_STATUS_IS_OK(status)) {
1070 if (state->cli->server_domain[0] == '\0') {
1071 fstrcpy(state->cli->server_domain,
1072 state->ntlmssp_state->server.netbios_domain);
1074 cli_set_session_key(
1075 state->cli, state->ntlmssp_state->session_key);
1077 if (cli_simple_set_signing(
1078 state->cli, state->ntlmssp_state->session_key,
1079 data_blob_null)
1080 && !cli_check_sign_mac(state->cli, inbuf, 1)) {
1081 TALLOC_FREE(subreq);
1082 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1083 return;
1085 TALLOC_FREE(subreq);
1086 TALLOC_FREE(state->ntlmssp_state);
1087 tevent_req_done(req);
1088 return;
1090 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1091 tevent_req_nterror(req, status);
1092 return;
1095 if (blob_in.length == 0) {
1096 tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
1097 return;
1100 if ((state->turn == 1)
1101 && NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1102 DATA_BLOB tmp_blob = data_blob_null;
1103 /* the server might give us back two challenges */
1104 parse_ret = spnego_parse_challenge(state, blob_in, &msg_in,
1105 &tmp_blob);
1106 data_blob_free(&tmp_blob);
1107 } else {
1108 parse_ret = spnego_parse_auth_response(state, blob_in, status,
1109 OID_NTLMSSP, &msg_in);
1111 state->turn += 1;
1113 if (!parse_ret) {
1114 DEBUG(3,("Failed to parse auth response\n"));
1115 if (NT_STATUS_IS_OK(status)
1116 || NT_STATUS_EQUAL(status,
1117 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1118 tevent_req_nterror(
1119 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
1120 return;
1124 status = ntlmssp_update(state->ntlmssp_state, msg_in, &blob_out);
1126 if (!NT_STATUS_IS_OK(status)
1127 && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1128 TALLOC_FREE(subreq);
1129 TALLOC_FREE(state->ntlmssp_state);
1130 tevent_req_nterror(req, status);
1131 return;
1134 state->blob_out = spnego_gen_auth(state, blob_out);
1135 TALLOC_FREE(subreq);
1136 if (tevent_req_nomem(state->blob_out.data, req)) {
1137 return;
1140 subreq = cli_sesssetup_blob_send(state, state->ev, state->cli,
1141 state->blob_out);
1142 if (tevent_req_nomem(subreq, req)) {
1143 return;
1145 tevent_req_set_callback(subreq, cli_session_setup_ntlmssp_done, req);
1148 static NTSTATUS cli_session_setup_ntlmssp_recv(struct tevent_req *req)
1150 struct cli_session_setup_ntlmssp_state *state = tevent_req_data(
1151 req, struct cli_session_setup_ntlmssp_state);
1152 NTSTATUS status;
1154 if (tevent_req_is_nterror(req, &status)) {
1155 state->cli->vuid = 0;
1156 return status;
1158 return NT_STATUS_OK;
1161 static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli,
1162 const char *user,
1163 const char *pass,
1164 const char *domain)
1166 struct tevent_context *ev;
1167 struct tevent_req *req;
1168 NTSTATUS status = NT_STATUS_NO_MEMORY;
1170 if (cli_has_async_calls(cli)) {
1171 return NT_STATUS_INVALID_PARAMETER;
1173 ev = tevent_context_init(talloc_tos());
1174 if (ev == NULL) {
1175 goto fail;
1177 req = cli_session_setup_ntlmssp_send(ev, ev, cli, user, pass, domain);
1178 if (req == NULL) {
1179 goto fail;
1181 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1182 goto fail;
1184 status = cli_session_setup_ntlmssp_recv(req);
1185 fail:
1186 TALLOC_FREE(ev);
1187 if (!NT_STATUS_IS_OK(status)) {
1188 cli_set_error(cli, status);
1190 return status;
1193 /****************************************************************************
1194 Do a spnego encrypted session setup.
1196 user_domain: The shortname of the domain the user/machine is a member of.
1197 dest_realm: The realm we're connecting to, if NULL we use our default realm.
1198 ****************************************************************************/
1200 ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, const char *user,
1201 const char *pass, const char *user_domain,
1202 const char * dest_realm)
1204 char *principal = NULL;
1205 char *OIDs[ASN1_MAX_OIDS];
1206 int i;
1207 DATA_BLOB blob;
1208 const char *p = NULL;
1209 char *account = NULL;
1210 NTSTATUS status;
1212 DEBUG(3,("Doing spnego session setup (blob length=%lu)\n", (unsigned long)cli->secblob.length));
1214 /* the server might not even do spnego */
1215 if (cli->secblob.length <= 16) {
1216 DEBUG(3,("server didn't supply a full spnego negprot\n"));
1217 goto ntlmssp;
1220 #if 0
1221 file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
1222 #endif
1224 /* there is 16 bytes of GUID before the real spnego packet starts */
1225 blob = data_blob(cli->secblob.data+16, cli->secblob.length-16);
1227 /* The server sent us the first part of the SPNEGO exchange in the
1228 * negprot reply. It is WRONG to depend on the principal sent in the
1229 * negprot reply, but right now we do it. If we don't receive one,
1230 * we try to best guess, then fall back to NTLM. */
1231 if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &principal, NULL)) {
1232 data_blob_free(&blob);
1233 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
1235 data_blob_free(&blob);
1237 /* make sure the server understands kerberos */
1238 for (i=0;OIDs[i];i++) {
1239 if (i == 0)
1240 DEBUG(3,("got OID=%s\n", OIDs[i]));
1241 else
1242 DEBUGADD(3,("got OID=%s\n", OIDs[i]));
1243 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
1244 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
1245 cli->got_kerberos_mechanism = True;
1247 talloc_free(OIDs[i]);
1250 DEBUG(3,("got principal=%s\n", principal ? principal : "<null>"));
1252 status = cli_set_username(cli, user);
1253 if (!NT_STATUS_IS_OK(status)) {
1254 TALLOC_FREE(principal);
1255 return ADS_ERROR_NT(status);
1258 #ifdef HAVE_KRB5
1259 /* If password is set we reauthenticate to kerberos server
1260 * and do not store results */
1262 if (cli->got_kerberos_mechanism && cli->use_kerberos) {
1263 ADS_STATUS rc;
1265 if (pass && *pass) {
1266 int ret;
1268 use_in_memory_ccache();
1269 ret = kerberos_kinit_password(user, pass, 0 /* no time correction for now */, NULL);
1271 if (ret){
1272 TALLOC_FREE(principal);
1273 DEBUG(0, ("Kinit failed: %s\n", error_message(ret)));
1274 if (cli->fallback_after_kerberos)
1275 goto ntlmssp;
1276 return ADS_ERROR_KRB5(ret);
1280 /* If we get a bad principal, try to guess it if
1281 we have a valid host NetBIOS name.
1283 if (strequal(principal, ADS_IGNORE_PRINCIPAL)) {
1284 TALLOC_FREE(principal);
1287 if (principal == NULL &&
1288 !is_ipaddress(cli->desthost) &&
1289 !strequal(STAR_SMBSERVER,
1290 cli->desthost)) {
1291 char *realm = NULL;
1292 char *machine = NULL;
1293 char *host = NULL;
1294 DEBUG(3,("cli_session_setup_spnego: got a "
1295 "bad server principal, trying to guess ...\n"));
1297 host = strchr_m(cli->desthost, '.');
1298 if (host) {
1299 /* We had a '.' in the name. */
1300 machine = SMB_STRNDUP(cli->desthost,
1301 host - cli->desthost);
1302 } else {
1303 machine = SMB_STRDUP(cli->desthost);
1305 if (machine == NULL) {
1306 TALLOC_FREE(principal);
1307 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1310 if (dest_realm) {
1311 realm = SMB_STRDUP(dest_realm);
1312 strupper_m(realm);
1313 } else {
1314 if (host) {
1315 /* DNS name. */
1316 realm = kerberos_get_realm_from_hostname(cli->desthost);
1317 } else {
1318 /* NetBIOS name - use our realm. */
1319 realm = kerberos_get_default_realm_from_ccache();
1323 if (realm && *realm) {
1324 if (host) {
1325 /* DNS name. */
1326 principal = talloc_asprintf(talloc_tos(),
1327 "cifs/%s@%s",
1328 cli->desthost,
1329 realm);
1330 } else {
1331 /* NetBIOS name, use machine account. */
1332 principal = talloc_asprintf(talloc_tos(),
1333 "%s$@%s",
1334 machine,
1335 realm);
1337 if (!principal) {
1338 SAFE_FREE(machine);
1339 SAFE_FREE(realm);
1340 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1342 DEBUG(3,("cli_session_setup_spnego: guessed "
1343 "server principal=%s\n",
1344 principal ? principal : "<null>"));
1346 SAFE_FREE(machine);
1347 SAFE_FREE(realm);
1350 if (principal) {
1351 rc = cli_session_setup_kerberos(cli, principal,
1352 dest_realm);
1353 if (ADS_ERR_OK(rc) || !cli->fallback_after_kerberos) {
1354 TALLOC_FREE(principal);
1355 return rc;
1359 #endif
1361 TALLOC_FREE(principal);
1363 ntlmssp:
1365 account = talloc_strdup(talloc_tos(), user);
1366 if (!account) {
1367 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1370 /* when falling back to ntlmssp while authenticating with a machine
1371 * account strip off the realm - gd */
1373 if ((p = strchr_m(user, '@')) != NULL) {
1374 account[PTR_DIFF(p,user)] = '\0';
1377 return ADS_ERROR_NT(cli_session_setup_ntlmssp(cli, account, pass, user_domain));
1380 /****************************************************************************
1381 Send a session setup. The username and workgroup is in UNIX character
1382 format and must be converted to DOS codepage format before sending. If the
1383 password is in plaintext, the same should be done.
1384 ****************************************************************************/
1386 NTSTATUS cli_session_setup(struct cli_state *cli,
1387 const char *user,
1388 const char *pass, int passlen,
1389 const char *ntpass, int ntpasslen,
1390 const char *workgroup)
1392 char *p;
1393 fstring user2;
1395 if (user) {
1396 fstrcpy(user2, user);
1397 } else {
1398 user2[0] ='\0';
1401 if (!workgroup) {
1402 workgroup = "";
1405 /* allow for workgroups as part of the username */
1406 if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/')) ||
1407 (p=strchr_m(user2,*lp_winbind_separator()))) {
1408 *p = 0;
1409 user = p+1;
1410 workgroup = user2;
1413 if (cli->protocol < PROTOCOL_LANMAN1) {
1414 return NT_STATUS_OK;
1417 /* now work out what sort of session setup we are going to
1418 do. I have split this into separate functions to make the
1419 flow a bit easier to understand (tridge) */
1421 /* if its an older server then we have to use the older request format */
1423 if (cli->protocol < PROTOCOL_NT1) {
1424 if (!lp_client_lanman_auth() && passlen != 24 && (*pass)) {
1425 DEBUG(1, ("Server requested LM password but 'client lanman auth'"
1426 " is disabled\n"));
1427 return NT_STATUS_ACCESS_DENIED;
1430 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0 &&
1431 !lp_client_plaintext_auth() && (*pass)) {
1432 DEBUG(1, ("Server requested plaintext password but "
1433 "'client plaintext auth' is disabled\n"));
1434 return NT_STATUS_ACCESS_DENIED;
1437 return cli_session_setup_lanman2(cli, user, pass, passlen,
1438 workgroup);
1441 /* if no user is supplied then we have to do an anonymous connection.
1442 passwords are ignored */
1444 if (!user || !*user)
1445 return cli_session_setup_guest(cli);
1447 /* if the server is share level then send a plaintext null
1448 password at this point. The password is sent in the tree
1449 connect */
1451 if ((cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) == 0)
1452 return cli_session_setup_plaintext(cli, user, "", workgroup);
1454 /* if the server doesn't support encryption then we have to use
1455 plaintext. The second password is ignored */
1457 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) {
1458 if (!lp_client_plaintext_auth() && (*pass)) {
1459 DEBUG(1, ("Server requested plaintext password but "
1460 "'client plaintext auth' is disabled\n"));
1461 return NT_STATUS_ACCESS_DENIED;
1463 return cli_session_setup_plaintext(cli, user, pass, workgroup);
1466 /* if the server supports extended security then use SPNEGO */
1468 if (cli->capabilities & CAP_EXTENDED_SECURITY) {
1469 ADS_STATUS status = cli_session_setup_spnego(cli, user, pass,
1470 workgroup, NULL);
1471 if (!ADS_ERR_OK(status)) {
1472 DEBUG(3, ("SPNEGO login failed: %s\n", ads_errstr(status)));
1473 return ads_ntstatus(status);
1475 } else {
1476 NTSTATUS status;
1478 /* otherwise do a NT1 style session setup */
1479 status = cli_session_setup_nt1(cli, user, pass, passlen,
1480 ntpass, ntpasslen, workgroup);
1481 if (!NT_STATUS_IS_OK(status)) {
1482 DEBUG(3,("cli_session_setup: NT1 session setup "
1483 "failed: %s\n", nt_errstr(status)));
1484 return status;
1488 if (strstr(cli->server_type, "Samba")) {
1489 cli->is_samba = True;
1492 return NT_STATUS_OK;
1495 /****************************************************************************
1496 Send a uloggoff.
1497 *****************************************************************************/
1499 struct cli_ulogoff_state {
1500 struct cli_state *cli;
1501 uint16_t vwv[3];
1504 static void cli_ulogoff_done(struct tevent_req *subreq);
1506 struct tevent_req *cli_ulogoff_send(TALLOC_CTX *mem_ctx,
1507 struct tevent_context *ev,
1508 struct cli_state *cli)
1510 struct tevent_req *req, *subreq;
1511 struct cli_ulogoff_state *state;
1513 req = tevent_req_create(mem_ctx, &state, struct cli_ulogoff_state);
1514 if (req == NULL) {
1515 return NULL;
1517 state->cli = cli;
1519 SCVAL(state->vwv+0, 0, 0xFF);
1520 SCVAL(state->vwv+1, 0, 0);
1521 SSVAL(state->vwv+2, 0, 0);
1523 subreq = cli_smb_send(state, ev, cli, SMBulogoffX, 0, 2, state->vwv,
1524 0, NULL);
1525 if (tevent_req_nomem(subreq, req)) {
1526 return tevent_req_post(req, ev);
1528 tevent_req_set_callback(subreq, cli_ulogoff_done, req);
1529 return req;
1532 static void cli_ulogoff_done(struct tevent_req *subreq)
1534 struct tevent_req *req = tevent_req_callback_data(
1535 subreq, struct tevent_req);
1536 struct cli_ulogoff_state *state = tevent_req_data(
1537 req, struct cli_ulogoff_state);
1538 NTSTATUS status;
1540 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1541 if (!NT_STATUS_IS_OK(status)) {
1542 tevent_req_nterror(req, status);
1543 return;
1545 state->cli->vuid = -1;
1546 tevent_req_done(req);
1549 NTSTATUS cli_ulogoff_recv(struct tevent_req *req)
1551 return tevent_req_simple_recv_ntstatus(req);
1554 NTSTATUS cli_ulogoff(struct cli_state *cli)
1556 struct tevent_context *ev;
1557 struct tevent_req *req;
1558 NTSTATUS status = NT_STATUS_NO_MEMORY;
1560 if (cli_has_async_calls(cli)) {
1561 return NT_STATUS_INVALID_PARAMETER;
1563 ev = tevent_context_init(talloc_tos());
1564 if (ev == NULL) {
1565 goto fail;
1567 req = cli_ulogoff_send(ev, ev, cli);
1568 if (req == NULL) {
1569 goto fail;
1571 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1572 goto fail;
1574 status = cli_ulogoff_recv(req);
1575 fail:
1576 TALLOC_FREE(ev);
1577 if (!NT_STATUS_IS_OK(status)) {
1578 cli_set_error(cli, status);
1580 return status;
1583 /****************************************************************************
1584 Send a tconX.
1585 ****************************************************************************/
1587 struct cli_tcon_andx_state {
1588 struct cli_state *cli;
1589 uint16_t vwv[4];
1590 struct iovec bytes;
1593 static void cli_tcon_andx_done(struct tevent_req *subreq);
1595 struct tevent_req *cli_tcon_andx_create(TALLOC_CTX *mem_ctx,
1596 struct event_context *ev,
1597 struct cli_state *cli,
1598 const char *share, const char *dev,
1599 const char *pass, int passlen,
1600 struct tevent_req **psmbreq)
1602 struct tevent_req *req, *subreq;
1603 struct cli_tcon_andx_state *state;
1604 fstring pword;
1605 uint16_t *vwv;
1606 char *tmp = NULL;
1607 uint8_t *bytes;
1609 *psmbreq = NULL;
1611 req = tevent_req_create(mem_ctx, &state, struct cli_tcon_andx_state);
1612 if (req == NULL) {
1613 return NULL;
1615 state->cli = cli;
1616 vwv = state->vwv;
1618 fstrcpy(cli->share, share);
1620 /* in user level security don't send a password now */
1621 if (cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) {
1622 passlen = 1;
1623 pass = "";
1624 } else if (pass == NULL) {
1625 DEBUG(1, ("Server not using user level security and no "
1626 "password supplied.\n"));
1627 goto access_denied;
1630 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) &&
1631 *pass && passlen != 24) {
1632 if (!lp_client_lanman_auth()) {
1633 DEBUG(1, ("Server requested LANMAN password "
1634 "(share-level security) but "
1635 "'client lanman auth' is disabled\n"));
1636 goto access_denied;
1640 * Non-encrypted passwords - convert to DOS codepage before
1641 * encryption.
1643 passlen = 24;
1644 SMBencrypt(pass, cli->secblob.data, (uchar *)pword);
1645 } else {
1646 if((cli->sec_mode & (NEGOTIATE_SECURITY_USER_LEVEL
1647 |NEGOTIATE_SECURITY_CHALLENGE_RESPONSE))
1648 == 0) {
1649 if (!lp_client_plaintext_auth() && (*pass)) {
1650 DEBUG(1, ("Server requested plaintext "
1651 "password but 'client plaintext "
1652 "auth' is disabled\n"));
1653 goto access_denied;
1657 * Non-encrypted passwords - convert to DOS codepage
1658 * before using.
1660 passlen = clistr_push(cli, pword, pass, sizeof(pword),
1661 STR_TERMINATE);
1662 if (passlen == -1) {
1663 DEBUG(1, ("clistr_push(pword) failed\n"));
1664 goto access_denied;
1666 } else {
1667 if (passlen) {
1668 memcpy(pword, pass, passlen);
1673 SCVAL(vwv+0, 0, 0xFF);
1674 SCVAL(vwv+0, 1, 0);
1675 SSVAL(vwv+1, 0, 0);
1676 SSVAL(vwv+2, 0, TCONX_FLAG_EXTENDED_RESPONSE);
1677 SSVAL(vwv+3, 0, passlen);
1679 if (passlen) {
1680 bytes = (uint8_t *)talloc_memdup(state, pword, passlen);
1681 } else {
1682 bytes = talloc_array(state, uint8_t, 0);
1686 * Add the sharename
1688 tmp = talloc_asprintf_strupper_m(talloc_tos(), "\\\\%s\\%s",
1689 cli->desthost, share);
1690 if (tmp == NULL) {
1691 TALLOC_FREE(req);
1692 return NULL;
1694 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), tmp, strlen(tmp)+1,
1695 NULL);
1696 TALLOC_FREE(tmp);
1699 * Add the devicetype
1701 tmp = talloc_strdup_upper(talloc_tos(), dev);
1702 if (tmp == NULL) {
1703 TALLOC_FREE(req);
1704 return NULL;
1706 bytes = smb_bytes_push_str(bytes, false, tmp, strlen(tmp)+1, NULL);
1707 TALLOC_FREE(tmp);
1709 if (bytes == NULL) {
1710 TALLOC_FREE(req);
1711 return NULL;
1714 state->bytes.iov_base = (void *)bytes;
1715 state->bytes.iov_len = talloc_get_size(bytes);
1717 subreq = cli_smb_req_create(state, ev, cli, SMBtconX, 0, 4, vwv,
1718 1, &state->bytes);
1719 if (subreq == NULL) {
1720 TALLOC_FREE(req);
1721 return NULL;
1723 tevent_req_set_callback(subreq, cli_tcon_andx_done, req);
1724 *psmbreq = subreq;
1725 return req;
1727 access_denied:
1728 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1729 return tevent_req_post(req, ev);
1732 struct tevent_req *cli_tcon_andx_send(TALLOC_CTX *mem_ctx,
1733 struct event_context *ev,
1734 struct cli_state *cli,
1735 const char *share, const char *dev,
1736 const char *pass, int passlen)
1738 struct tevent_req *req, *subreq;
1739 NTSTATUS status;
1741 req = cli_tcon_andx_create(mem_ctx, ev, cli, share, dev, pass, passlen,
1742 &subreq);
1743 if (req == NULL) {
1744 return NULL;
1746 if (subreq == NULL) {
1747 return req;
1749 status = cli_smb_req_send(subreq);
1750 if (!NT_STATUS_IS_OK(status)) {
1751 tevent_req_nterror(req, status);
1752 return tevent_req_post(req, ev);
1754 return req;
1757 static void cli_tcon_andx_done(struct tevent_req *subreq)
1759 struct tevent_req *req = tevent_req_callback_data(
1760 subreq, struct tevent_req);
1761 struct cli_tcon_andx_state *state = tevent_req_data(
1762 req, struct cli_tcon_andx_state);
1763 struct cli_state *cli = state->cli;
1764 uint8_t *in;
1765 char *inbuf;
1766 uint8_t wct;
1767 uint16_t *vwv;
1768 uint32_t num_bytes;
1769 uint8_t *bytes;
1770 NTSTATUS status;
1772 status = cli_smb_recv(subreq, state, &in, 0, &wct, &vwv,
1773 &num_bytes, &bytes);
1774 TALLOC_FREE(subreq);
1775 if (!NT_STATUS_IS_OK(status)) {
1776 tevent_req_nterror(req, status);
1777 return;
1780 inbuf = (char *)in;
1782 clistr_pull(inbuf, cli->dev, bytes, sizeof(fstring), num_bytes,
1783 STR_TERMINATE|STR_ASCII);
1785 if ((cli->protocol >= PROTOCOL_NT1) && (num_bytes == 3)) {
1786 /* almost certainly win95 - enable bug fixes */
1787 cli->win95 = True;
1791 * Make sure that we have the optional support 16-bit field. WCT > 2.
1792 * Avoids issues when connecting to Win9x boxes sharing files
1795 cli->dfsroot = false;
1797 if ((wct > 2) && (cli->protocol >= PROTOCOL_LANMAN2)) {
1798 cli->dfsroot = ((SVAL(vwv+2, 0) & SMB_SHARE_IN_DFS) != 0);
1801 cli->cnum = SVAL(inbuf,smb_tid);
1802 tevent_req_done(req);
1805 NTSTATUS cli_tcon_andx_recv(struct tevent_req *req)
1807 return tevent_req_simple_recv_ntstatus(req);
1810 NTSTATUS cli_tcon_andx(struct cli_state *cli, const char *share,
1811 const char *dev, const char *pass, int passlen)
1813 TALLOC_CTX *frame = talloc_stackframe();
1814 struct event_context *ev;
1815 struct tevent_req *req;
1816 NTSTATUS status = NT_STATUS_OK;
1818 if (cli_has_async_calls(cli)) {
1820 * Can't use sync call while an async call is in flight
1822 status = NT_STATUS_INVALID_PARAMETER;
1823 goto fail;
1826 ev = event_context_init(frame);
1827 if (ev == NULL) {
1828 status = NT_STATUS_NO_MEMORY;
1829 goto fail;
1832 req = cli_tcon_andx_send(frame, ev, cli, share, dev, pass, passlen);
1833 if (req == NULL) {
1834 status = NT_STATUS_NO_MEMORY;
1835 goto fail;
1838 if (!tevent_req_poll(req, ev)) {
1839 status = map_nt_error_from_unix(errno);
1840 goto fail;
1843 status = cli_tcon_andx_recv(req);
1844 fail:
1845 TALLOC_FREE(frame);
1846 if (!NT_STATUS_IS_OK(status)) {
1847 cli_set_error(cli, status);
1849 return status;
1852 /****************************************************************************
1853 Send a tree disconnect.
1854 ****************************************************************************/
1856 struct cli_tdis_state {
1857 struct cli_state *cli;
1860 static void cli_tdis_done(struct tevent_req *subreq);
1862 struct tevent_req *cli_tdis_send(TALLOC_CTX *mem_ctx,
1863 struct tevent_context *ev,
1864 struct cli_state *cli)
1866 struct tevent_req *req, *subreq;
1867 struct cli_tdis_state *state;
1869 req = tevent_req_create(mem_ctx, &state, struct cli_tdis_state);
1870 if (req == NULL) {
1871 return NULL;
1873 state->cli = cli;
1875 subreq = cli_smb_send(state, ev, cli, SMBtdis, 0, 0, NULL, 0, NULL);
1876 if (tevent_req_nomem(subreq, req)) {
1877 return tevent_req_post(req, ev);
1879 tevent_req_set_callback(subreq, cli_tdis_done, req);
1880 return req;
1883 static void cli_tdis_done(struct tevent_req *subreq)
1885 struct tevent_req *req = tevent_req_callback_data(
1886 subreq, struct tevent_req);
1887 struct cli_tdis_state *state = tevent_req_data(
1888 req, struct cli_tdis_state);
1889 NTSTATUS status;
1891 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1892 TALLOC_FREE(subreq);
1893 if (!NT_STATUS_IS_OK(status)) {
1894 tevent_req_nterror(req, status);
1895 return;
1897 state->cli->cnum = -1;
1898 tevent_req_done(req);
1901 NTSTATUS cli_tdis_recv(struct tevent_req *req)
1903 return tevent_req_simple_recv_ntstatus(req);
1906 NTSTATUS cli_tdis(struct cli_state *cli)
1908 struct tevent_context *ev;
1909 struct tevent_req *req;
1910 NTSTATUS status = NT_STATUS_NO_MEMORY;
1912 if (cli_has_async_calls(cli)) {
1913 return NT_STATUS_INVALID_PARAMETER;
1915 ev = tevent_context_init(talloc_tos());
1916 if (ev == NULL) {
1917 goto fail;
1919 req = cli_tdis_send(ev, ev, cli);
1920 if (req == NULL) {
1921 goto fail;
1923 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1924 goto fail;
1926 status = cli_tdis_recv(req);
1927 fail:
1928 TALLOC_FREE(ev);
1929 if (!NT_STATUS_IS_OK(status)) {
1930 cli_set_error(cli, status);
1932 return status;
1935 /****************************************************************************
1936 Send a negprot command.
1937 ****************************************************************************/
1939 void cli_negprot_sendsync(struct cli_state *cli)
1941 char *p;
1942 int numprots;
1944 if (cli->protocol < PROTOCOL_NT1)
1945 cli->use_spnego = False;
1947 memset(cli->outbuf,'\0',smb_size);
1949 /* setup the protocol strings */
1950 cli_set_message(cli->outbuf,0,0,True);
1952 p = smb_buf(cli->outbuf);
1953 for (numprots=0; numprots < ARRAY_SIZE(prots); numprots++) {
1954 if (prots[numprots].prot > cli->protocol) {
1955 break;
1957 *p++ = 2;
1958 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
1961 SCVAL(cli->outbuf,smb_com,SMBnegprot);
1962 cli_setup_bcc(cli, p);
1963 cli_setup_packet(cli);
1965 SCVAL(smb_buf(cli->outbuf),0,2);
1967 cli_send_smb(cli);
1970 /****************************************************************************
1971 Send a negprot command.
1972 ****************************************************************************/
1974 struct cli_negprot_state {
1975 struct cli_state *cli;
1978 static void cli_negprot_done(struct tevent_req *subreq);
1980 struct tevent_req *cli_negprot_send(TALLOC_CTX *mem_ctx,
1981 struct event_context *ev,
1982 struct cli_state *cli)
1984 struct tevent_req *req, *subreq;
1985 struct cli_negprot_state *state;
1986 uint8_t *bytes = NULL;
1987 int numprots;
1988 uint16_t cnum;
1990 req = tevent_req_create(mem_ctx, &state, struct cli_negprot_state);
1991 if (req == NULL) {
1992 return NULL;
1994 state->cli = cli;
1996 if (cli->protocol < PROTOCOL_NT1)
1997 cli->use_spnego = False;
1999 /* setup the protocol strings */
2000 for (numprots=0; numprots < ARRAY_SIZE(prots); numprots++) {
2001 uint8_t c = 2;
2002 if (prots[numprots].prot > cli->protocol) {
2003 break;
2005 bytes = (uint8_t *)talloc_append_blob(
2006 state, bytes, data_blob_const(&c, sizeof(c)));
2007 if (tevent_req_nomem(bytes, req)) {
2008 return tevent_req_post(req, ev);
2010 bytes = smb_bytes_push_str(bytes, false,
2011 prots[numprots].name,
2012 strlen(prots[numprots].name)+1,
2013 NULL);
2014 if (tevent_req_nomem(bytes, req)) {
2015 return tevent_req_post(req, ev);
2019 cnum = cli->cnum;
2021 cli->cnum = 0;
2022 subreq = cli_smb_send(state, ev, cli, SMBnegprot, 0, 0, NULL,
2023 talloc_get_size(bytes), bytes);
2024 cli->cnum = cnum;
2026 if (tevent_req_nomem(subreq, req)) {
2027 return tevent_req_post(req, ev);
2029 tevent_req_set_callback(subreq, cli_negprot_done, req);
2030 return req;
2033 static void cli_negprot_done(struct tevent_req *subreq)
2035 struct tevent_req *req = tevent_req_callback_data(
2036 subreq, struct tevent_req);
2037 struct cli_negprot_state *state = tevent_req_data(
2038 req, struct cli_negprot_state);
2039 struct cli_state *cli = state->cli;
2040 uint8_t wct;
2041 uint16_t *vwv;
2042 uint32_t num_bytes;
2043 uint8_t *bytes;
2044 NTSTATUS status;
2045 uint16_t protnum;
2046 uint8_t *inbuf;
2048 status = cli_smb_recv(subreq, state, &inbuf, 1, &wct, &vwv,
2049 &num_bytes, &bytes);
2050 TALLOC_FREE(subreq);
2051 if (!NT_STATUS_IS_OK(status)) {
2052 tevent_req_nterror(req, status);
2053 return;
2056 protnum = SVAL(vwv, 0);
2058 if ((protnum >= ARRAY_SIZE(prots))
2059 || (prots[protnum].prot > cli->protocol)) {
2060 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2061 return;
2064 cli->protocol = prots[protnum].prot;
2066 if ((cli->protocol < PROTOCOL_NT1) &&
2067 client_is_signing_mandatory(cli)) {
2068 DEBUG(0,("cli_negprot: SMB signing is mandatory and the selected protocol level doesn't support it.\n"));
2069 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
2070 return;
2073 if (cli->protocol >= PROTOCOL_NT1) {
2074 struct timespec ts;
2075 bool negotiated_smb_signing = false;
2077 /* NT protocol */
2078 cli->sec_mode = CVAL(vwv + 1, 0);
2079 cli->max_mux = SVAL(vwv + 1, 1);
2080 cli->max_xmit = IVAL(vwv + 3, 1);
2081 cli->sesskey = IVAL(vwv + 7, 1);
2082 cli->serverzone = SVALS(vwv + 15, 1);
2083 cli->serverzone *= 60;
2084 /* this time arrives in real GMT */
2085 ts = interpret_long_date(((char *)(vwv+11))+1);
2086 cli->servertime = ts.tv_sec;
2087 cli->secblob = data_blob(bytes, num_bytes);
2088 cli->capabilities = IVAL(vwv + 9, 1);
2089 if (cli->capabilities & CAP_RAW_MODE) {
2090 cli->readbraw_supported = True;
2091 cli->writebraw_supported = True;
2093 /* work out if they sent us a workgroup */
2094 if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
2095 smb_buflen(cli->inbuf) > 8) {
2096 clistr_pull(cli->inbuf, cli->server_domain,
2097 bytes+8, sizeof(cli->server_domain),
2098 num_bytes-8,
2099 STR_UNICODE|STR_NOALIGN);
2103 * As signing is slow we only turn it on if either the client or
2104 * the server require it. JRA.
2107 if (cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED) {
2108 /* Fail if server says signing is mandatory and we don't want to support it. */
2109 if (!client_is_signing_allowed(cli)) {
2110 DEBUG(0,("cli_negprot: SMB signing is mandatory and we have disabled it.\n"));
2111 tevent_req_nterror(req,
2112 NT_STATUS_ACCESS_DENIED);
2113 return;
2115 negotiated_smb_signing = true;
2116 } else if (client_is_signing_mandatory(cli) && client_is_signing_allowed(cli)) {
2117 /* Fail if client says signing is mandatory and the server doesn't support it. */
2118 if (!(cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED)) {
2119 DEBUG(1,("cli_negprot: SMB signing is mandatory and the server doesn't support it.\n"));
2120 tevent_req_nterror(req,
2121 NT_STATUS_ACCESS_DENIED);
2122 return;
2124 negotiated_smb_signing = true;
2125 } else if (cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) {
2126 negotiated_smb_signing = true;
2129 if (negotiated_smb_signing) {
2130 cli_set_signing_negotiated(cli);
2133 if (cli->capabilities & (CAP_LARGE_READX|CAP_LARGE_WRITEX)) {
2134 SAFE_FREE(cli->outbuf);
2135 SAFE_FREE(cli->inbuf);
2136 cli->outbuf = (char *)SMB_MALLOC(CLI_SAMBA_MAX_LARGE_READX_SIZE+LARGE_WRITEX_HDR_SIZE+SAFETY_MARGIN);
2137 cli->inbuf = (char *)SMB_MALLOC(CLI_SAMBA_MAX_LARGE_READX_SIZE+LARGE_WRITEX_HDR_SIZE+SAFETY_MARGIN);
2138 if (!cli->outbuf || !cli->inbuf) {
2139 tevent_req_nterror(req,
2140 NT_STATUS_NO_MEMORY);
2141 return;
2143 cli->bufsize = CLI_SAMBA_MAX_LARGE_READX_SIZE + LARGE_WRITEX_HDR_SIZE;
2146 } else if (cli->protocol >= PROTOCOL_LANMAN1) {
2147 cli->use_spnego = False;
2148 cli->sec_mode = SVAL(vwv + 1, 0);
2149 cli->max_xmit = SVAL(vwv + 2, 0);
2150 cli->max_mux = SVAL(vwv + 3, 0);
2151 cli->sesskey = IVAL(vwv + 6, 0);
2152 cli->serverzone = SVALS(vwv + 10, 0);
2153 cli->serverzone *= 60;
2154 /* this time is converted to GMT by make_unix_date */
2155 cli->servertime = make_unix_date(
2156 (char *)(vwv + 8), cli->serverzone);
2157 cli->readbraw_supported = ((SVAL(vwv + 5, 0) & 0x1) != 0);
2158 cli->writebraw_supported = ((SVAL(vwv + 5, 0) & 0x2) != 0);
2159 cli->secblob = data_blob(bytes, num_bytes);
2160 } else {
2161 /* the old core protocol */
2162 cli->use_spnego = False;
2163 cli->sec_mode = 0;
2164 cli->serverzone = get_time_zone(time(NULL));
2167 cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
2169 /* a way to force ascii SMB */
2170 if (getenv("CLI_FORCE_ASCII"))
2171 cli->capabilities &= ~CAP_UNICODE;
2173 tevent_req_done(req);
2176 NTSTATUS cli_negprot_recv(struct tevent_req *req)
2178 return tevent_req_simple_recv_ntstatus(req);
2181 NTSTATUS cli_negprot(struct cli_state *cli)
2183 TALLOC_CTX *frame = talloc_stackframe();
2184 struct event_context *ev;
2185 struct tevent_req *req;
2186 NTSTATUS status = NT_STATUS_OK;
2188 if (cli_has_async_calls(cli)) {
2190 * Can't use sync call while an async call is in flight
2192 status = NT_STATUS_INVALID_PARAMETER;
2193 goto fail;
2196 ev = event_context_init(frame);
2197 if (ev == NULL) {
2198 status = NT_STATUS_NO_MEMORY;
2199 goto fail;
2202 req = cli_negprot_send(frame, ev, cli);
2203 if (req == NULL) {
2204 status = NT_STATUS_NO_MEMORY;
2205 goto fail;
2208 if (!tevent_req_poll(req, ev)) {
2209 status = map_nt_error_from_unix(errno);
2210 goto fail;
2213 status = cli_negprot_recv(req);
2214 fail:
2215 TALLOC_FREE(frame);
2216 if (!NT_STATUS_IS_OK(status)) {
2217 cli_set_error(cli, status);
2219 return status;
2222 /****************************************************************************
2223 Send a session request. See rfc1002.txt 4.3 and 4.3.2.
2224 ****************************************************************************/
2226 bool cli_session_request(struct cli_state *cli,
2227 struct nmb_name *calling, struct nmb_name *called)
2229 char *p;
2230 int len = 4;
2231 char *tmp;
2233 /* 445 doesn't have session request */
2234 if (cli->port == 445)
2235 return True;
2237 memcpy(&(cli->calling), calling, sizeof(*calling));
2238 memcpy(&(cli->called ), called , sizeof(*called ));
2240 /* put in the destination name */
2242 tmp = name_mangle(talloc_tos(), cli->called.name,
2243 cli->called.name_type);
2244 if (tmp == NULL) {
2245 return false;
2248 p = cli->outbuf+len;
2249 memcpy(p, tmp, name_len(tmp));
2250 len += name_len(tmp);
2251 TALLOC_FREE(tmp);
2253 /* and my name */
2255 tmp = name_mangle(talloc_tos(), cli->calling.name,
2256 cli->calling.name_type);
2257 if (tmp == NULL) {
2258 return false;
2261 p = cli->outbuf+len;
2262 memcpy(p, tmp, name_len(tmp));
2263 len += name_len(tmp);
2264 TALLOC_FREE(tmp);
2266 /* send a session request (RFC 1002) */
2267 /* setup the packet length
2268 * Remove four bytes from the length count, since the length
2269 * field in the NBT Session Service header counts the number
2270 * of bytes which follow. The cli_send_smb() function knows
2271 * about this and accounts for those four bytes.
2272 * CRH.
2274 len -= 4;
2275 _smb_setlen(cli->outbuf,len);
2276 SCVAL(cli->outbuf,0,0x81);
2278 cli_send_smb(cli);
2279 DEBUG(5,("Sent session request\n"));
2281 if (!cli_receive_smb(cli))
2282 return False;
2284 if (CVAL(cli->inbuf,0) == 0x84) {
2285 /* C. Hoch 9/14/95 Start */
2286 /* For information, here is the response structure.
2287 * We do the byte-twiddling to for portability.
2288 struct RetargetResponse{
2289 unsigned char type;
2290 unsigned char flags;
2291 int16 length;
2292 int32 ip_addr;
2293 int16 port;
2296 uint16_t port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
2297 struct in_addr dest_ip;
2298 NTSTATUS status;
2300 /* SESSION RETARGET */
2301 putip((char *)&dest_ip,cli->inbuf+4);
2302 in_addr_to_sockaddr_storage(&cli->dest_ss, dest_ip);
2304 status = open_socket_out(&cli->dest_ss, port,
2305 LONG_CONNECT_TIMEOUT, &cli->fd);
2306 if (!NT_STATUS_IS_OK(status)) {
2307 return False;
2310 DEBUG(3,("Retargeted\n"));
2312 set_socket_options(cli->fd, lp_socket_options());
2314 /* Try again */
2316 static int depth;
2317 bool ret;
2318 if (depth > 4) {
2319 DEBUG(0,("Retarget recursion - failing\n"));
2320 return False;
2322 depth++;
2323 ret = cli_session_request(cli, calling, called);
2324 depth--;
2325 return ret;
2327 } /* C. Hoch 9/14/95 End */
2329 if (CVAL(cli->inbuf,0) != 0x82) {
2330 /* This is the wrong place to put the error... JRA. */
2331 cli->rap_error = CVAL(cli->inbuf,4);
2332 return False;
2334 return(True);
2337 struct fd_struct {
2338 int fd;
2341 static void smb_sock_connected(struct tevent_req *req)
2343 struct fd_struct *pfd = tevent_req_callback_data(
2344 req, struct fd_struct);
2345 int fd;
2346 NTSTATUS status;
2348 status = open_socket_out_defer_recv(req, &fd);
2349 if (NT_STATUS_IS_OK(status)) {
2350 pfd->fd = fd;
2354 static NTSTATUS open_smb_socket(const struct sockaddr_storage *pss,
2355 uint16_t *port, int timeout, int *pfd)
2357 struct event_context *ev;
2358 struct tevent_req *r139, *r445;
2359 struct fd_struct *fd139, *fd445;
2360 NTSTATUS status = NT_STATUS_NO_MEMORY;
2362 if (*port != 0) {
2363 return open_socket_out(pss, *port, timeout, pfd);
2366 ev = event_context_init(talloc_tos());
2367 if (ev == NULL) {
2368 return NT_STATUS_NO_MEMORY;
2371 fd139 = talloc(ev, struct fd_struct);
2372 if (fd139 == NULL) {
2373 goto done;
2375 fd139->fd = -1;
2377 fd445 = talloc(ev, struct fd_struct);
2378 if (fd445 == NULL) {
2379 goto done;
2381 fd445->fd = -1;
2383 r445 = open_socket_out_defer_send(ev, ev, timeval_set(0, 0),
2384 pss, 445, timeout);
2385 r139 = open_socket_out_defer_send(ev, ev, timeval_set(0, 3000),
2386 pss, 139, timeout);
2387 if ((r445 == NULL) || (r139 == NULL)) {
2388 goto done;
2390 tevent_req_set_callback(r445, smb_sock_connected, fd445);
2391 tevent_req_set_callback(r139, smb_sock_connected, fd139);
2393 while ((fd445->fd == -1) && (fd139->fd == -1)
2394 && (tevent_req_is_in_progress(r139)
2395 || tevent_req_is_in_progress(r445))) {
2396 event_loop_once(ev);
2399 if ((fd139->fd != -1) && (fd445->fd != -1)) {
2400 close(fd139->fd);
2401 fd139->fd = -1;
2404 if (fd445->fd != -1) {
2405 *port = 445;
2406 *pfd = fd445->fd;
2407 status = NT_STATUS_OK;
2408 goto done;
2410 if (fd139->fd != -1) {
2411 *port = 139;
2412 *pfd = fd139->fd;
2413 status = NT_STATUS_OK;
2414 goto done;
2417 status = open_socket_out_defer_recv(r445, &fd445->fd);
2418 done:
2419 TALLOC_FREE(ev);
2420 return status;
2423 /****************************************************************************
2424 Open the client sockets.
2425 ****************************************************************************/
2427 NTSTATUS cli_connect(struct cli_state *cli,
2428 const char *host,
2429 struct sockaddr_storage *dest_ss)
2432 int name_type = 0x20;
2433 TALLOC_CTX *frame = talloc_stackframe();
2434 unsigned int num_addrs = 0;
2435 unsigned int i = 0;
2436 struct sockaddr_storage *ss_arr = NULL;
2437 char *p = NULL;
2439 /* reasonable default hostname */
2440 if (!host) {
2441 host = STAR_SMBSERVER;
2444 fstrcpy(cli->desthost, host);
2446 /* allow hostnames of the form NAME#xx and do a netbios lookup */
2447 if ((p = strchr(cli->desthost, '#'))) {
2448 name_type = strtol(p+1, NULL, 16);
2449 *p = 0;
2452 if (!dest_ss || is_zero_addr((struct sockaddr *)dest_ss)) {
2453 NTSTATUS status =resolve_name_list(frame,
2454 cli->desthost,
2455 name_type,
2456 &ss_arr,
2457 &num_addrs);
2458 if (!NT_STATUS_IS_OK(status)) {
2459 TALLOC_FREE(frame);
2460 return NT_STATUS_BAD_NETWORK_NAME;
2462 } else {
2463 num_addrs = 1;
2464 ss_arr = TALLOC_P(frame, struct sockaddr_storage);
2465 if (!ss_arr) {
2466 TALLOC_FREE(frame);
2467 return NT_STATUS_NO_MEMORY;
2469 *ss_arr = *dest_ss;
2472 for (i = 0; i < num_addrs; i++) {
2473 cli->dest_ss = ss_arr[i];
2474 if (getenv("LIBSMB_PROG")) {
2475 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
2476 } else {
2477 uint16_t port = cli->port;
2478 NTSTATUS status;
2479 status = open_smb_socket(&cli->dest_ss, &port,
2480 cli->timeout, &cli->fd);
2481 if (NT_STATUS_IS_OK(status)) {
2482 cli->port = port;
2485 if (cli->fd == -1) {
2486 char addr[INET6_ADDRSTRLEN];
2487 print_sockaddr(addr, sizeof(addr), &ss_arr[i]);
2488 DEBUG(2,("Error connecting to %s (%s)\n",
2489 dest_ss?addr:host,strerror(errno)));
2490 } else {
2491 /* Exit from loop on first connection. */
2492 break;
2496 if (cli->fd == -1) {
2497 TALLOC_FREE(frame);
2498 return map_nt_error_from_unix(errno);
2501 if (dest_ss) {
2502 *dest_ss = cli->dest_ss;
2505 set_socket_options(cli->fd, lp_socket_options());
2507 TALLOC_FREE(frame);
2508 return NT_STATUS_OK;
2512 establishes a connection to after the negprot.
2513 @param output_cli A fully initialised cli structure, non-null only on success
2514 @param dest_host The netbios name of the remote host
2515 @param dest_ss (optional) The the destination IP, NULL for name based lookup
2516 @param port (optional) The destination port (0 for default)
2517 @param retry bool. Did this connection fail with a retryable error ?
2520 NTSTATUS cli_start_connection(struct cli_state **output_cli,
2521 const char *my_name,
2522 const char *dest_host,
2523 struct sockaddr_storage *dest_ss, int port,
2524 int signing_state, int flags,
2525 bool *retry)
2527 NTSTATUS nt_status;
2528 struct nmb_name calling;
2529 struct nmb_name called;
2530 struct cli_state *cli;
2531 struct sockaddr_storage ss;
2533 if (retry)
2534 *retry = False;
2536 if (!my_name)
2537 my_name = global_myname();
2539 if (!(cli = cli_initialise_ex(signing_state))) {
2540 return NT_STATUS_NO_MEMORY;
2543 make_nmb_name(&calling, my_name, 0x0);
2544 make_nmb_name(&called , dest_host, 0x20);
2546 cli_set_port(cli, port);
2547 cli_set_timeout(cli, 10000); /* 10 seconds. */
2549 if (dest_ss) {
2550 ss = *dest_ss;
2551 } else {
2552 zero_sockaddr(&ss);
2555 again:
2557 DEBUG(3,("Connecting to host=%s\n", dest_host));
2559 nt_status = cli_connect(cli, dest_host, &ss);
2560 if (!NT_STATUS_IS_OK(nt_status)) {
2561 char addr[INET6_ADDRSTRLEN];
2562 print_sockaddr(addr, sizeof(addr), &ss);
2563 DEBUG(1,("cli_start_connection: failed to connect to %s (%s). Error %s\n",
2564 nmb_namestr(&called), addr, nt_errstr(nt_status) ));
2565 cli_shutdown(cli);
2566 return nt_status;
2569 if (retry)
2570 *retry = True;
2572 if (!cli_session_request(cli, &calling, &called)) {
2573 char *p;
2574 DEBUG(1,("session request to %s failed (%s)\n",
2575 called.name, cli_errstr(cli)));
2576 if ((p=strchr(called.name, '.')) && !is_ipaddress(called.name)) {
2577 *p = 0;
2578 goto again;
2580 if (strcmp(called.name, STAR_SMBSERVER)) {
2581 make_nmb_name(&called , STAR_SMBSERVER, 0x20);
2582 goto again;
2584 return NT_STATUS_BAD_NETWORK_NAME;
2587 if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO)
2588 cli->use_spnego = False;
2589 else if (flags & CLI_FULL_CONNECTION_USE_KERBEROS)
2590 cli->use_kerberos = True;
2592 if ((flags & CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS) &&
2593 cli->use_kerberos) {
2594 cli->fallback_after_kerberos = true;
2596 if (flags & CLI_FULL_CONNECTION_USE_CCACHE) {
2597 cli->use_ccache = true;
2600 nt_status = cli_negprot(cli);
2601 if (!NT_STATUS_IS_OK(nt_status)) {
2602 DEBUG(1, ("failed negprot: %s\n", nt_errstr(nt_status)));
2603 cli_shutdown(cli);
2604 return nt_status;
2607 *output_cli = cli;
2608 return NT_STATUS_OK;
2613 establishes a connection right up to doing tconX, password specified.
2614 @param output_cli A fully initialised cli structure, non-null only on success
2615 @param dest_host The netbios name of the remote host
2616 @param dest_ip (optional) The the destination IP, NULL for name based lookup
2617 @param port (optional) The destination port (0 for default)
2618 @param service (optional) The share to make the connection to. Should be 'unqualified' in any way.
2619 @param service_type The 'type' of serivice.
2620 @param user Username, unix string
2621 @param domain User's domain
2622 @param password User's password, unencrypted unix string.
2623 @param retry bool. Did this connection fail with a retryable error ?
2626 NTSTATUS cli_full_connection(struct cli_state **output_cli,
2627 const char *my_name,
2628 const char *dest_host,
2629 struct sockaddr_storage *dest_ss, int port,
2630 const char *service, const char *service_type,
2631 const char *user, const char *domain,
2632 const char *password, int flags,
2633 int signing_state,
2634 bool *retry)
2636 NTSTATUS nt_status;
2637 struct cli_state *cli = NULL;
2638 int pw_len = password ? strlen(password)+1 : 0;
2640 *output_cli = NULL;
2642 if (password == NULL) {
2643 password = "";
2646 nt_status = cli_start_connection(&cli, my_name, dest_host,
2647 dest_ss, port, signing_state,
2648 flags, retry);
2650 if (!NT_STATUS_IS_OK(nt_status)) {
2651 return nt_status;
2654 cli->use_oplocks = ((flags & CLI_FULL_CONNECTION_OPLOCKS) != 0);
2655 cli->use_level_II_oplocks =
2656 ((flags & CLI_FULL_CONNECTION_LEVEL_II_OPLOCKS) != 0);
2658 nt_status = cli_session_setup(cli, user, password, pw_len, password,
2659 pw_len, domain);
2660 if (!NT_STATUS_IS_OK(nt_status)) {
2662 if (!(flags & CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK)) {
2663 DEBUG(1,("failed session setup with %s\n",
2664 nt_errstr(nt_status)));
2665 cli_shutdown(cli);
2666 return nt_status;
2669 nt_status = cli_session_setup(cli, "", "", 0, "", 0, domain);
2670 if (!NT_STATUS_IS_OK(nt_status)) {
2671 DEBUG(1,("anonymous failed session setup with %s\n",
2672 nt_errstr(nt_status)));
2673 cli_shutdown(cli);
2674 return nt_status;
2678 if (service) {
2679 nt_status = cli_tcon_andx(cli, service, service_type, password,
2680 pw_len);
2681 if (!NT_STATUS_IS_OK(nt_status)) {
2682 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(nt_status)));
2683 cli_shutdown(cli);
2684 if (NT_STATUS_IS_OK(nt_status)) {
2685 nt_status = NT_STATUS_UNSUCCESSFUL;
2687 return nt_status;
2691 nt_status = cli_init_creds(cli, user, domain, password);
2692 if (!NT_STATUS_IS_OK(nt_status)) {
2693 cli_shutdown(cli);
2694 return nt_status;
2697 *output_cli = cli;
2698 return NT_STATUS_OK;
2701 /****************************************************************************
2702 Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
2703 ****************************************************************************/
2705 bool attempt_netbios_session_request(struct cli_state **ppcli, const char *srchost, const char *desthost,
2706 struct sockaddr_storage *pdest_ss)
2708 struct nmb_name calling, called;
2710 make_nmb_name(&calling, srchost, 0x0);
2713 * If the called name is an IP address
2714 * then use *SMBSERVER immediately.
2717 if(is_ipaddress(desthost)) {
2718 make_nmb_name(&called, STAR_SMBSERVER, 0x20);
2719 } else {
2720 make_nmb_name(&called, desthost, 0x20);
2723 if (!cli_session_request(*ppcli, &calling, &called)) {
2724 NTSTATUS status;
2725 struct nmb_name smbservername;
2727 make_nmb_name(&smbservername, STAR_SMBSERVER, 0x20);
2730 * If the name wasn't *SMBSERVER then
2731 * try with *SMBSERVER if the first name fails.
2734 if (nmb_name_equal(&called, &smbservername)) {
2737 * The name used was *SMBSERVER, don't bother with another name.
2740 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
2741 with error %s.\n", desthost, cli_errstr(*ppcli) ));
2742 return False;
2745 /* Try again... */
2746 cli_shutdown(*ppcli);
2748 *ppcli = cli_initialise();
2749 if (!*ppcli) {
2750 /* Out of memory... */
2751 return False;
2754 status = cli_connect(*ppcli, desthost, pdest_ss);
2755 if (!NT_STATUS_IS_OK(status) ||
2756 !cli_session_request(*ppcli, &calling, &smbservername)) {
2757 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
2758 name *SMBSERVER with error %s\n", desthost, cli_errstr(*ppcli) ));
2759 return False;
2763 return True;
2766 /****************************************************************************
2767 Send an old style tcon.
2768 ****************************************************************************/
2769 NTSTATUS cli_raw_tcon(struct cli_state *cli,
2770 const char *service, const char *pass, const char *dev,
2771 uint16 *max_xmit, uint16 *tid)
2773 char *p;
2775 if (!lp_client_plaintext_auth() && (*pass)) {
2776 DEBUG(1, ("Server requested plaintext password but 'client "
2777 "plaintext auth' is disabled\n"));
2778 return NT_STATUS_ACCESS_DENIED;
2781 memset(cli->outbuf,'\0',smb_size);
2782 memset(cli->inbuf,'\0',smb_size);
2784 cli_set_message(cli->outbuf, 0, 0, True);
2785 SCVAL(cli->outbuf,smb_com,SMBtcon);
2786 cli_setup_packet(cli);
2788 p = smb_buf(cli->outbuf);
2789 *p++ = 4; p += clistr_push(cli, p, service, -1, STR_TERMINATE | STR_NOALIGN);
2790 *p++ = 4; p += clistr_push(cli, p, pass, -1, STR_TERMINATE | STR_NOALIGN);
2791 *p++ = 4; p += clistr_push(cli, p, dev, -1, STR_TERMINATE | STR_NOALIGN);
2793 cli_setup_bcc(cli, p);
2795 cli_send_smb(cli);
2796 if (!cli_receive_smb(cli)) {
2797 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
2800 if (cli_is_error(cli)) {
2801 return cli_nt_error(cli);
2804 *max_xmit = SVAL(cli->inbuf, smb_vwv0);
2805 *tid = SVAL(cli->inbuf, smb_vwv1);
2807 return NT_STATUS_OK;
2810 /* Return a cli_state pointing at the IPC$ share for the given server */
2812 struct cli_state *get_ipc_connect(char *server,
2813 struct sockaddr_storage *server_ss,
2814 const struct user_auth_info *user_info)
2816 struct cli_state *cli;
2817 NTSTATUS nt_status;
2818 uint32_t flags = CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK;
2820 if (user_info->use_kerberos) {
2821 flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
2824 nt_status = cli_full_connection(&cli, NULL, server, server_ss, 0, "IPC$", "IPC",
2825 user_info->username ? user_info->username : "",
2826 lp_workgroup(),
2827 user_info->password ? user_info->password : "",
2828 flags,
2829 Undefined, NULL);
2831 if (NT_STATUS_IS_OK(nt_status)) {
2832 return cli;
2833 } else if (is_ipaddress(server)) {
2834 /* windows 9* needs a correct NMB name for connections */
2835 fstring remote_name;
2837 if (name_status_find("*", 0, 0, server_ss, remote_name)) {
2838 cli = get_ipc_connect(remote_name, server_ss, user_info);
2839 if (cli)
2840 return cli;
2843 return NULL;
2847 * Given the IP address of a master browser on the network, return its
2848 * workgroup and connect to it.
2850 * This function is provided to allow additional processing beyond what
2851 * get_ipc_connect_master_ip_bcast() does, e.g. to retrieve the list of master
2852 * browsers and obtain each master browsers' list of domains (in case the
2853 * first master browser is recently on the network and has not yet
2854 * synchronized with other master browsers and therefore does not yet have the
2855 * entire network browse list)
2858 struct cli_state *get_ipc_connect_master_ip(TALLOC_CTX *ctx,
2859 struct ip_service *mb_ip,
2860 const struct user_auth_info *user_info,
2861 char **pp_workgroup_out)
2863 char addr[INET6_ADDRSTRLEN];
2864 fstring name;
2865 struct cli_state *cli;
2866 struct sockaddr_storage server_ss;
2868 *pp_workgroup_out = NULL;
2870 print_sockaddr(addr, sizeof(addr), &mb_ip->ss);
2871 DEBUG(99, ("Looking up name of master browser %s\n",
2872 addr));
2875 * Do a name status query to find out the name of the master browser.
2876 * We use <01><02>__MSBROWSE__<02>#01 if *#00 fails because a domain
2877 * master browser will not respond to a wildcard query (or, at least,
2878 * an NT4 server acting as the domain master browser will not).
2880 * We might be able to use ONLY the query on MSBROWSE, but that's not
2881 * yet been tested with all Windows versions, so until it is, leave
2882 * the original wildcard query as the first choice and fall back to
2883 * MSBROWSE if the wildcard query fails.
2885 if (!name_status_find("*", 0, 0x1d, &mb_ip->ss, name) &&
2886 !name_status_find(MSBROWSE, 1, 0x1d, &mb_ip->ss, name)) {
2888 DEBUG(99, ("Could not retrieve name status for %s\n",
2889 addr));
2890 return NULL;
2893 if (!find_master_ip(name, &server_ss)) {
2894 DEBUG(99, ("Could not find master ip for %s\n", name));
2895 return NULL;
2898 *pp_workgroup_out = talloc_strdup(ctx, name);
2900 DEBUG(4, ("found master browser %s, %s\n", name, addr));
2902 print_sockaddr(addr, sizeof(addr), &server_ss);
2903 cli = get_ipc_connect(addr, &server_ss, user_info);
2905 return cli;
2909 * Return the IP address and workgroup of a master browser on the network, and
2910 * connect to it.
2913 struct cli_state *get_ipc_connect_master_ip_bcast(TALLOC_CTX *ctx,
2914 const struct user_auth_info *user_info,
2915 char **pp_workgroup_out)
2917 struct ip_service *ip_list;
2918 struct cli_state *cli;
2919 int i, count;
2921 *pp_workgroup_out = NULL;
2923 DEBUG(99, ("Do broadcast lookup for workgroups on local network\n"));
2925 /* Go looking for workgroups by broadcasting on the local network */
2927 if (!NT_STATUS_IS_OK(name_resolve_bcast(MSBROWSE, 1, &ip_list,
2928 &count))) {
2929 DEBUG(99, ("No master browsers responded\n"));
2930 return False;
2933 for (i = 0; i < count; i++) {
2934 char addr[INET6_ADDRSTRLEN];
2935 print_sockaddr(addr, sizeof(addr), &ip_list[i].ss);
2936 DEBUG(99, ("Found master browser %s\n", addr));
2938 cli = get_ipc_connect_master_ip(ctx, &ip_list[i],
2939 user_info, pp_workgroup_out);
2940 if (cli)
2941 return(cli);
2944 return NULL;