s3: Explicitly handle inbuf in cli_session_setup_guest_done
[Samba/nascimento.git] / source3 / libsmb / cliconnect.c
blobf24582df0045dc8b278943f5bf2a1c1f0d92a802
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 "../libcli/auth/libcli_auth.h"
23 #include "../libcli/auth/spnego.h"
24 #include "smb_krb5.h"
25 #include "ntlmssp.h"
27 static const struct {
28 int prot;
29 const char name[24];
30 } prots[10] = {
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, "LANMAN2.1"},
38 {PROTOCOL_LANMAN2, "Samba"},
39 {PROTOCOL_NT1, "NT LANMAN 1.0"},
40 {PROTOCOL_NT1, "NT LM 0.12"},
43 #define STAR_SMBSERVER "*SMBSERVER"
45 /**
46 * Set the user session key for a connection
47 * @param cli The cli structure to add it too
48 * @param session_key The session key used. (A copy of this is taken for the cli struct)
52 static void cli_set_session_key (struct cli_state *cli, const DATA_BLOB session_key)
54 cli->user_session_key = data_blob(session_key.data, session_key.length);
57 /****************************************************************************
58 Do an old lanman2 style session setup.
59 ****************************************************************************/
61 static NTSTATUS cli_session_setup_lanman2(struct cli_state *cli,
62 const char *user,
63 const char *pass, size_t passlen,
64 const char *workgroup)
66 DATA_BLOB session_key = data_blob_null;
67 DATA_BLOB lm_response = data_blob_null;
68 NTSTATUS status;
69 fstring pword;
70 char *p;
72 if (passlen > sizeof(pword)-1) {
73 return NT_STATUS_INVALID_PARAMETER;
76 /* LANMAN servers predate NT status codes and Unicode and ignore those
77 smb flags so we must disable the corresponding default capabilities
78 that would otherwise cause the Unicode and NT Status flags to be
79 set (and even returned by the server) */
81 cli->capabilities &= ~(CAP_UNICODE | CAP_STATUS32);
83 /* if in share level security then don't send a password now */
84 if (!(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL))
85 passlen = 0;
87 if (passlen > 0 && (cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen != 24) {
88 /* Encrypted mode needed, and non encrypted password supplied. */
89 lm_response = data_blob(NULL, 24);
90 if (!SMBencrypt(pass, cli->secblob.data,(uchar *)lm_response.data)) {
91 DEBUG(1, ("Password is > 14 chars in length, and is therefore incompatible with Lanman authentication\n"));
92 return NT_STATUS_ACCESS_DENIED;
94 } else if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen == 24) {
95 /* Encrypted mode needed, and encrypted password supplied. */
96 lm_response = data_blob(pass, passlen);
97 } else if (passlen > 0) {
98 /* Plaintext mode needed, assume plaintext supplied. */
99 passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
100 lm_response = data_blob(pass, passlen);
103 /* send a session setup command */
104 memset(cli->outbuf,'\0',smb_size);
105 cli_set_message(cli->outbuf,10, 0, True);
106 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
107 cli_setup_packet(cli);
109 SCVAL(cli->outbuf,smb_vwv0,0xFF);
110 SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
111 SSVAL(cli->outbuf,smb_vwv3,2);
112 SSVAL(cli->outbuf,smb_vwv4,1);
113 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
114 SSVAL(cli->outbuf,smb_vwv7,lm_response.length);
116 p = smb_buf(cli->outbuf);
117 memcpy(p,lm_response.data,lm_response.length);
118 p += lm_response.length;
119 p += clistr_push(cli, p, user, -1, STR_TERMINATE|STR_UPPER);
120 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
121 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
122 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
123 cli_setup_bcc(cli, p);
125 if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
126 return cli_nt_error(cli);
129 show_msg(cli->inbuf);
131 if (cli_is_error(cli)) {
132 return cli_nt_error(cli);
135 /* use the returned vuid from now on */
136 cli->vuid = SVAL(cli->inbuf,smb_uid);
137 status = cli_set_username(cli, user);
138 if (!NT_STATUS_IS_OK(status)) {
139 return status;
142 if (session_key.data) {
143 /* Have plaintext orginal */
144 cli_set_session_key(cli, session_key);
147 return NT_STATUS_OK;
150 /****************************************************************************
151 Work out suitable capabilities to offer the server.
152 ****************************************************************************/
154 static uint32 cli_session_setup_capabilities(struct cli_state *cli)
156 uint32 capabilities = CAP_NT_SMBS;
158 if (!cli->force_dos_errors)
159 capabilities |= CAP_STATUS32;
161 if (cli->use_level_II_oplocks)
162 capabilities |= CAP_LEVEL_II_OPLOCKS;
164 capabilities |= (cli->capabilities & (CAP_UNICODE|CAP_LARGE_FILES|CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_DFS));
165 return capabilities;
168 /****************************************************************************
169 Do a NT1 guest session setup.
170 ****************************************************************************/
172 struct cli_session_setup_guest_state {
173 struct cli_state *cli;
174 uint16_t vwv[16];
175 struct iovec bytes;
178 static void cli_session_setup_guest_done(struct tevent_req *subreq);
180 struct tevent_req *cli_session_setup_guest_create(TALLOC_CTX *mem_ctx,
181 struct event_context *ev,
182 struct cli_state *cli,
183 struct tevent_req **psmbreq)
185 struct tevent_req *req, *subreq;
186 struct cli_session_setup_guest_state *state;
187 uint16_t *vwv;
188 uint8_t *bytes;
190 req = tevent_req_create(mem_ctx, &state,
191 struct cli_session_setup_guest_state);
192 if (req == NULL) {
193 return NULL;
195 state->cli = cli;
196 vwv = state->vwv;
198 SCVAL(vwv+0, 0, 0xFF);
199 SCVAL(vwv+0, 1, 0);
200 SSVAL(vwv+1, 0, 0);
201 SSVAL(vwv+2, 0, CLI_BUFFER_SIZE);
202 SSVAL(vwv+3, 0, 2);
203 SSVAL(vwv+4, 0, cli->pid);
204 SIVAL(vwv+5, 0, cli->sesskey);
205 SSVAL(vwv+7, 0, 0);
206 SSVAL(vwv+8, 0, 0);
207 SSVAL(vwv+9, 0, 0);
208 SSVAL(vwv+10, 0, 0);
209 SIVAL(vwv+11, 0, cli_session_setup_capabilities(cli));
211 bytes = talloc_array(state, uint8_t, 0);
213 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "", 1, /* username */
214 NULL);
215 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "", 1, /* workgroup */
216 NULL);
217 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "Unix", 5, NULL);
218 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "Samba", 6, NULL);
220 if (bytes == NULL) {
221 TALLOC_FREE(req);
222 return NULL;
225 state->bytes.iov_base = (void *)bytes;
226 state->bytes.iov_len = talloc_get_size(bytes);
228 subreq = cli_smb_req_create(state, ev, cli, SMBsesssetupX, 0, 13, vwv,
229 1, &state->bytes);
230 if (subreq == NULL) {
231 TALLOC_FREE(req);
232 return NULL;
234 tevent_req_set_callback(subreq, cli_session_setup_guest_done, req);
235 *psmbreq = subreq;
236 return req;
239 struct tevent_req *cli_session_setup_guest_send(TALLOC_CTX *mem_ctx,
240 struct event_context *ev,
241 struct cli_state *cli)
243 struct tevent_req *req, *subreq;
244 NTSTATUS status;
246 req = cli_session_setup_guest_create(mem_ctx, ev, cli, &subreq);
247 if (req == NULL) {
248 return NULL;
251 status = cli_smb_req_send(subreq);
252 if (NT_STATUS_IS_OK(status)) {
253 tevent_req_nterror(req, status);
254 return tevent_req_post(req, ev);
256 return req;
259 static void cli_session_setup_guest_done(struct tevent_req *subreq)
261 struct tevent_req *req = tevent_req_callback_data(
262 subreq, struct tevent_req);
263 struct cli_session_setup_guest_state *state = tevent_req_data(
264 req, struct cli_session_setup_guest_state);
265 struct cli_state *cli = state->cli;
266 uint32_t num_bytes;
267 uint8_t *in;
268 char *inbuf;
269 uint8_t *bytes;
270 uint8_t *p;
271 NTSTATUS status;
273 status = cli_smb_recv(subreq, state, &in, 0, NULL, NULL,
274 &num_bytes, &bytes);
275 TALLOC_FREE(subreq);
276 if (!NT_STATUS_IS_OK(status)) {
277 tevent_req_nterror(req, status);
278 return;
281 inbuf = (char *)in;
282 p = bytes;
284 cli->vuid = SVAL(inbuf, smb_uid);
286 p += clistr_pull(inbuf, cli->server_os, (char *)p, sizeof(fstring),
287 bytes+num_bytes-p, STR_TERMINATE);
288 p += clistr_pull(inbuf, cli->server_type, (char *)p, sizeof(fstring),
289 bytes+num_bytes-p, STR_TERMINATE);
290 p += clistr_pull(inbuf, cli->server_domain, (char *)p, sizeof(fstring),
291 bytes+num_bytes-p, STR_TERMINATE);
293 if (strstr(cli->server_type, "Samba")) {
294 cli->is_samba = True;
297 status = cli_set_username(cli, "");
298 if (!NT_STATUS_IS_OK(status)) {
299 tevent_req_nterror(req, status);
300 return;
302 tevent_req_done(req);
305 NTSTATUS cli_session_setup_guest_recv(struct tevent_req *req)
307 return tevent_req_simple_recv_ntstatus(req);
310 static NTSTATUS cli_session_setup_guest(struct cli_state *cli)
312 TALLOC_CTX *frame = talloc_stackframe();
313 struct event_context *ev;
314 struct tevent_req *req;
315 NTSTATUS status = NT_STATUS_OK;
317 if (cli_has_async_calls(cli)) {
319 * Can't use sync call while an async call is in flight
321 status = NT_STATUS_INVALID_PARAMETER;
322 goto fail;
325 ev = event_context_init(frame);
326 if (ev == NULL) {
327 status = NT_STATUS_NO_MEMORY;
328 goto fail;
331 req = cli_session_setup_guest_send(frame, ev, cli);
332 if (req == NULL) {
333 status = NT_STATUS_NO_MEMORY;
334 goto fail;
337 if (!tevent_req_poll(req, ev)) {
338 status = map_nt_error_from_unix(errno);
339 goto fail;
342 status = cli_session_setup_guest_recv(req);
343 fail:
344 TALLOC_FREE(frame);
345 if (!NT_STATUS_IS_OK(status)) {
346 cli_set_error(cli, status);
348 return status;
351 /****************************************************************************
352 Do a NT1 plaintext session setup.
353 ****************************************************************************/
355 static NTSTATUS cli_session_setup_plaintext(struct cli_state *cli,
356 const char *user, const char *pass,
357 const char *workgroup)
359 uint32 capabilities = cli_session_setup_capabilities(cli);
360 char *p;
361 NTSTATUS status;
362 fstring lanman;
364 fstr_sprintf( lanman, "Samba %s", samba_version_string());
366 memset(cli->outbuf, '\0', smb_size);
367 cli_set_message(cli->outbuf,13,0,True);
368 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
369 cli_setup_packet(cli);
371 SCVAL(cli->outbuf,smb_vwv0,0xFF);
372 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
373 SSVAL(cli->outbuf,smb_vwv3,2);
374 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
375 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
376 SSVAL(cli->outbuf,smb_vwv8,0);
377 SIVAL(cli->outbuf,smb_vwv11,capabilities);
378 p = smb_buf(cli->outbuf);
380 /* check wether to send the ASCII or UNICODE version of the password */
382 if ( (capabilities & CAP_UNICODE) == 0 ) {
383 p += clistr_push(cli, p, pass, -1, STR_TERMINATE); /* password */
384 SSVAL(cli->outbuf,smb_vwv7,PTR_DIFF(p, smb_buf(cli->outbuf)));
386 else {
387 /* For ucs2 passwords clistr_push calls ucs2_align, which causes
388 * the space taken by the unicode password to be one byte too
389 * long (as we're on an odd byte boundary here). Reduce the
390 * count by 1 to cope with this. Fixes smbclient against NetApp
391 * servers which can't cope. Fix from
392 * bryan.kolodziej@allenlund.com in bug #3840.
394 p += clistr_push(cli, p, pass, -1, STR_UNICODE|STR_TERMINATE); /* unicode password */
395 SSVAL(cli->outbuf,smb_vwv8,PTR_DIFF(p, smb_buf(cli->outbuf))-1);
398 p += clistr_push(cli, p, user, -1, STR_TERMINATE); /* username */
399 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE); /* workgroup */
400 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
401 p += clistr_push(cli, p, lanman, -1, STR_TERMINATE);
402 cli_setup_bcc(cli, p);
404 if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
405 return cli_nt_error(cli);
408 show_msg(cli->inbuf);
410 if (cli_is_error(cli)) {
411 return cli_nt_error(cli);
414 cli->vuid = SVAL(cli->inbuf,smb_uid);
415 p = smb_buf(cli->inbuf);
416 p += clistr_pull(cli->inbuf, cli->server_os, p, sizeof(fstring),
417 -1, STR_TERMINATE);
418 p += clistr_pull(cli->inbuf, cli->server_type, p, sizeof(fstring),
419 -1, STR_TERMINATE);
420 p += clistr_pull(cli->inbuf, cli->server_domain, p, sizeof(fstring),
421 -1, STR_TERMINATE);
422 status = cli_set_username(cli, user);
423 if (!NT_STATUS_IS_OK(status)) {
424 return status;
426 if (strstr(cli->server_type, "Samba")) {
427 cli->is_samba = True;
430 return NT_STATUS_OK;
433 /****************************************************************************
434 do a NT1 NTLM/LM encrypted session setup - for when extended security
435 is not negotiated.
436 @param cli client state to create do session setup on
437 @param user username
438 @param pass *either* cleartext password (passlen !=24) or LM response.
439 @param ntpass NT response, implies ntpasslen >=24, implies pass is not clear
440 @param workgroup The user's domain.
441 ****************************************************************************/
443 static NTSTATUS cli_session_setup_nt1(struct cli_state *cli, const char *user,
444 const char *pass, size_t passlen,
445 const char *ntpass, size_t ntpasslen,
446 const char *workgroup)
448 uint32 capabilities = cli_session_setup_capabilities(cli);
449 DATA_BLOB lm_response = data_blob_null;
450 DATA_BLOB nt_response = data_blob_null;
451 DATA_BLOB session_key = data_blob_null;
452 NTSTATUS result;
453 char *p;
454 bool ok;
456 if (passlen == 0) {
457 /* do nothing - guest login */
458 } else if (passlen != 24) {
459 if (lp_client_ntlmv2_auth()) {
460 DATA_BLOB server_chal;
461 DATA_BLOB names_blob;
462 server_chal = data_blob(cli->secblob.data, MIN(cli->secblob.length, 8));
464 /* note that the 'workgroup' here is a best guess - we don't know
465 the server's domain at this point. The 'server name' is also
466 dodgy...
468 names_blob = NTLMv2_generate_names_blob(NULL, cli->called.name, workgroup);
470 if (!SMBNTLMv2encrypt(NULL, user, workgroup, pass, &server_chal,
471 &names_blob,
472 &lm_response, &nt_response, NULL, &session_key)) {
473 data_blob_free(&names_blob);
474 data_blob_free(&server_chal);
475 return NT_STATUS_ACCESS_DENIED;
477 data_blob_free(&names_blob);
478 data_blob_free(&server_chal);
480 } else {
481 uchar nt_hash[16];
482 E_md4hash(pass, nt_hash);
484 #ifdef LANMAN_ONLY
485 nt_response = data_blob_null;
486 #else
487 nt_response = data_blob(NULL, 24);
488 SMBNTencrypt(pass,cli->secblob.data,nt_response.data);
489 #endif
490 /* non encrypted password supplied. Ignore ntpass. */
491 if (lp_client_lanman_auth()) {
492 lm_response = data_blob(NULL, 24);
493 if (!SMBencrypt(pass,cli->secblob.data, lm_response.data)) {
494 /* Oops, the LM response is invalid, just put
495 the NT response there instead */
496 data_blob_free(&lm_response);
497 lm_response = data_blob(nt_response.data, nt_response.length);
499 } else {
500 /* LM disabled, place NT# in LM field instead */
501 lm_response = data_blob(nt_response.data, nt_response.length);
504 session_key = data_blob(NULL, 16);
505 #ifdef LANMAN_ONLY
506 E_deshash(pass, session_key.data);
507 memset(&session_key.data[8], '\0', 8);
508 #else
509 SMBsesskeygen_ntv1(nt_hash, session_key.data);
510 #endif
512 cli_temp_set_signing(cli);
513 } else {
514 /* pre-encrypted password supplied. Only used for
515 security=server, can't do
516 signing because we don't have original key */
518 lm_response = data_blob(pass, passlen);
519 nt_response = data_blob(ntpass, ntpasslen);
522 /* send a session setup command */
523 memset(cli->outbuf,'\0',smb_size);
525 cli_set_message(cli->outbuf,13,0,True);
526 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
527 cli_setup_packet(cli);
529 SCVAL(cli->outbuf,smb_vwv0,0xFF);
530 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
531 SSVAL(cli->outbuf,smb_vwv3,2);
532 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
533 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
534 SSVAL(cli->outbuf,smb_vwv7,lm_response.length);
535 SSVAL(cli->outbuf,smb_vwv8,nt_response.length);
536 SIVAL(cli->outbuf,smb_vwv11,capabilities);
537 p = smb_buf(cli->outbuf);
538 if (lm_response.length) {
539 memcpy(p,lm_response.data, lm_response.length); p += lm_response.length;
541 if (nt_response.length) {
542 memcpy(p,nt_response.data, nt_response.length); p += nt_response.length;
544 p += clistr_push(cli, p, user, -1, STR_TERMINATE);
546 /* Upper case here might help some NTLMv2 implementations */
547 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
548 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
549 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
550 cli_setup_bcc(cli, p);
552 if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
553 result = cli_nt_error(cli);
554 goto end;
557 /* show_msg(cli->inbuf); */
559 if (cli_is_error(cli)) {
560 result = cli_nt_error(cli);
561 goto end;
564 #ifdef LANMAN_ONLY
565 ok = cli_simple_set_signing(cli, session_key, lm_response);
566 #else
567 ok = cli_simple_set_signing(cli, session_key, nt_response);
568 #endif
569 if (ok) {
570 if (!cli_check_sign_mac(cli, cli->inbuf, 1)) {
571 result = NT_STATUS_ACCESS_DENIED;
572 goto end;
576 /* use the returned vuid from now on */
577 cli->vuid = SVAL(cli->inbuf,smb_uid);
579 p = smb_buf(cli->inbuf);
580 p += clistr_pull(cli->inbuf, cli->server_os, p, sizeof(fstring),
581 -1, STR_TERMINATE);
582 p += clistr_pull(cli->inbuf, cli->server_type, p, sizeof(fstring),
583 -1, STR_TERMINATE);
584 p += clistr_pull(cli->inbuf, cli->server_domain, p, sizeof(fstring),
585 -1, STR_TERMINATE);
587 if (strstr(cli->server_type, "Samba")) {
588 cli->is_samba = True;
591 result = cli_set_username(cli, user);
592 if (!NT_STATUS_IS_OK(result)) {
593 goto end;
596 if (session_key.data) {
597 /* Have plaintext orginal */
598 cli_set_session_key(cli, session_key);
601 result = NT_STATUS_OK;
602 end:
603 data_blob_free(&lm_response);
604 data_blob_free(&nt_response);
605 data_blob_free(&session_key);
606 return result;
609 /* The following is calculated from :
610 * (smb_size-4) = 35
611 * (smb_wcnt * 2) = 24 (smb_wcnt == 12 in cli_session_setup_blob_send() )
612 * (strlen("Unix") + 1 + strlen("Samba") + 1) * 2 = 22 (unicode strings at
613 * end of packet.
616 #define BASE_SESSSETUP_BLOB_PACKET_SIZE (35 + 24 + 22)
618 struct cli_sesssetup_blob_state {
619 struct tevent_context *ev;
620 struct cli_state *cli;
621 DATA_BLOB blob;
622 uint16_t max_blob_size;
623 uint16_t vwv[12];
624 uint8_t *buf;
626 NTSTATUS status;
627 char *inbuf;
628 DATA_BLOB ret_blob;
631 static bool cli_sesssetup_blob_next(struct cli_sesssetup_blob_state *state,
632 struct tevent_req **psubreq);
633 static void cli_sesssetup_blob_done(struct tevent_req *subreq);
635 static struct tevent_req *cli_sesssetup_blob_send(TALLOC_CTX *mem_ctx,
636 struct tevent_context *ev,
637 struct cli_state *cli,
638 DATA_BLOB blob)
640 struct tevent_req *req, *subreq;
641 struct cli_sesssetup_blob_state *state;
643 req = tevent_req_create(mem_ctx, &state,
644 struct cli_sesssetup_blob_state);
645 if (req == NULL) {
646 return NULL;
648 state->ev = ev;
649 state->blob = blob;
650 state->cli = cli;
652 if (cli->max_xmit < BASE_SESSSETUP_BLOB_PACKET_SIZE + 1) {
653 DEBUG(1, ("cli_session_setup_blob: cli->max_xmit too small "
654 "(was %u, need minimum %u)\n",
655 (unsigned int)cli->max_xmit,
656 BASE_SESSSETUP_BLOB_PACKET_SIZE));
657 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
658 return tevent_req_post(req, ev);
660 state->max_blob_size =
661 MIN(cli->max_xmit - BASE_SESSSETUP_BLOB_PACKET_SIZE, 0xFFFF);
663 if (!cli_sesssetup_blob_next(state, &subreq)) {
664 tevent_req_nomem(NULL, req);
665 return tevent_req_post(req, ev);
667 tevent_req_set_callback(subreq, cli_sesssetup_blob_done, req);
668 return req;
671 static bool cli_sesssetup_blob_next(struct cli_sesssetup_blob_state *state,
672 struct tevent_req **psubreq)
674 struct tevent_req *subreq;
675 uint16_t thistime;
677 SCVAL(state->vwv+0, 0, 0xFF);
678 SCVAL(state->vwv+0, 1, 0);
679 SSVAL(state->vwv+1, 0, 0);
680 SSVAL(state->vwv+2, 0, CLI_BUFFER_SIZE);
681 SSVAL(state->vwv+3, 0, 2);
682 SSVAL(state->vwv+4, 0, 1);
683 SIVAL(state->vwv+5, 0, 0);
685 thistime = MIN(state->blob.length, state->max_blob_size);
686 SSVAL(state->vwv+7, 0, thistime);
688 SSVAL(state->vwv+8, 0, 0);
689 SSVAL(state->vwv+9, 0, 0);
690 SIVAL(state->vwv+10, 0,
691 cli_session_setup_capabilities(state->cli)
692 | CAP_EXTENDED_SECURITY);
694 state->buf = (uint8_t *)talloc_memdup(state, state->blob.data,
695 thistime);
696 if (state->buf == NULL) {
697 return false;
699 state->blob.data += thistime;
700 state->blob.length -= thistime;
702 state->buf = smb_bytes_push_str(state->buf, cli_ucs2(state->cli),
703 "Unix", 5, NULL);
704 state->buf = smb_bytes_push_str(state->buf, cli_ucs2(state->cli),
705 "Samba", 6, NULL);
706 if (state->buf == NULL) {
707 return false;
709 subreq = cli_smb_send(state, state->ev, state->cli, SMBsesssetupX, 0,
710 12, state->vwv,
711 talloc_get_size(state->buf), state->buf);
712 if (subreq == NULL) {
713 return false;
715 *psubreq = subreq;
716 return true;
719 static void cli_sesssetup_blob_done(struct tevent_req *subreq)
721 struct tevent_req *req = tevent_req_callback_data(
722 subreq, struct tevent_req);
723 struct cli_sesssetup_blob_state *state = tevent_req_data(
724 req, struct cli_sesssetup_blob_state);
725 struct cli_state *cli = state->cli;
726 uint8_t wct;
727 uint16_t *vwv;
728 uint32_t num_bytes;
729 uint8_t *bytes;
730 NTSTATUS status;
731 uint8_t *p;
732 uint16_t blob_length;
734 status = cli_smb_recv(subreq, NULL, NULL, 1, &wct, &vwv,
735 &num_bytes, &bytes);
736 if (!NT_STATUS_IS_OK(status)
737 && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
738 TALLOC_FREE(subreq);
739 tevent_req_nterror(req, status);
740 return;
743 state->status = status;
744 TALLOC_FREE(state->buf);
746 state->inbuf = (char *)cli_smb_inbuf(subreq);
747 cli->vuid = SVAL(state->inbuf, smb_uid);
749 blob_length = SVAL(vwv+3, 0);
750 if (blob_length > num_bytes) {
751 TALLOC_FREE(subreq);
752 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
753 return;
755 state->ret_blob = data_blob_const(bytes, blob_length);
757 p = bytes + blob_length;
759 p += clistr_pull(state->inbuf, cli->server_os,
760 (char *)p, sizeof(fstring),
761 bytes+num_bytes-p, STR_TERMINATE);
762 p += clistr_pull(state->inbuf, cli->server_type,
763 (char *)p, sizeof(fstring),
764 bytes+num_bytes-p, STR_TERMINATE);
765 p += clistr_pull(state->inbuf, cli->server_domain,
766 (char *)p, sizeof(fstring),
767 bytes+num_bytes-p, STR_TERMINATE);
769 if (strstr(cli->server_type, "Samba")) {
770 cli->is_samba = True;
773 if (state->blob.length != 0) {
774 TALLOC_FREE(subreq);
776 * More to send
778 if (!cli_sesssetup_blob_next(state, &subreq)) {
779 tevent_req_nomem(NULL, req);
780 return;
782 tevent_req_set_callback(subreq, cli_sesssetup_blob_done, req);
783 return;
785 tevent_req_done(req);
788 static NTSTATUS cli_sesssetup_blob_recv(struct tevent_req *req,
789 TALLOC_CTX *mem_ctx,
790 DATA_BLOB *pblob,
791 char **pinbuf)
793 struct cli_sesssetup_blob_state *state = tevent_req_data(
794 req, struct cli_sesssetup_blob_state);
795 NTSTATUS status;
796 char *inbuf;
798 if (tevent_req_is_nterror(req, &status)) {
799 state->cli->vuid = 0;
800 return status;
803 inbuf = talloc_move(mem_ctx, &state->inbuf);
804 if (pblob != NULL) {
805 *pblob = state->ret_blob;
807 if (pinbuf != NULL) {
808 *pinbuf = inbuf;
810 /* could be NT_STATUS_MORE_PROCESSING_REQUIRED */
811 return state->status;
814 #ifdef HAVE_KRB5
816 /****************************************************************************
817 Use in-memory credentials cache
818 ****************************************************************************/
820 static void use_in_memory_ccache(void) {
821 setenv(KRB5_ENV_CCNAME, "MEMORY:cliconnect", 1);
824 /****************************************************************************
825 Do a spnego/kerberos encrypted session setup.
826 ****************************************************************************/
828 struct cli_session_setup_kerberos_state {
829 struct cli_state *cli;
830 DATA_BLOB negTokenTarg;
831 DATA_BLOB session_key_krb5;
832 ADS_STATUS ads_status;
835 static void cli_session_setup_kerberos_done(struct tevent_req *subreq);
837 static struct tevent_req *cli_session_setup_kerberos_send(
838 TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
839 const char *principal, const char *workgroup)
841 struct tevent_req *req, *subreq;
842 struct cli_session_setup_kerberos_state *state;
843 int rc;
845 DEBUG(2,("Doing kerberos session setup\n"));
847 req = tevent_req_create(mem_ctx, &state,
848 struct cli_session_setup_kerberos_state);
849 if (req == NULL) {
850 return NULL;
852 state->cli = cli;
853 state->ads_status = ADS_SUCCESS;
855 cli_temp_set_signing(cli);
858 * Ok, this is cheated: spnego_gen_negTokenTarg can block if
859 * we have to acquire a ticket. To be fixed later :-)
861 rc = spnego_gen_negTokenTarg(principal, 0, &state->negTokenTarg,
862 &state->session_key_krb5, 0, NULL);
863 if (rc) {
864 DEBUG(1, ("cli_session_setup_kerberos: "
865 "spnego_gen_negTokenTarg failed: %s\n",
866 error_message(rc)));
867 state->ads_status = ADS_ERROR_KRB5(rc);
868 tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
869 return tevent_req_post(req, ev);
872 #if 0
873 file_save("negTokenTarg.dat", state->negTokenTarg.data,
874 state->negTokenTarg.length);
875 #endif
877 subreq = cli_sesssetup_blob_send(state, ev, cli, state->negTokenTarg);
878 if (tevent_req_nomem(subreq, req)) {
879 return tevent_req_post(req, ev);
881 tevent_req_set_callback(subreq, cli_session_setup_kerberos_done, req);
882 return req;
885 static void cli_session_setup_kerberos_done(struct tevent_req *subreq)
887 struct tevent_req *req = tevent_req_callback_data(
888 subreq, struct tevent_req);
889 struct cli_session_setup_kerberos_state *state = tevent_req_data(
890 req, struct cli_session_setup_kerberos_state);
891 char *inbuf = NULL;
892 NTSTATUS status;
894 status = cli_sesssetup_blob_recv(subreq, talloc_tos(), NULL, &inbuf);
895 if (!NT_STATUS_IS_OK(status)) {
896 TALLOC_FREE(subreq);
897 tevent_req_nterror(req, status);
898 return;
901 cli_set_session_key(state->cli, state->session_key_krb5);
903 if (cli_simple_set_signing(state->cli, state->session_key_krb5,
904 data_blob_null)
905 && !cli_check_sign_mac(state->cli, inbuf, 1)) {
906 TALLOC_FREE(subreq);
907 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
908 return;
910 TALLOC_FREE(subreq);
911 tevent_req_done(req);
914 static ADS_STATUS cli_session_setup_kerberos_recv(struct tevent_req *req)
916 struct cli_session_setup_kerberos_state *state = tevent_req_data(
917 req, struct cli_session_setup_kerberos_state);
918 NTSTATUS status;
920 if (tevent_req_is_nterror(req, &status)) {
921 return ADS_ERROR_NT(status);
923 return state->ads_status;
926 static ADS_STATUS cli_session_setup_kerberos(struct cli_state *cli,
927 const char *principal,
928 const char *workgroup)
930 struct tevent_context *ev;
931 struct tevent_req *req;
932 ADS_STATUS status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
934 if (cli_has_async_calls(cli)) {
935 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
937 ev = tevent_context_init(talloc_tos());
938 if (ev == NULL) {
939 goto fail;
941 req = cli_session_setup_kerberos_send(ev, ev, cli, principal,
942 workgroup);
943 if (req == NULL) {
944 goto fail;
946 if (!tevent_req_poll(req, ev)) {
947 status = ADS_ERROR_SYSTEM(errno);
948 goto fail;
950 status = cli_session_setup_kerberos_recv(req);
951 fail:
952 TALLOC_FREE(ev);
953 return status;
955 #endif /* HAVE_KRB5 */
957 /****************************************************************************
958 Do a spnego/NTLMSSP encrypted session setup.
959 ****************************************************************************/
961 struct cli_session_setup_ntlmssp_state {
962 struct tevent_context *ev;
963 struct cli_state *cli;
964 struct ntlmssp_state *ntlmssp_state;
965 int turn;
966 DATA_BLOB blob_out;
969 static int cli_session_setup_ntlmssp_state_destructor(
970 struct cli_session_setup_ntlmssp_state *state)
972 if (state->ntlmssp_state != NULL) {
973 ntlmssp_end(&state->ntlmssp_state);
975 return 0;
978 static void cli_session_setup_ntlmssp_done(struct tevent_req *req);
980 static struct tevent_req *cli_session_setup_ntlmssp_send(
981 TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
982 const char *user, const char *pass, const char *domain)
984 struct tevent_req *req, *subreq;
985 struct cli_session_setup_ntlmssp_state *state;
986 NTSTATUS status;
987 DATA_BLOB blob_out;
989 req = tevent_req_create(mem_ctx, &state,
990 struct cli_session_setup_ntlmssp_state);
991 if (req == NULL) {
992 return NULL;
994 state->ev = ev;
995 state->cli = cli;
996 state->turn = 1;
998 state->ntlmssp_state = NULL;
999 talloc_set_destructor(
1000 state, cli_session_setup_ntlmssp_state_destructor);
1002 cli_temp_set_signing(cli);
1004 status = ntlmssp_client_start(&state->ntlmssp_state);
1005 if (!NT_STATUS_IS_OK(status)) {
1006 goto fail;
1008 ntlmssp_want_feature(state->ntlmssp_state,
1009 NTLMSSP_FEATURE_SESSION_KEY);
1010 if (cli->use_ccache) {
1011 ntlmssp_want_feature(state->ntlmssp_state,
1012 NTLMSSP_FEATURE_CCACHE);
1014 status = ntlmssp_set_username(state->ntlmssp_state, user);
1015 if (!NT_STATUS_IS_OK(status)) {
1016 goto fail;
1018 status = ntlmssp_set_domain(state->ntlmssp_state, domain);
1019 if (!NT_STATUS_IS_OK(status)) {
1020 goto fail;
1022 status = ntlmssp_set_password(state->ntlmssp_state, pass);
1023 if (!NT_STATUS_IS_OK(status)) {
1024 goto fail;
1026 status = ntlmssp_update(state->ntlmssp_state, data_blob_null,
1027 &blob_out);
1028 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1029 goto fail;
1032 state->blob_out = gen_negTokenInit(OID_NTLMSSP, blob_out);
1033 data_blob_free(&blob_out);
1035 subreq = cli_sesssetup_blob_send(state, ev, cli, state->blob_out);
1036 if (tevent_req_nomem(subreq, req)) {
1037 return tevent_req_post(req, ev);
1039 tevent_req_set_callback(subreq, cli_session_setup_ntlmssp_done, req);
1040 return req;
1041 fail:
1042 tevent_req_nterror(req, status);
1043 return tevent_req_post(req, ev);
1046 static void cli_session_setup_ntlmssp_done(struct tevent_req *subreq)
1048 struct tevent_req *req = tevent_req_callback_data(
1049 subreq, struct tevent_req);
1050 struct cli_session_setup_ntlmssp_state *state = tevent_req_data(
1051 req, struct cli_session_setup_ntlmssp_state);
1052 DATA_BLOB blob_in, msg_in, blob_out;
1053 char *inbuf = NULL;
1054 bool parse_ret;
1055 NTSTATUS status;
1057 status = cli_sesssetup_blob_recv(subreq, talloc_tos(), &blob_in,
1058 &inbuf);
1059 TALLOC_FREE(subreq);
1060 data_blob_free(&state->blob_out);
1062 if (NT_STATUS_IS_OK(status)) {
1063 if (state->cli->server_domain[0] == '\0') {
1064 fstrcpy(state->cli->server_domain,
1065 state->ntlmssp_state->server_domain);
1067 cli_set_session_key(
1068 state->cli, state->ntlmssp_state->session_key);
1070 if (cli_simple_set_signing(
1071 state->cli, state->ntlmssp_state->session_key,
1072 data_blob_null)
1073 && !cli_check_sign_mac(state->cli, inbuf, 1)) {
1074 TALLOC_FREE(subreq);
1075 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1076 return;
1078 TALLOC_FREE(subreq);
1079 ntlmssp_end(&state->ntlmssp_state);
1080 tevent_req_done(req);
1081 return;
1083 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1084 tevent_req_nterror(req, status);
1085 return;
1088 if (blob_in.length == 0) {
1089 tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
1090 return;
1093 if ((state->turn == 1)
1094 && NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1095 DATA_BLOB tmp_blob = data_blob_null;
1096 /* the server might give us back two challenges */
1097 parse_ret = spnego_parse_challenge(blob_in, &msg_in,
1098 &tmp_blob);
1099 data_blob_free(&tmp_blob);
1100 } else {
1101 parse_ret = spnego_parse_auth_response(blob_in, status,
1102 OID_NTLMSSP, &msg_in);
1104 state->turn += 1;
1106 if (!parse_ret) {
1107 DEBUG(3,("Failed to parse auth response\n"));
1108 if (NT_STATUS_IS_OK(status)
1109 || NT_STATUS_EQUAL(status,
1110 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1111 tevent_req_nterror(
1112 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
1113 return;
1117 status = ntlmssp_update(state->ntlmssp_state, msg_in, &blob_out);
1119 if (!NT_STATUS_IS_OK(status)
1120 && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1121 TALLOC_FREE(subreq);
1122 ntlmssp_end(&state->ntlmssp_state);
1123 tevent_req_nterror(req, status);
1124 return;
1127 state->blob_out = spnego_gen_auth(blob_out);
1128 TALLOC_FREE(subreq);
1129 if (tevent_req_nomem(state->blob_out.data, req)) {
1130 return;
1133 subreq = cli_sesssetup_blob_send(state, state->ev, state->cli,
1134 state->blob_out);
1135 if (tevent_req_nomem(subreq, req)) {
1136 return;
1138 tevent_req_set_callback(subreq, cli_session_setup_ntlmssp_done, req);
1141 static NTSTATUS cli_session_setup_ntlmssp_recv(struct tevent_req *req)
1143 struct cli_session_setup_ntlmssp_state *state = tevent_req_data(
1144 req, struct cli_session_setup_ntlmssp_state);
1145 NTSTATUS status;
1147 if (tevent_req_is_nterror(req, &status)) {
1148 state->cli->vuid = 0;
1149 return status;
1151 return NT_STATUS_OK;
1154 static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli,
1155 const char *user,
1156 const char *pass,
1157 const char *domain)
1159 struct tevent_context *ev;
1160 struct tevent_req *req;
1161 NTSTATUS status = NT_STATUS_NO_MEMORY;
1163 if (cli_has_async_calls(cli)) {
1164 return NT_STATUS_INVALID_PARAMETER;
1166 ev = tevent_context_init(talloc_tos());
1167 if (ev == NULL) {
1168 goto fail;
1170 req = cli_session_setup_ntlmssp_send(ev, ev, cli, user, pass, domain);
1171 if (req == NULL) {
1172 goto fail;
1174 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1175 goto fail;
1177 status = cli_session_setup_ntlmssp_recv(req);
1178 fail:
1179 TALLOC_FREE(ev);
1180 if (!NT_STATUS_IS_OK(status)) {
1181 cli_set_error(cli, status);
1183 return status;
1186 /****************************************************************************
1187 Do a spnego encrypted session setup.
1189 user_domain: The shortname of the domain the user/machine is a member of.
1190 dest_realm: The realm we're connecting to, if NULL we use our default realm.
1191 ****************************************************************************/
1193 ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, const char *user,
1194 const char *pass, const char *user_domain,
1195 const char * dest_realm)
1197 char *principal = NULL;
1198 char *OIDs[ASN1_MAX_OIDS];
1199 int i;
1200 DATA_BLOB blob;
1201 const char *p = NULL;
1202 char *account = NULL;
1203 NTSTATUS status;
1205 DEBUG(3,("Doing spnego session setup (blob length=%lu)\n", (unsigned long)cli->secblob.length));
1207 /* the server might not even do spnego */
1208 if (cli->secblob.length <= 16) {
1209 DEBUG(3,("server didn't supply a full spnego negprot\n"));
1210 goto ntlmssp;
1213 #if 0
1214 file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
1215 #endif
1217 /* there is 16 bytes of GUID before the real spnego packet starts */
1218 blob = data_blob(cli->secblob.data+16, cli->secblob.length-16);
1220 /* The server sent us the first part of the SPNEGO exchange in the
1221 * negprot reply. It is WRONG to depend on the principal sent in the
1222 * negprot reply, but right now we do it. If we don't receive one,
1223 * we try to best guess, then fall back to NTLM. */
1224 if (!spnego_parse_negTokenInit(blob, OIDs, &principal)) {
1225 data_blob_free(&blob);
1226 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
1228 data_blob_free(&blob);
1230 /* make sure the server understands kerberos */
1231 for (i=0;OIDs[i];i++) {
1232 if (i == 0)
1233 DEBUG(3,("got OID=%s\n", OIDs[i]));
1234 else
1235 DEBUGADD(3,("got OID=%s\n", OIDs[i]));
1236 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
1237 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
1238 cli->got_kerberos_mechanism = True;
1240 talloc_free(OIDs[i]);
1243 DEBUG(3,("got principal=%s\n", principal ? principal : "<null>"));
1245 status = cli_set_username(cli, user);
1246 if (!NT_STATUS_IS_OK(status)) {
1247 return ADS_ERROR_NT(status);
1250 #ifdef HAVE_KRB5
1251 /* If password is set we reauthenticate to kerberos server
1252 * and do not store results */
1254 if (cli->got_kerberos_mechanism && cli->use_kerberos) {
1255 ADS_STATUS rc;
1257 if (pass && *pass) {
1258 int ret;
1260 use_in_memory_ccache();
1261 ret = kerberos_kinit_password(user, pass, 0 /* no time correction for now */, NULL);
1263 if (ret){
1264 TALLOC_FREE(principal);
1265 DEBUG(0, ("Kinit failed: %s\n", error_message(ret)));
1266 if (cli->fallback_after_kerberos)
1267 goto ntlmssp;
1268 return ADS_ERROR_KRB5(ret);
1272 /* If we get a bad principal, try to guess it if
1273 we have a valid host NetBIOS name.
1275 if (strequal(principal, ADS_IGNORE_PRINCIPAL)) {
1276 TALLOC_FREE(principal);
1279 if (principal == NULL &&
1280 !is_ipaddress(cli->desthost) &&
1281 !strequal(STAR_SMBSERVER,
1282 cli->desthost)) {
1283 char *realm = NULL;
1284 char *machine = NULL;
1285 char *host = NULL;
1286 DEBUG(3,("cli_session_setup_spnego: got a "
1287 "bad server principal, trying to guess ...\n"));
1289 host = strchr_m(cli->desthost, '.');
1290 if (host) {
1291 /* We had a '.' in the name. */
1292 machine = SMB_STRNDUP(cli->desthost,
1293 host - cli->desthost);
1294 } else {
1295 machine = SMB_STRDUP(cli->desthost);
1297 if (machine == NULL) {
1298 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1301 if (dest_realm) {
1302 realm = SMB_STRDUP(dest_realm);
1303 strupper_m(realm);
1304 } else {
1305 if (host) {
1306 /* DNS name. */
1307 realm = kerberos_get_realm_from_hostname(cli->desthost);
1308 } else {
1309 /* NetBIOS name - use our realm. */
1310 realm = kerberos_get_default_realm_from_ccache();
1314 if (realm && *realm) {
1315 if (host) {
1316 /* DNS name. */
1317 principal = talloc_asprintf(talloc_tos(),
1318 "cifs/%s@%s",
1319 cli->desthost,
1320 realm);
1321 } else {
1322 /* NetBIOS name, use machine account. */
1323 principal = talloc_asprintf(talloc_tos(),
1324 "%s$@%s",
1325 machine,
1326 realm);
1328 if (!principal) {
1329 SAFE_FREE(machine);
1330 SAFE_FREE(realm);
1331 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1333 DEBUG(3,("cli_session_setup_spnego: guessed "
1334 "server principal=%s\n",
1335 principal ? principal : "<null>"));
1337 SAFE_FREE(machine);
1338 SAFE_FREE(realm);
1341 if (principal) {
1342 rc = cli_session_setup_kerberos(cli, principal,
1343 dest_realm);
1344 if (ADS_ERR_OK(rc) || !cli->fallback_after_kerberos) {
1345 TALLOC_FREE(principal);
1346 return rc;
1350 #endif
1352 TALLOC_FREE(principal);
1354 ntlmssp:
1356 account = talloc_strdup(talloc_tos(), user);
1357 if (!account) {
1358 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1361 /* when falling back to ntlmssp while authenticating with a machine
1362 * account strip off the realm - gd */
1364 if ((p = strchr_m(user, '@')) != NULL) {
1365 account[PTR_DIFF(p,user)] = '\0';
1368 return ADS_ERROR_NT(cli_session_setup_ntlmssp(cli, account, pass, user_domain));
1371 /****************************************************************************
1372 Send a session setup. The username and workgroup is in UNIX character
1373 format and must be converted to DOS codepage format before sending. If the
1374 password is in plaintext, the same should be done.
1375 ****************************************************************************/
1377 NTSTATUS cli_session_setup(struct cli_state *cli,
1378 const char *user,
1379 const char *pass, int passlen,
1380 const char *ntpass, int ntpasslen,
1381 const char *workgroup)
1383 char *p;
1384 fstring user2;
1386 if (user) {
1387 fstrcpy(user2, user);
1388 } else {
1389 user2[0] ='\0';
1392 if (!workgroup) {
1393 workgroup = "";
1396 /* allow for workgroups as part of the username */
1397 if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/')) ||
1398 (p=strchr_m(user2,*lp_winbind_separator()))) {
1399 *p = 0;
1400 user = p+1;
1401 workgroup = user2;
1404 if (cli->protocol < PROTOCOL_LANMAN1) {
1405 return NT_STATUS_OK;
1408 /* now work out what sort of session setup we are going to
1409 do. I have split this into separate functions to make the
1410 flow a bit easier to understand (tridge) */
1412 /* if its an older server then we have to use the older request format */
1414 if (cli->protocol < PROTOCOL_NT1) {
1415 if (!lp_client_lanman_auth() && passlen != 24 && (*pass)) {
1416 DEBUG(1, ("Server requested LM password but 'client lanman auth'"
1417 " is disabled\n"));
1418 return NT_STATUS_ACCESS_DENIED;
1421 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0 &&
1422 !lp_client_plaintext_auth() && (*pass)) {
1423 DEBUG(1, ("Server requested plaintext password but "
1424 "'client plaintext auth' is disabled\n"));
1425 return NT_STATUS_ACCESS_DENIED;
1428 return cli_session_setup_lanman2(cli, user, pass, passlen,
1429 workgroup);
1432 /* if no user is supplied then we have to do an anonymous connection.
1433 passwords are ignored */
1435 if (!user || !*user)
1436 return cli_session_setup_guest(cli);
1438 /* if the server is share level then send a plaintext null
1439 password at this point. The password is sent in the tree
1440 connect */
1442 if ((cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) == 0)
1443 return cli_session_setup_plaintext(cli, user, "", workgroup);
1445 /* if the server doesn't support encryption then we have to use
1446 plaintext. The second password is ignored */
1448 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) {
1449 if (!lp_client_plaintext_auth() && (*pass)) {
1450 DEBUG(1, ("Server requested plaintext password but "
1451 "'client plaintext auth' is disabled\n"));
1452 return NT_STATUS_ACCESS_DENIED;
1454 return cli_session_setup_plaintext(cli, user, pass, workgroup);
1457 /* if the server supports extended security then use SPNEGO */
1459 if (cli->capabilities & CAP_EXTENDED_SECURITY) {
1460 ADS_STATUS status = cli_session_setup_spnego(cli, user, pass,
1461 workgroup, NULL);
1462 if (!ADS_ERR_OK(status)) {
1463 DEBUG(3, ("SPNEGO login failed: %s\n", ads_errstr(status)));
1464 return ads_ntstatus(status);
1466 } else {
1467 NTSTATUS status;
1469 /* otherwise do a NT1 style session setup */
1470 status = cli_session_setup_nt1(cli, user, pass, passlen,
1471 ntpass, ntpasslen, workgroup);
1472 if (!NT_STATUS_IS_OK(status)) {
1473 DEBUG(3,("cli_session_setup: NT1 session setup "
1474 "failed: %s\n", nt_errstr(status)));
1475 return status;
1479 if (strstr(cli->server_type, "Samba")) {
1480 cli->is_samba = True;
1483 return NT_STATUS_OK;
1486 /****************************************************************************
1487 Send a uloggoff.
1488 *****************************************************************************/
1490 struct cli_ulogoff_state {
1491 struct cli_state *cli;
1492 uint16_t vwv[2];
1495 static void cli_ulogoff_done(struct tevent_req *subreq);
1497 struct tevent_req *cli_ulogoff_send(TALLOC_CTX *mem_ctx,
1498 struct tevent_context *ev,
1499 struct cli_state *cli)
1501 struct tevent_req *req, *subreq;
1502 struct cli_ulogoff_state *state;
1504 req = tevent_req_create(mem_ctx, &state, struct cli_ulogoff_state);
1505 if (req == NULL) {
1506 return NULL;
1508 state->cli = cli;
1510 SCVAL(state->vwv+0, 0, 0xFF);
1511 SCVAL(state->vwv+1, 0, 0);
1512 SSVAL(state->vwv+2, 0, 0);
1514 subreq = cli_smb_send(state, ev, cli, SMBulogoffX, 0, 2, state->vwv,
1515 0, NULL);
1516 if (tevent_req_nomem(subreq, req)) {
1517 return tevent_req_post(req, ev);
1519 tevent_req_set_callback(subreq, cli_ulogoff_done, req);
1520 return req;
1523 static void cli_ulogoff_done(struct tevent_req *subreq)
1525 struct tevent_req *req = tevent_req_callback_data(
1526 subreq, struct tevent_req);
1527 struct cli_ulogoff_state *state = tevent_req_data(
1528 req, struct cli_ulogoff_state);
1529 NTSTATUS status;
1531 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1532 if (!NT_STATUS_IS_OK(status)) {
1533 tevent_req_nterror(req, status);
1534 return;
1536 state->cli->vuid = -1;
1537 tevent_req_done(req);
1540 NTSTATUS cli_ulogoff_recv(struct tevent_req *req)
1542 return tevent_req_simple_recv_ntstatus(req);
1545 NTSTATUS cli_ulogoff(struct cli_state *cli)
1547 struct tevent_context *ev;
1548 struct tevent_req *req;
1549 NTSTATUS status = NT_STATUS_NO_MEMORY;
1551 if (cli_has_async_calls(cli)) {
1552 return NT_STATUS_INVALID_PARAMETER;
1554 ev = tevent_context_init(talloc_tos());
1555 if (ev == NULL) {
1556 goto fail;
1558 req = cli_ulogoff_send(ev, ev, cli);
1559 if (req == NULL) {
1560 goto fail;
1562 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1563 goto fail;
1565 status = cli_ulogoff_recv(req);
1566 fail:
1567 TALLOC_FREE(ev);
1568 if (!NT_STATUS_IS_OK(status)) {
1569 cli_set_error(cli, status);
1571 return status;
1574 /****************************************************************************
1575 Send a tconX.
1576 ****************************************************************************/
1578 struct cli_tcon_andx_state {
1579 struct cli_state *cli;
1580 uint16_t vwv[4];
1581 struct iovec bytes;
1584 static void cli_tcon_andx_done(struct tevent_req *subreq);
1586 struct tevent_req *cli_tcon_andx_create(TALLOC_CTX *mem_ctx,
1587 struct event_context *ev,
1588 struct cli_state *cli,
1589 const char *share, const char *dev,
1590 const char *pass, int passlen,
1591 struct tevent_req **psmbreq)
1593 struct tevent_req *req, *subreq;
1594 struct cli_tcon_andx_state *state;
1595 fstring pword;
1596 uint16_t *vwv;
1597 char *tmp = NULL;
1598 uint8_t *bytes;
1600 *psmbreq = NULL;
1602 req = tevent_req_create(mem_ctx, &state, struct cli_tcon_andx_state);
1603 if (req == NULL) {
1604 return NULL;
1606 state->cli = cli;
1607 vwv = state->vwv;
1609 fstrcpy(cli->share, share);
1611 /* in user level security don't send a password now */
1612 if (cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) {
1613 passlen = 1;
1614 pass = "";
1615 } else if (pass == NULL) {
1616 DEBUG(1, ("Server not using user level security and no "
1617 "password supplied.\n"));
1618 goto access_denied;
1621 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) &&
1622 *pass && passlen != 24) {
1623 if (!lp_client_lanman_auth()) {
1624 DEBUG(1, ("Server requested LANMAN password "
1625 "(share-level security) but "
1626 "'client lanman auth' is disabled\n"));
1627 goto access_denied;
1631 * Non-encrypted passwords - convert to DOS codepage before
1632 * encryption.
1634 passlen = 24;
1635 SMBencrypt(pass, cli->secblob.data, (uchar *)pword);
1636 } else {
1637 if((cli->sec_mode & (NEGOTIATE_SECURITY_USER_LEVEL
1638 |NEGOTIATE_SECURITY_CHALLENGE_RESPONSE))
1639 == 0) {
1640 if (!lp_client_plaintext_auth() && (*pass)) {
1641 DEBUG(1, ("Server requested plaintext "
1642 "password but 'client plaintext "
1643 "auth' is disabled\n"));
1644 goto access_denied;
1648 * Non-encrypted passwords - convert to DOS codepage
1649 * before using.
1651 passlen = clistr_push(cli, pword, pass, sizeof(pword),
1652 STR_TERMINATE);
1653 if (passlen == -1) {
1654 DEBUG(1, ("clistr_push(pword) failed\n"));
1655 goto access_denied;
1657 } else {
1658 if (passlen) {
1659 memcpy(pword, pass, passlen);
1664 SCVAL(vwv+0, 0, 0xFF);
1665 SCVAL(vwv+0, 1, 0);
1666 SSVAL(vwv+1, 0, 0);
1667 SSVAL(vwv+2, 0, TCONX_FLAG_EXTENDED_RESPONSE);
1668 SSVAL(vwv+3, 0, passlen);
1670 if (passlen) {
1671 bytes = (uint8_t *)talloc_memdup(state, pword, passlen);
1672 } else {
1673 bytes = talloc_array(state, uint8_t, 0);
1677 * Add the sharename
1679 tmp = talloc_asprintf_strupper_m(talloc_tos(), "\\\\%s\\%s",
1680 cli->desthost, share);
1681 if (tmp == NULL) {
1682 TALLOC_FREE(req);
1683 return NULL;
1685 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), tmp, strlen(tmp)+1,
1686 NULL);
1687 TALLOC_FREE(tmp);
1690 * Add the devicetype
1692 tmp = talloc_strdup_upper(talloc_tos(), dev);
1693 if (tmp == NULL) {
1694 TALLOC_FREE(req);
1695 return NULL;
1697 bytes = smb_bytes_push_str(bytes, false, tmp, strlen(tmp)+1, NULL);
1698 TALLOC_FREE(tmp);
1700 if (bytes == NULL) {
1701 TALLOC_FREE(req);
1702 return NULL;
1705 state->bytes.iov_base = (void *)bytes;
1706 state->bytes.iov_len = talloc_get_size(bytes);
1708 subreq = cli_smb_req_create(state, ev, cli, SMBtconX, 0, 4, vwv,
1709 1, &state->bytes);
1710 if (subreq == NULL) {
1711 TALLOC_FREE(req);
1712 return NULL;
1714 tevent_req_set_callback(subreq, cli_tcon_andx_done, req);
1715 *psmbreq = subreq;
1716 return req;
1718 access_denied:
1719 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1720 return tevent_req_post(req, ev);
1723 struct tevent_req *cli_tcon_andx_send(TALLOC_CTX *mem_ctx,
1724 struct event_context *ev,
1725 struct cli_state *cli,
1726 const char *share, const char *dev,
1727 const char *pass, int passlen)
1729 struct tevent_req *req, *subreq;
1730 NTSTATUS status;
1732 req = cli_tcon_andx_create(mem_ctx, ev, cli, share, dev, pass, passlen,
1733 &subreq);
1734 if (req == NULL) {
1735 return NULL;
1737 if (subreq == NULL) {
1738 return req;
1740 status = cli_smb_req_send(subreq);
1741 if (!NT_STATUS_IS_OK(status)) {
1742 tevent_req_nterror(req, status);
1743 return tevent_req_post(req, ev);
1745 return req;
1748 static void cli_tcon_andx_done(struct tevent_req *subreq)
1750 struct tevent_req *req = tevent_req_callback_data(
1751 subreq, struct tevent_req);
1752 struct cli_tcon_andx_state *state = tevent_req_data(
1753 req, struct cli_tcon_andx_state);
1754 struct cli_state *cli = state->cli;
1755 char *inbuf = (char *)cli_smb_inbuf(subreq);
1756 uint8_t wct;
1757 uint16_t *vwv;
1758 uint32_t num_bytes;
1759 uint8_t *bytes;
1760 NTSTATUS status;
1762 status = cli_smb_recv(subreq, NULL, NULL, 0, &wct, &vwv,
1763 &num_bytes, &bytes);
1764 if (!NT_STATUS_IS_OK(status)) {
1765 TALLOC_FREE(subreq);
1766 tevent_req_nterror(req, status);
1767 return;
1770 clistr_pull(inbuf, cli->dev, bytes, sizeof(fstring), num_bytes,
1771 STR_TERMINATE|STR_ASCII);
1773 if ((cli->protocol >= PROTOCOL_NT1) && (num_bytes == 3)) {
1774 /* almost certainly win95 - enable bug fixes */
1775 cli->win95 = True;
1779 * Make sure that we have the optional support 16-bit field. WCT > 2.
1780 * Avoids issues when connecting to Win9x boxes sharing files
1783 cli->dfsroot = false;
1785 if ((wct > 2) && (cli->protocol >= PROTOCOL_LANMAN2)) {
1786 cli->dfsroot = ((SVAL(vwv+2, 0) & SMB_SHARE_IN_DFS) != 0);
1789 cli->cnum = SVAL(inbuf,smb_tid);
1790 tevent_req_done(req);
1793 NTSTATUS cli_tcon_andx_recv(struct tevent_req *req)
1795 return tevent_req_simple_recv_ntstatus(req);
1798 NTSTATUS cli_tcon_andx(struct cli_state *cli, const char *share,
1799 const char *dev, const char *pass, int passlen)
1801 TALLOC_CTX *frame = talloc_stackframe();
1802 struct event_context *ev;
1803 struct tevent_req *req;
1804 NTSTATUS status = NT_STATUS_OK;
1806 if (cli_has_async_calls(cli)) {
1808 * Can't use sync call while an async call is in flight
1810 status = NT_STATUS_INVALID_PARAMETER;
1811 goto fail;
1814 ev = event_context_init(frame);
1815 if (ev == NULL) {
1816 status = NT_STATUS_NO_MEMORY;
1817 goto fail;
1820 req = cli_tcon_andx_send(frame, ev, cli, share, dev, pass, passlen);
1821 if (req == NULL) {
1822 status = NT_STATUS_NO_MEMORY;
1823 goto fail;
1826 if (!tevent_req_poll(req, ev)) {
1827 status = map_nt_error_from_unix(errno);
1828 goto fail;
1831 status = cli_tcon_andx_recv(req);
1832 fail:
1833 TALLOC_FREE(frame);
1834 if (!NT_STATUS_IS_OK(status)) {
1835 cli_set_error(cli, status);
1837 return status;
1840 /****************************************************************************
1841 Send a tree disconnect.
1842 ****************************************************************************/
1844 struct cli_tdis_state {
1845 struct cli_state *cli;
1848 static void cli_tdis_done(struct tevent_req *subreq);
1850 struct tevent_req *cli_tdis_send(TALLOC_CTX *mem_ctx,
1851 struct tevent_context *ev,
1852 struct cli_state *cli)
1854 struct tevent_req *req, *subreq;
1855 struct cli_tdis_state *state;
1857 req = tevent_req_create(mem_ctx, &state, struct cli_tdis_state);
1858 if (req == NULL) {
1859 return NULL;
1861 state->cli = cli;
1863 subreq = cli_smb_send(state, ev, cli, SMBtdis, 0, 0, NULL, 0, NULL);
1864 if (tevent_req_nomem(subreq, req)) {
1865 return tevent_req_post(req, ev);
1867 tevent_req_set_callback(subreq, cli_tdis_done, req);
1868 return req;
1871 static void cli_tdis_done(struct tevent_req *subreq)
1873 struct tevent_req *req = tevent_req_callback_data(
1874 subreq, struct tevent_req);
1875 struct cli_tdis_state *state = tevent_req_data(
1876 req, struct cli_tdis_state);
1877 NTSTATUS status;
1879 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1880 TALLOC_FREE(subreq);
1881 if (!NT_STATUS_IS_OK(status)) {
1882 tevent_req_nterror(req, status);
1883 return;
1885 state->cli->cnum = -1;
1886 tevent_req_done(req);
1889 NTSTATUS cli_tdis_recv(struct tevent_req *req)
1891 return tevent_req_simple_recv_ntstatus(req);
1894 NTSTATUS cli_tdis(struct cli_state *cli)
1896 struct tevent_context *ev;
1897 struct tevent_req *req;
1898 NTSTATUS status = NT_STATUS_NO_MEMORY;
1900 if (cli_has_async_calls(cli)) {
1901 return NT_STATUS_INVALID_PARAMETER;
1903 ev = tevent_context_init(talloc_tos());
1904 if (ev == NULL) {
1905 goto fail;
1907 req = cli_tdis_send(ev, ev, cli);
1908 if (req == NULL) {
1909 goto fail;
1911 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1912 goto fail;
1914 status = cli_tdis_recv(req);
1915 fail:
1916 TALLOC_FREE(ev);
1917 if (!NT_STATUS_IS_OK(status)) {
1918 cli_set_error(cli, status);
1920 return status;
1923 /****************************************************************************
1924 Send a negprot command.
1925 ****************************************************************************/
1927 void cli_negprot_sendsync(struct cli_state *cli)
1929 char *p;
1930 int numprots;
1932 if (cli->protocol < PROTOCOL_NT1)
1933 cli->use_spnego = False;
1935 memset(cli->outbuf,'\0',smb_size);
1937 /* setup the protocol strings */
1938 cli_set_message(cli->outbuf,0,0,True);
1940 p = smb_buf(cli->outbuf);
1941 for (numprots=0; numprots < ARRAY_SIZE(prots); numprots++) {
1942 if (prots[numprots].prot > cli->protocol) {
1943 break;
1945 *p++ = 2;
1946 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
1949 SCVAL(cli->outbuf,smb_com,SMBnegprot);
1950 cli_setup_bcc(cli, p);
1951 cli_setup_packet(cli);
1953 SCVAL(smb_buf(cli->outbuf),0,2);
1955 cli_send_smb(cli);
1958 /****************************************************************************
1959 Send a negprot command.
1960 ****************************************************************************/
1962 struct cli_negprot_state {
1963 struct cli_state *cli;
1966 static void cli_negprot_done(struct tevent_req *subreq);
1968 struct tevent_req *cli_negprot_send(TALLOC_CTX *mem_ctx,
1969 struct event_context *ev,
1970 struct cli_state *cli)
1972 struct tevent_req *req, *subreq;
1973 struct cli_negprot_state *state;
1974 uint8_t *bytes = NULL;
1975 int numprots;
1976 uint16_t cnum;
1978 req = tevent_req_create(mem_ctx, &state, struct cli_negprot_state);
1979 if (req == NULL) {
1980 return NULL;
1982 state->cli = cli;
1984 if (cli->protocol < PROTOCOL_NT1)
1985 cli->use_spnego = False;
1987 /* setup the protocol strings */
1988 for (numprots=0; numprots < ARRAY_SIZE(prots); numprots++) {
1989 uint8_t c = 2;
1990 if (prots[numprots].prot > cli->protocol) {
1991 break;
1993 bytes = (uint8_t *)talloc_append_blob(
1994 state, bytes, data_blob_const(&c, sizeof(c)));
1995 if (tevent_req_nomem(bytes, req)) {
1996 return tevent_req_post(req, ev);
1998 bytes = smb_bytes_push_str(bytes, false,
1999 prots[numprots].name,
2000 strlen(prots[numprots].name)+1,
2001 NULL);
2002 if (tevent_req_nomem(bytes, req)) {
2003 return tevent_req_post(req, ev);
2007 cnum = cli->cnum;
2009 cli->cnum = 0;
2010 subreq = cli_smb_send(state, ev, cli, SMBnegprot, 0, 0, NULL,
2011 talloc_get_size(bytes), bytes);
2012 cli->cnum = cnum;
2014 if (tevent_req_nomem(subreq, req)) {
2015 return tevent_req_post(req, ev);
2017 tevent_req_set_callback(subreq, cli_negprot_done, req);
2018 return req;
2021 static void cli_negprot_done(struct tevent_req *subreq)
2023 struct tevent_req *req = tevent_req_callback_data(
2024 subreq, struct tevent_req);
2025 struct cli_negprot_state *state = tevent_req_data(
2026 req, struct cli_negprot_state);
2027 struct cli_state *cli = state->cli;
2028 uint8_t wct;
2029 uint16_t *vwv;
2030 uint32_t num_bytes;
2031 uint8_t *bytes;
2032 NTSTATUS status;
2033 uint16_t protnum;
2035 status = cli_smb_recv(subreq, NULL, NULL, 1, &wct, &vwv,
2036 &num_bytes, &bytes);
2037 if (!NT_STATUS_IS_OK(status)) {
2038 TALLOC_FREE(subreq);
2039 tevent_req_nterror(req, status);
2040 return;
2043 protnum = SVAL(vwv, 0);
2045 if ((protnum >= ARRAY_SIZE(prots))
2046 || (prots[protnum].prot > cli->protocol)) {
2047 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2048 return;
2051 cli->protocol = prots[protnum].prot;
2053 if ((cli->protocol < PROTOCOL_NT1) &&
2054 client_is_signing_mandatory(cli)) {
2055 DEBUG(0,("cli_negprot: SMB signing is mandatory and the selected protocol level doesn't support it.\n"));
2056 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
2057 return;
2060 if (cli->protocol >= PROTOCOL_NT1) {
2061 struct timespec ts;
2062 bool negotiated_smb_signing = false;
2064 /* NT protocol */
2065 cli->sec_mode = CVAL(vwv + 1, 0);
2066 cli->max_mux = SVAL(vwv + 1, 1);
2067 cli->max_xmit = IVAL(vwv + 3, 1);
2068 cli->sesskey = IVAL(vwv + 7, 1);
2069 cli->serverzone = SVALS(vwv + 15, 1);
2070 cli->serverzone *= 60;
2071 /* this time arrives in real GMT */
2072 ts = interpret_long_date(((char *)(vwv+11))+1);
2073 cli->servertime = ts.tv_sec;
2074 cli->secblob = data_blob(bytes, num_bytes);
2075 cli->capabilities = IVAL(vwv + 9, 1);
2076 if (cli->capabilities & CAP_RAW_MODE) {
2077 cli->readbraw_supported = True;
2078 cli->writebraw_supported = True;
2080 /* work out if they sent us a workgroup */
2081 if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
2082 smb_buflen(cli->inbuf) > 8) {
2083 clistr_pull(cli->inbuf, cli->server_domain,
2084 bytes+8, sizeof(cli->server_domain),
2085 num_bytes-8,
2086 STR_UNICODE|STR_NOALIGN);
2090 * As signing is slow we only turn it on if either the client or
2091 * the server require it. JRA.
2094 if (cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED) {
2095 /* Fail if server says signing is mandatory and we don't want to support it. */
2096 if (!client_is_signing_allowed(cli)) {
2097 DEBUG(0,("cli_negprot: SMB signing is mandatory and we have disabled it.\n"));
2098 tevent_req_nterror(req,
2099 NT_STATUS_ACCESS_DENIED);
2100 return;
2102 negotiated_smb_signing = true;
2103 } else if (client_is_signing_mandatory(cli) && client_is_signing_allowed(cli)) {
2104 /* Fail if client says signing is mandatory and the server doesn't support it. */
2105 if (!(cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED)) {
2106 DEBUG(1,("cli_negprot: SMB signing is mandatory and the server doesn't support it.\n"));
2107 tevent_req_nterror(req,
2108 NT_STATUS_ACCESS_DENIED);
2109 return;
2111 negotiated_smb_signing = true;
2112 } else if (cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) {
2113 negotiated_smb_signing = true;
2116 if (negotiated_smb_signing) {
2117 cli_set_signing_negotiated(cli);
2120 if (cli->capabilities & (CAP_LARGE_READX|CAP_LARGE_WRITEX)) {
2121 SAFE_FREE(cli->outbuf);
2122 SAFE_FREE(cli->inbuf);
2123 cli->outbuf = (char *)SMB_MALLOC(CLI_SAMBA_MAX_LARGE_READX_SIZE+LARGE_WRITEX_HDR_SIZE+SAFETY_MARGIN);
2124 cli->inbuf = (char *)SMB_MALLOC(CLI_SAMBA_MAX_LARGE_READX_SIZE+LARGE_WRITEX_HDR_SIZE+SAFETY_MARGIN);
2125 cli->bufsize = CLI_SAMBA_MAX_LARGE_READX_SIZE + LARGE_WRITEX_HDR_SIZE;
2128 } else if (cli->protocol >= PROTOCOL_LANMAN1) {
2129 cli->use_spnego = False;
2130 cli->sec_mode = SVAL(vwv + 1, 0);
2131 cli->max_xmit = SVAL(vwv + 2, 0);
2132 cli->max_mux = SVAL(vwv + 3, 0);
2133 cli->sesskey = IVAL(vwv + 6, 0);
2134 cli->serverzone = SVALS(vwv + 10, 0);
2135 cli->serverzone *= 60;
2136 /* this time is converted to GMT by make_unix_date */
2137 cli->servertime = cli_make_unix_date(
2138 cli, (char *)(vwv + 8));
2139 cli->readbraw_supported = ((SVAL(vwv + 5, 0) & 0x1) != 0);
2140 cli->writebraw_supported = ((SVAL(vwv + 5, 0) & 0x2) != 0);
2141 cli->secblob = data_blob(bytes, num_bytes);
2142 } else {
2143 /* the old core protocol */
2144 cli->use_spnego = False;
2145 cli->sec_mode = 0;
2146 cli->serverzone = get_time_zone(time(NULL));
2149 cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
2151 /* a way to force ascii SMB */
2152 if (getenv("CLI_FORCE_ASCII"))
2153 cli->capabilities &= ~CAP_UNICODE;
2155 tevent_req_done(req);
2158 NTSTATUS cli_negprot_recv(struct tevent_req *req)
2160 return tevent_req_simple_recv_ntstatus(req);
2163 NTSTATUS cli_negprot(struct cli_state *cli)
2165 TALLOC_CTX *frame = talloc_stackframe();
2166 struct event_context *ev;
2167 struct tevent_req *req;
2168 NTSTATUS status = NT_STATUS_OK;
2170 if (cli_has_async_calls(cli)) {
2172 * Can't use sync call while an async call is in flight
2174 status = NT_STATUS_INVALID_PARAMETER;
2175 goto fail;
2178 ev = event_context_init(frame);
2179 if (ev == NULL) {
2180 status = NT_STATUS_NO_MEMORY;
2181 goto fail;
2184 req = cli_negprot_send(frame, ev, cli);
2185 if (req == NULL) {
2186 status = NT_STATUS_NO_MEMORY;
2187 goto fail;
2190 if (!tevent_req_poll(req, ev)) {
2191 status = map_nt_error_from_unix(errno);
2192 goto fail;
2195 status = cli_negprot_recv(req);
2196 fail:
2197 TALLOC_FREE(frame);
2198 if (!NT_STATUS_IS_OK(status)) {
2199 cli_set_error(cli, status);
2201 return status;
2204 /****************************************************************************
2205 Send a session request. See rfc1002.txt 4.3 and 4.3.2.
2206 ****************************************************************************/
2208 bool cli_session_request(struct cli_state *cli,
2209 struct nmb_name *calling, struct nmb_name *called)
2211 char *p;
2212 int len = 4;
2213 char *tmp;
2215 /* 445 doesn't have session request */
2216 if (cli->port == 445)
2217 return True;
2219 memcpy(&(cli->calling), calling, sizeof(*calling));
2220 memcpy(&(cli->called ), called , sizeof(*called ));
2222 /* put in the destination name */
2224 tmp = name_mangle(talloc_tos(), cli->called.name,
2225 cli->called.name_type);
2226 if (tmp == NULL) {
2227 return false;
2230 p = cli->outbuf+len;
2231 memcpy(p, tmp, name_len(tmp));
2232 len += name_len(tmp);
2233 TALLOC_FREE(tmp);
2235 /* and my name */
2237 tmp = name_mangle(talloc_tos(), cli->calling.name,
2238 cli->calling.name_type);
2239 if (tmp == NULL) {
2240 return false;
2243 p = cli->outbuf+len;
2244 memcpy(p, tmp, name_len(tmp));
2245 len += name_len(tmp);
2246 TALLOC_FREE(tmp);
2248 /* send a session request (RFC 1002) */
2249 /* setup the packet length
2250 * Remove four bytes from the length count, since the length
2251 * field in the NBT Session Service header counts the number
2252 * of bytes which follow. The cli_send_smb() function knows
2253 * about this and accounts for those four bytes.
2254 * CRH.
2256 len -= 4;
2257 _smb_setlen(cli->outbuf,len);
2258 SCVAL(cli->outbuf,0,0x81);
2260 cli_send_smb(cli);
2261 DEBUG(5,("Sent session request\n"));
2263 if (!cli_receive_smb(cli))
2264 return False;
2266 if (CVAL(cli->inbuf,0) == 0x84) {
2267 /* C. Hoch 9/14/95 Start */
2268 /* For information, here is the response structure.
2269 * We do the byte-twiddling to for portability.
2270 struct RetargetResponse{
2271 unsigned char type;
2272 unsigned char flags;
2273 int16 length;
2274 int32 ip_addr;
2275 int16 port;
2278 uint16_t port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
2279 struct in_addr dest_ip;
2280 NTSTATUS status;
2282 /* SESSION RETARGET */
2283 putip((char *)&dest_ip,cli->inbuf+4);
2284 in_addr_to_sockaddr_storage(&cli->dest_ss, dest_ip);
2286 status = open_socket_out(&cli->dest_ss, port,
2287 LONG_CONNECT_TIMEOUT, &cli->fd);
2288 if (!NT_STATUS_IS_OK(status)) {
2289 return False;
2292 DEBUG(3,("Retargeted\n"));
2294 set_socket_options(cli->fd, lp_socket_options());
2296 /* Try again */
2298 static int depth;
2299 bool ret;
2300 if (depth > 4) {
2301 DEBUG(0,("Retarget recursion - failing\n"));
2302 return False;
2304 depth++;
2305 ret = cli_session_request(cli, calling, called);
2306 depth--;
2307 return ret;
2309 } /* C. Hoch 9/14/95 End */
2311 if (CVAL(cli->inbuf,0) != 0x82) {
2312 /* This is the wrong place to put the error... JRA. */
2313 cli->rap_error = CVAL(cli->inbuf,4);
2314 return False;
2316 return(True);
2319 struct fd_struct {
2320 int fd;
2323 static void smb_sock_connected(struct tevent_req *req)
2325 struct fd_struct *pfd = tevent_req_callback_data(
2326 req, struct fd_struct);
2327 int fd;
2328 NTSTATUS status;
2330 status = open_socket_out_defer_recv(req, &fd);
2331 if (NT_STATUS_IS_OK(status)) {
2332 pfd->fd = fd;
2336 static NTSTATUS open_smb_socket(const struct sockaddr_storage *pss,
2337 uint16_t *port, int timeout, int *pfd)
2339 struct event_context *ev;
2340 struct tevent_req *r139, *r445;
2341 struct fd_struct *fd139, *fd445;
2342 NTSTATUS status = NT_STATUS_NO_MEMORY;
2344 if (*port != 0) {
2345 return open_socket_out(pss, *port, timeout, pfd);
2348 ev = event_context_init(talloc_tos());
2349 if (ev == NULL) {
2350 return NT_STATUS_NO_MEMORY;
2353 fd139 = talloc(ev, struct fd_struct);
2354 if (fd139 == NULL) {
2355 goto done;
2357 fd139->fd = -1;
2359 fd445 = talloc(ev, struct fd_struct);
2360 if (fd445 == NULL) {
2361 goto done;
2363 fd445->fd = -1;
2365 r445 = open_socket_out_defer_send(ev, ev, timeval_set(0, 0),
2366 pss, 445, timeout);
2367 r139 = open_socket_out_defer_send(ev, ev, timeval_set(0, 3000),
2368 pss, 139, timeout);
2369 if ((r445 == NULL) || (r139 == NULL)) {
2370 goto done;
2372 tevent_req_set_callback(r445, smb_sock_connected, fd445);
2373 tevent_req_set_callback(r139, smb_sock_connected, fd139);
2375 while ((fd445->fd == -1) && (fd139->fd == -1)
2376 && (tevent_req_is_in_progress(r139)
2377 || tevent_req_is_in_progress(r445))) {
2378 event_loop_once(ev);
2381 if ((fd139->fd != -1) && (fd445->fd != -1)) {
2382 close(fd139->fd);
2383 fd139->fd = -1;
2386 if (fd445->fd != -1) {
2387 *port = 445;
2388 *pfd = fd445->fd;
2389 status = NT_STATUS_OK;
2390 goto done;
2392 if (fd139->fd != -1) {
2393 *port = 139;
2394 *pfd = fd139->fd;
2395 status = NT_STATUS_OK;
2396 goto done;
2399 status = open_socket_out_defer_recv(r445, &fd445->fd);
2400 done:
2401 TALLOC_FREE(ev);
2402 return status;
2405 /****************************************************************************
2406 Open the client sockets.
2407 ****************************************************************************/
2409 NTSTATUS cli_connect(struct cli_state *cli,
2410 const char *host,
2411 struct sockaddr_storage *dest_ss)
2414 int name_type = 0x20;
2415 TALLOC_CTX *frame = talloc_stackframe();
2416 unsigned int num_addrs = 0;
2417 unsigned int i = 0;
2418 struct sockaddr_storage *ss_arr = NULL;
2419 char *p = NULL;
2421 /* reasonable default hostname */
2422 if (!host) {
2423 host = STAR_SMBSERVER;
2426 fstrcpy(cli->desthost, host);
2428 /* allow hostnames of the form NAME#xx and do a netbios lookup */
2429 if ((p = strchr(cli->desthost, '#'))) {
2430 name_type = strtol(p+1, NULL, 16);
2431 *p = 0;
2434 if (!dest_ss || is_zero_addr((struct sockaddr *)dest_ss)) {
2435 NTSTATUS status =resolve_name_list(frame,
2436 cli->desthost,
2437 name_type,
2438 &ss_arr,
2439 &num_addrs);
2440 if (!NT_STATUS_IS_OK(status)) {
2441 TALLOC_FREE(frame);
2442 return NT_STATUS_BAD_NETWORK_NAME;
2444 } else {
2445 num_addrs = 1;
2446 ss_arr = TALLOC_P(frame, struct sockaddr_storage);
2447 if (!ss_arr) {
2448 TALLOC_FREE(frame);
2449 return NT_STATUS_NO_MEMORY;
2451 *ss_arr = *dest_ss;
2454 for (i = 0; i < num_addrs; i++) {
2455 cli->dest_ss = ss_arr[i];
2456 if (getenv("LIBSMB_PROG")) {
2457 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
2458 } else {
2459 uint16_t port = cli->port;
2460 NTSTATUS status;
2461 status = open_smb_socket(&cli->dest_ss, &port,
2462 cli->timeout, &cli->fd);
2463 if (NT_STATUS_IS_OK(status)) {
2464 cli->port = port;
2467 if (cli->fd == -1) {
2468 char addr[INET6_ADDRSTRLEN];
2469 print_sockaddr(addr, sizeof(addr), &ss_arr[i]);
2470 DEBUG(2,("Error connecting to %s (%s)\n",
2471 dest_ss?addr:host,strerror(errno)));
2472 } else {
2473 /* Exit from loop on first connection. */
2474 break;
2478 if (cli->fd == -1) {
2479 TALLOC_FREE(frame);
2480 return map_nt_error_from_unix(errno);
2483 if (dest_ss) {
2484 *dest_ss = cli->dest_ss;
2487 set_socket_options(cli->fd, lp_socket_options());
2489 TALLOC_FREE(frame);
2490 return NT_STATUS_OK;
2494 establishes a connection to after the negprot.
2495 @param output_cli A fully initialised cli structure, non-null only on success
2496 @param dest_host The netbios name of the remote host
2497 @param dest_ss (optional) The the destination IP, NULL for name based lookup
2498 @param port (optional) The destination port (0 for default)
2499 @param retry bool. Did this connection fail with a retryable error ?
2502 NTSTATUS cli_start_connection(struct cli_state **output_cli,
2503 const char *my_name,
2504 const char *dest_host,
2505 struct sockaddr_storage *dest_ss, int port,
2506 int signing_state, int flags,
2507 bool *retry)
2509 NTSTATUS nt_status;
2510 struct nmb_name calling;
2511 struct nmb_name called;
2512 struct cli_state *cli;
2513 struct sockaddr_storage ss;
2515 if (retry)
2516 *retry = False;
2518 if (!my_name)
2519 my_name = global_myname();
2521 if (!(cli = cli_initialise_ex(signing_state))) {
2522 return NT_STATUS_NO_MEMORY;
2525 make_nmb_name(&calling, my_name, 0x0);
2526 make_nmb_name(&called , dest_host, 0x20);
2528 cli_set_port(cli, port);
2529 cli_set_timeout(cli, 10000); /* 10 seconds. */
2531 if (dest_ss) {
2532 ss = *dest_ss;
2533 } else {
2534 zero_sockaddr(&ss);
2537 again:
2539 DEBUG(3,("Connecting to host=%s\n", dest_host));
2541 nt_status = cli_connect(cli, dest_host, &ss);
2542 if (!NT_STATUS_IS_OK(nt_status)) {
2543 char addr[INET6_ADDRSTRLEN];
2544 print_sockaddr(addr, sizeof(addr), &ss);
2545 DEBUG(1,("cli_start_connection: failed to connect to %s (%s). Error %s\n",
2546 nmb_namestr(&called), addr, nt_errstr(nt_status) ));
2547 cli_shutdown(cli);
2548 return nt_status;
2551 if (retry)
2552 *retry = True;
2554 if (!cli_session_request(cli, &calling, &called)) {
2555 char *p;
2556 DEBUG(1,("session request to %s failed (%s)\n",
2557 called.name, cli_errstr(cli)));
2558 if ((p=strchr(called.name, '.')) && !is_ipaddress(called.name)) {
2559 *p = 0;
2560 goto again;
2562 if (strcmp(called.name, STAR_SMBSERVER)) {
2563 make_nmb_name(&called , STAR_SMBSERVER, 0x20);
2564 goto again;
2566 return NT_STATUS_BAD_NETWORK_NAME;
2569 if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO)
2570 cli->use_spnego = False;
2571 else if (flags & CLI_FULL_CONNECTION_USE_KERBEROS)
2572 cli->use_kerberos = True;
2574 if ((flags & CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS) &&
2575 cli->use_kerberos) {
2576 cli->fallback_after_kerberos = true;
2578 if (flags & CLI_FULL_CONNECTION_USE_CCACHE) {
2579 cli->use_ccache = true;
2582 nt_status = cli_negprot(cli);
2583 if (!NT_STATUS_IS_OK(nt_status)) {
2584 DEBUG(1, ("failed negprot: %s\n", nt_errstr(nt_status)));
2585 cli_shutdown(cli);
2586 return nt_status;
2589 *output_cli = cli;
2590 return NT_STATUS_OK;
2595 establishes a connection right up to doing tconX, password specified.
2596 @param output_cli A fully initialised cli structure, non-null only on success
2597 @param dest_host The netbios name of the remote host
2598 @param dest_ip (optional) The the destination IP, NULL for name based lookup
2599 @param port (optional) The destination port (0 for default)
2600 @param service (optional) The share to make the connection to. Should be 'unqualified' in any way.
2601 @param service_type The 'type' of serivice.
2602 @param user Username, unix string
2603 @param domain User's domain
2604 @param password User's password, unencrypted unix string.
2605 @param retry bool. Did this connection fail with a retryable error ?
2608 NTSTATUS cli_full_connection(struct cli_state **output_cli,
2609 const char *my_name,
2610 const char *dest_host,
2611 struct sockaddr_storage *dest_ss, int port,
2612 const char *service, const char *service_type,
2613 const char *user, const char *domain,
2614 const char *password, int flags,
2615 int signing_state,
2616 bool *retry)
2618 NTSTATUS nt_status;
2619 struct cli_state *cli = NULL;
2620 int pw_len = password ? strlen(password)+1 : 0;
2622 *output_cli = NULL;
2624 if (password == NULL) {
2625 password = "";
2628 nt_status = cli_start_connection(&cli, my_name, dest_host,
2629 dest_ss, port, signing_state,
2630 flags, retry);
2632 if (!NT_STATUS_IS_OK(nt_status)) {
2633 return nt_status;
2636 cli->use_oplocks = ((flags & CLI_FULL_CONNECTION_OPLOCKS) != 0);
2637 cli->use_level_II_oplocks =
2638 ((flags & CLI_FULL_CONNECTION_LEVEL_II_OPLOCKS) != 0);
2640 nt_status = cli_session_setup(cli, user, password, pw_len, password,
2641 pw_len, domain);
2642 if (!NT_STATUS_IS_OK(nt_status)) {
2644 if (!(flags & CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK)) {
2645 DEBUG(1,("failed session setup with %s\n",
2646 nt_errstr(nt_status)));
2647 cli_shutdown(cli);
2648 return nt_status;
2651 nt_status = cli_session_setup(cli, "", "", 0, "", 0, domain);
2652 if (!NT_STATUS_IS_OK(nt_status)) {
2653 DEBUG(1,("anonymous failed session setup with %s\n",
2654 nt_errstr(nt_status)));
2655 cli_shutdown(cli);
2656 return nt_status;
2660 if (service) {
2661 nt_status = cli_tcon_andx(cli, service, service_type, password,
2662 pw_len);
2663 if (!NT_STATUS_IS_OK(nt_status)) {
2664 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(nt_status)));
2665 cli_shutdown(cli);
2666 if (NT_STATUS_IS_OK(nt_status)) {
2667 nt_status = NT_STATUS_UNSUCCESSFUL;
2669 return nt_status;
2673 nt_status = cli_init_creds(cli, user, domain, password);
2674 if (!NT_STATUS_IS_OK(nt_status)) {
2675 cli_shutdown(cli);
2676 return nt_status;
2679 *output_cli = cli;
2680 return NT_STATUS_OK;
2683 /****************************************************************************
2684 Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
2685 ****************************************************************************/
2687 bool attempt_netbios_session_request(struct cli_state **ppcli, const char *srchost, const char *desthost,
2688 struct sockaddr_storage *pdest_ss)
2690 struct nmb_name calling, called;
2692 make_nmb_name(&calling, srchost, 0x0);
2695 * If the called name is an IP address
2696 * then use *SMBSERVER immediately.
2699 if(is_ipaddress(desthost)) {
2700 make_nmb_name(&called, STAR_SMBSERVER, 0x20);
2701 } else {
2702 make_nmb_name(&called, desthost, 0x20);
2705 if (!cli_session_request(*ppcli, &calling, &called)) {
2706 NTSTATUS status;
2707 struct nmb_name smbservername;
2709 make_nmb_name(&smbservername, STAR_SMBSERVER, 0x20);
2712 * If the name wasn't *SMBSERVER then
2713 * try with *SMBSERVER if the first name fails.
2716 if (nmb_name_equal(&called, &smbservername)) {
2719 * The name used was *SMBSERVER, don't bother with another name.
2722 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
2723 with error %s.\n", desthost, cli_errstr(*ppcli) ));
2724 return False;
2727 /* Try again... */
2728 cli_shutdown(*ppcli);
2730 *ppcli = cli_initialise();
2731 if (!*ppcli) {
2732 /* Out of memory... */
2733 return False;
2736 status = cli_connect(*ppcli, desthost, pdest_ss);
2737 if (!NT_STATUS_IS_OK(status) ||
2738 !cli_session_request(*ppcli, &calling, &smbservername)) {
2739 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
2740 name *SMBSERVER with error %s\n", desthost, cli_errstr(*ppcli) ));
2741 return False;
2745 return True;
2748 /****************************************************************************
2749 Send an old style tcon.
2750 ****************************************************************************/
2751 NTSTATUS cli_raw_tcon(struct cli_state *cli,
2752 const char *service, const char *pass, const char *dev,
2753 uint16 *max_xmit, uint16 *tid)
2755 char *p;
2757 if (!lp_client_plaintext_auth() && (*pass)) {
2758 DEBUG(1, ("Server requested plaintext password but 'client "
2759 "plaintext auth' is disabled\n"));
2760 return NT_STATUS_ACCESS_DENIED;
2763 memset(cli->outbuf,'\0',smb_size);
2764 memset(cli->inbuf,'\0',smb_size);
2766 cli_set_message(cli->outbuf, 0, 0, True);
2767 SCVAL(cli->outbuf,smb_com,SMBtcon);
2768 cli_setup_packet(cli);
2770 p = smb_buf(cli->outbuf);
2771 *p++ = 4; p += clistr_push(cli, p, service, -1, STR_TERMINATE | STR_NOALIGN);
2772 *p++ = 4; p += clistr_push(cli, p, pass, -1, STR_TERMINATE | STR_NOALIGN);
2773 *p++ = 4; p += clistr_push(cli, p, dev, -1, STR_TERMINATE | STR_NOALIGN);
2775 cli_setup_bcc(cli, p);
2777 cli_send_smb(cli);
2778 if (!cli_receive_smb(cli)) {
2779 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
2782 if (cli_is_error(cli)) {
2783 return cli_nt_error(cli);
2786 *max_xmit = SVAL(cli->inbuf, smb_vwv0);
2787 *tid = SVAL(cli->inbuf, smb_vwv1);
2789 return NT_STATUS_OK;
2792 /* Return a cli_state pointing at the IPC$ share for the given server */
2794 struct cli_state *get_ipc_connect(char *server,
2795 struct sockaddr_storage *server_ss,
2796 const struct user_auth_info *user_info)
2798 struct cli_state *cli;
2799 NTSTATUS nt_status;
2800 uint32_t flags = CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK;
2802 if (user_info->use_kerberos) {
2803 flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
2806 nt_status = cli_full_connection(&cli, NULL, server, server_ss, 0, "IPC$", "IPC",
2807 user_info->username ? user_info->username : "",
2808 lp_workgroup(),
2809 user_info->password ? user_info->password : "",
2810 flags,
2811 Undefined, NULL);
2813 if (NT_STATUS_IS_OK(nt_status)) {
2814 return cli;
2815 } else if (is_ipaddress(server)) {
2816 /* windows 9* needs a correct NMB name for connections */
2817 fstring remote_name;
2819 if (name_status_find("*", 0, 0, server_ss, remote_name)) {
2820 cli = get_ipc_connect(remote_name, server_ss, user_info);
2821 if (cli)
2822 return cli;
2825 return NULL;
2829 * Given the IP address of a master browser on the network, return its
2830 * workgroup and connect to it.
2832 * This function is provided to allow additional processing beyond what
2833 * get_ipc_connect_master_ip_bcast() does, e.g. to retrieve the list of master
2834 * browsers and obtain each master browsers' list of domains (in case the
2835 * first master browser is recently on the network and has not yet
2836 * synchronized with other master browsers and therefore does not yet have the
2837 * entire network browse list)
2840 struct cli_state *get_ipc_connect_master_ip(TALLOC_CTX *ctx,
2841 struct ip_service *mb_ip,
2842 const struct user_auth_info *user_info,
2843 char **pp_workgroup_out)
2845 char addr[INET6_ADDRSTRLEN];
2846 fstring name;
2847 struct cli_state *cli;
2848 struct sockaddr_storage server_ss;
2850 *pp_workgroup_out = NULL;
2852 print_sockaddr(addr, sizeof(addr), &mb_ip->ss);
2853 DEBUG(99, ("Looking up name of master browser %s\n",
2854 addr));
2857 * Do a name status query to find out the name of the master browser.
2858 * We use <01><02>__MSBROWSE__<02>#01 if *#00 fails because a domain
2859 * master browser will not respond to a wildcard query (or, at least,
2860 * an NT4 server acting as the domain master browser will not).
2862 * We might be able to use ONLY the query on MSBROWSE, but that's not
2863 * yet been tested with all Windows versions, so until it is, leave
2864 * the original wildcard query as the first choice and fall back to
2865 * MSBROWSE if the wildcard query fails.
2867 if (!name_status_find("*", 0, 0x1d, &mb_ip->ss, name) &&
2868 !name_status_find(MSBROWSE, 1, 0x1d, &mb_ip->ss, name)) {
2870 DEBUG(99, ("Could not retrieve name status for %s\n",
2871 addr));
2872 return NULL;
2875 if (!find_master_ip(name, &server_ss)) {
2876 DEBUG(99, ("Could not find master ip for %s\n", name));
2877 return NULL;
2880 *pp_workgroup_out = talloc_strdup(ctx, name);
2882 DEBUG(4, ("found master browser %s, %s\n", name, addr));
2884 print_sockaddr(addr, sizeof(addr), &server_ss);
2885 cli = get_ipc_connect(addr, &server_ss, user_info);
2887 return cli;
2891 * Return the IP address and workgroup of a master browser on the network, and
2892 * connect to it.
2895 struct cli_state *get_ipc_connect_master_ip_bcast(TALLOC_CTX *ctx,
2896 const struct user_auth_info *user_info,
2897 char **pp_workgroup_out)
2899 struct ip_service *ip_list;
2900 struct cli_state *cli;
2901 int i, count;
2903 *pp_workgroup_out = NULL;
2905 DEBUG(99, ("Do broadcast lookup for workgroups on local network\n"));
2907 /* Go looking for workgroups by broadcasting on the local network */
2909 if (!NT_STATUS_IS_OK(name_resolve_bcast(MSBROWSE, 1, &ip_list,
2910 &count))) {
2911 DEBUG(99, ("No master browsers responded\n"));
2912 return False;
2915 for (i = 0; i < count; i++) {
2916 char addr[INET6_ADDRSTRLEN];
2917 print_sockaddr(addr, sizeof(addr), &ip_list[i].ss);
2918 DEBUG(99, ("Found master browser %s\n", addr));
2920 cli = get_ipc_connect_master_ip(ctx, &ip_list[i],
2921 user_info, pp_workgroup_out);
2922 if (cli)
2923 return(cli);
2926 return NULL;