s3: Add a talloc_move for the inbuf to cli_smb_recv
[Samba/kamenim.git] / source3 / libsmb / cliconnect.c
blobf5e763c1f2988c4010746f891af42a2c924f938f
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 char *inbuf;
268 uint8_t *bytes;
269 uint8_t *p;
270 NTSTATUS status;
272 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL,
273 &num_bytes, &bytes);
274 if (!NT_STATUS_IS_OK(status)) {
275 TALLOC_FREE(subreq);
276 tevent_req_nterror(req, status);
277 return;
280 inbuf = (char *)cli_smb_inbuf(subreq);
281 p = bytes;
283 cli->vuid = SVAL(inbuf, smb_uid);
285 p += clistr_pull(inbuf, cli->server_os, (char *)p, sizeof(fstring),
286 bytes+num_bytes-p, STR_TERMINATE);
287 p += clistr_pull(inbuf, cli->server_type, (char *)p, sizeof(fstring),
288 bytes+num_bytes-p, STR_TERMINATE);
289 p += clistr_pull(inbuf, cli->server_domain, (char *)p, sizeof(fstring),
290 bytes+num_bytes-p, STR_TERMINATE);
292 if (strstr(cli->server_type, "Samba")) {
293 cli->is_samba = True;
296 TALLOC_FREE(subreq);
298 status = cli_set_username(cli, "");
299 if (!NT_STATUS_IS_OK(status)) {
300 tevent_req_nterror(req, status);
301 return;
303 tevent_req_done(req);
306 NTSTATUS cli_session_setup_guest_recv(struct tevent_req *req)
308 return tevent_req_simple_recv_ntstatus(req);
311 static NTSTATUS cli_session_setup_guest(struct cli_state *cli)
313 TALLOC_CTX *frame = talloc_stackframe();
314 struct event_context *ev;
315 struct tevent_req *req;
316 NTSTATUS status = NT_STATUS_OK;
318 if (cli_has_async_calls(cli)) {
320 * Can't use sync call while an async call is in flight
322 status = NT_STATUS_INVALID_PARAMETER;
323 goto fail;
326 ev = event_context_init(frame);
327 if (ev == NULL) {
328 status = NT_STATUS_NO_MEMORY;
329 goto fail;
332 req = cli_session_setup_guest_send(frame, ev, cli);
333 if (req == NULL) {
334 status = NT_STATUS_NO_MEMORY;
335 goto fail;
338 if (!tevent_req_poll(req, ev)) {
339 status = map_nt_error_from_unix(errno);
340 goto fail;
343 status = cli_session_setup_guest_recv(req);
344 fail:
345 TALLOC_FREE(frame);
346 if (!NT_STATUS_IS_OK(status)) {
347 cli_set_error(cli, status);
349 return status;
352 /****************************************************************************
353 Do a NT1 plaintext session setup.
354 ****************************************************************************/
356 static NTSTATUS cli_session_setup_plaintext(struct cli_state *cli,
357 const char *user, const char *pass,
358 const char *workgroup)
360 uint32 capabilities = cli_session_setup_capabilities(cli);
361 char *p;
362 NTSTATUS status;
363 fstring lanman;
365 fstr_sprintf( lanman, "Samba %s", samba_version_string());
367 memset(cli->outbuf, '\0', smb_size);
368 cli_set_message(cli->outbuf,13,0,True);
369 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
370 cli_setup_packet(cli);
372 SCVAL(cli->outbuf,smb_vwv0,0xFF);
373 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
374 SSVAL(cli->outbuf,smb_vwv3,2);
375 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
376 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
377 SSVAL(cli->outbuf,smb_vwv8,0);
378 SIVAL(cli->outbuf,smb_vwv11,capabilities);
379 p = smb_buf(cli->outbuf);
381 /* check wether to send the ASCII or UNICODE version of the password */
383 if ( (capabilities & CAP_UNICODE) == 0 ) {
384 p += clistr_push(cli, p, pass, -1, STR_TERMINATE); /* password */
385 SSVAL(cli->outbuf,smb_vwv7,PTR_DIFF(p, smb_buf(cli->outbuf)));
387 else {
388 /* For ucs2 passwords clistr_push calls ucs2_align, which causes
389 * the space taken by the unicode password to be one byte too
390 * long (as we're on an odd byte boundary here). Reduce the
391 * count by 1 to cope with this. Fixes smbclient against NetApp
392 * servers which can't cope. Fix from
393 * bryan.kolodziej@allenlund.com in bug #3840.
395 p += clistr_push(cli, p, pass, -1, STR_UNICODE|STR_TERMINATE); /* unicode password */
396 SSVAL(cli->outbuf,smb_vwv8,PTR_DIFF(p, smb_buf(cli->outbuf))-1);
399 p += clistr_push(cli, p, user, -1, STR_TERMINATE); /* username */
400 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE); /* workgroup */
401 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
402 p += clistr_push(cli, p, lanman, -1, STR_TERMINATE);
403 cli_setup_bcc(cli, p);
405 if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
406 return cli_nt_error(cli);
409 show_msg(cli->inbuf);
411 if (cli_is_error(cli)) {
412 return cli_nt_error(cli);
415 cli->vuid = SVAL(cli->inbuf,smb_uid);
416 p = smb_buf(cli->inbuf);
417 p += clistr_pull(cli->inbuf, cli->server_os, p, sizeof(fstring),
418 -1, STR_TERMINATE);
419 p += clistr_pull(cli->inbuf, cli->server_type, p, sizeof(fstring),
420 -1, STR_TERMINATE);
421 p += clistr_pull(cli->inbuf, cli->server_domain, p, sizeof(fstring),
422 -1, STR_TERMINATE);
423 status = cli_set_username(cli, user);
424 if (!NT_STATUS_IS_OK(status)) {
425 return status;
427 if (strstr(cli->server_type, "Samba")) {
428 cli->is_samba = True;
431 return NT_STATUS_OK;
434 /****************************************************************************
435 do a NT1 NTLM/LM encrypted session setup - for when extended security
436 is not negotiated.
437 @param cli client state to create do session setup on
438 @param user username
439 @param pass *either* cleartext password (passlen !=24) or LM response.
440 @param ntpass NT response, implies ntpasslen >=24, implies pass is not clear
441 @param workgroup The user's domain.
442 ****************************************************************************/
444 static NTSTATUS cli_session_setup_nt1(struct cli_state *cli, const char *user,
445 const char *pass, size_t passlen,
446 const char *ntpass, size_t ntpasslen,
447 const char *workgroup)
449 uint32 capabilities = cli_session_setup_capabilities(cli);
450 DATA_BLOB lm_response = data_blob_null;
451 DATA_BLOB nt_response = data_blob_null;
452 DATA_BLOB session_key = data_blob_null;
453 NTSTATUS result;
454 char *p;
455 bool ok;
457 if (passlen == 0) {
458 /* do nothing - guest login */
459 } else if (passlen != 24) {
460 if (lp_client_ntlmv2_auth()) {
461 DATA_BLOB server_chal;
462 DATA_BLOB names_blob;
463 server_chal = data_blob(cli->secblob.data, MIN(cli->secblob.length, 8));
465 /* note that the 'workgroup' here is a best guess - we don't know
466 the server's domain at this point. The 'server name' is also
467 dodgy...
469 names_blob = NTLMv2_generate_names_blob(NULL, cli->called.name, workgroup);
471 if (!SMBNTLMv2encrypt(NULL, user, workgroup, pass, &server_chal,
472 &names_blob,
473 &lm_response, &nt_response, NULL, &session_key)) {
474 data_blob_free(&names_blob);
475 data_blob_free(&server_chal);
476 return NT_STATUS_ACCESS_DENIED;
478 data_blob_free(&names_blob);
479 data_blob_free(&server_chal);
481 } else {
482 uchar nt_hash[16];
483 E_md4hash(pass, nt_hash);
485 #ifdef LANMAN_ONLY
486 nt_response = data_blob_null;
487 #else
488 nt_response = data_blob(NULL, 24);
489 SMBNTencrypt(pass,cli->secblob.data,nt_response.data);
490 #endif
491 /* non encrypted password supplied. Ignore ntpass. */
492 if (lp_client_lanman_auth()) {
493 lm_response = data_blob(NULL, 24);
494 if (!SMBencrypt(pass,cli->secblob.data, lm_response.data)) {
495 /* Oops, the LM response is invalid, just put
496 the NT response there instead */
497 data_blob_free(&lm_response);
498 lm_response = data_blob(nt_response.data, nt_response.length);
500 } else {
501 /* LM disabled, place NT# in LM field instead */
502 lm_response = data_blob(nt_response.data, nt_response.length);
505 session_key = data_blob(NULL, 16);
506 #ifdef LANMAN_ONLY
507 E_deshash(pass, session_key.data);
508 memset(&session_key.data[8], '\0', 8);
509 #else
510 SMBsesskeygen_ntv1(nt_hash, session_key.data);
511 #endif
513 cli_temp_set_signing(cli);
514 } else {
515 /* pre-encrypted password supplied. Only used for
516 security=server, can't do
517 signing because we don't have original key */
519 lm_response = data_blob(pass, passlen);
520 nt_response = data_blob(ntpass, ntpasslen);
523 /* send a session setup command */
524 memset(cli->outbuf,'\0',smb_size);
526 cli_set_message(cli->outbuf,13,0,True);
527 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
528 cli_setup_packet(cli);
530 SCVAL(cli->outbuf,smb_vwv0,0xFF);
531 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
532 SSVAL(cli->outbuf,smb_vwv3,2);
533 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
534 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
535 SSVAL(cli->outbuf,smb_vwv7,lm_response.length);
536 SSVAL(cli->outbuf,smb_vwv8,nt_response.length);
537 SIVAL(cli->outbuf,smb_vwv11,capabilities);
538 p = smb_buf(cli->outbuf);
539 if (lm_response.length) {
540 memcpy(p,lm_response.data, lm_response.length); p += lm_response.length;
542 if (nt_response.length) {
543 memcpy(p,nt_response.data, nt_response.length); p += nt_response.length;
545 p += clistr_push(cli, p, user, -1, STR_TERMINATE);
547 /* Upper case here might help some NTLMv2 implementations */
548 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
549 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
550 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
551 cli_setup_bcc(cli, p);
553 if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
554 result = cli_nt_error(cli);
555 goto end;
558 /* show_msg(cli->inbuf); */
560 if (cli_is_error(cli)) {
561 result = cli_nt_error(cli);
562 goto end;
565 #ifdef LANMAN_ONLY
566 ok = cli_simple_set_signing(cli, session_key, lm_response);
567 #else
568 ok = cli_simple_set_signing(cli, session_key, nt_response);
569 #endif
570 if (ok) {
571 if (!cli_check_sign_mac(cli, cli->inbuf, 1)) {
572 result = NT_STATUS_ACCESS_DENIED;
573 goto end;
577 /* use the returned vuid from now on */
578 cli->vuid = SVAL(cli->inbuf,smb_uid);
580 p = smb_buf(cli->inbuf);
581 p += clistr_pull(cli->inbuf, cli->server_os, p, sizeof(fstring),
582 -1, STR_TERMINATE);
583 p += clistr_pull(cli->inbuf, cli->server_type, p, sizeof(fstring),
584 -1, STR_TERMINATE);
585 p += clistr_pull(cli->inbuf, cli->server_domain, p, sizeof(fstring),
586 -1, STR_TERMINATE);
588 if (strstr(cli->server_type, "Samba")) {
589 cli->is_samba = True;
592 result = cli_set_username(cli, user);
593 if (!NT_STATUS_IS_OK(result)) {
594 goto end;
597 if (session_key.data) {
598 /* Have plaintext orginal */
599 cli_set_session_key(cli, session_key);
602 result = NT_STATUS_OK;
603 end:
604 data_blob_free(&lm_response);
605 data_blob_free(&nt_response);
606 data_blob_free(&session_key);
607 return result;
610 /* The following is calculated from :
611 * (smb_size-4) = 35
612 * (smb_wcnt * 2) = 24 (smb_wcnt == 12 in cli_session_setup_blob_send() )
613 * (strlen("Unix") + 1 + strlen("Samba") + 1) * 2 = 22 (unicode strings at
614 * end of packet.
617 #define BASE_SESSSETUP_BLOB_PACKET_SIZE (35 + 24 + 22)
619 struct cli_sesssetup_blob_state {
620 struct tevent_context *ev;
621 struct cli_state *cli;
622 DATA_BLOB blob;
623 uint16_t max_blob_size;
624 uint16_t vwv[12];
625 uint8_t *buf;
627 NTSTATUS status;
628 char *inbuf;
629 DATA_BLOB ret_blob;
632 static bool cli_sesssetup_blob_next(struct cli_sesssetup_blob_state *state,
633 struct tevent_req **psubreq);
634 static void cli_sesssetup_blob_done(struct tevent_req *subreq);
636 static struct tevent_req *cli_sesssetup_blob_send(TALLOC_CTX *mem_ctx,
637 struct tevent_context *ev,
638 struct cli_state *cli,
639 DATA_BLOB blob)
641 struct tevent_req *req, *subreq;
642 struct cli_sesssetup_blob_state *state;
644 req = tevent_req_create(mem_ctx, &state,
645 struct cli_sesssetup_blob_state);
646 if (req == NULL) {
647 return NULL;
649 state->ev = ev;
650 state->blob = blob;
651 state->cli = cli;
653 if (cli->max_xmit < BASE_SESSSETUP_BLOB_PACKET_SIZE + 1) {
654 DEBUG(1, ("cli_session_setup_blob: cli->max_xmit too small "
655 "(was %u, need minimum %u)\n",
656 (unsigned int)cli->max_xmit,
657 BASE_SESSSETUP_BLOB_PACKET_SIZE));
658 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
659 return tevent_req_post(req, ev);
661 state->max_blob_size =
662 MIN(cli->max_xmit - BASE_SESSSETUP_BLOB_PACKET_SIZE, 0xFFFF);
664 if (!cli_sesssetup_blob_next(state, &subreq)) {
665 tevent_req_nomem(NULL, req);
666 return tevent_req_post(req, ev);
668 tevent_req_set_callback(subreq, cli_sesssetup_blob_done, req);
669 return req;
672 static bool cli_sesssetup_blob_next(struct cli_sesssetup_blob_state *state,
673 struct tevent_req **psubreq)
675 struct tevent_req *subreq;
676 uint16_t thistime;
678 SCVAL(state->vwv+0, 0, 0xFF);
679 SCVAL(state->vwv+0, 1, 0);
680 SSVAL(state->vwv+1, 0, 0);
681 SSVAL(state->vwv+2, 0, CLI_BUFFER_SIZE);
682 SSVAL(state->vwv+3, 0, 2);
683 SSVAL(state->vwv+4, 0, 1);
684 SIVAL(state->vwv+5, 0, 0);
686 thistime = MIN(state->blob.length, state->max_blob_size);
687 SSVAL(state->vwv+7, 0, thistime);
689 SSVAL(state->vwv+8, 0, 0);
690 SSVAL(state->vwv+9, 0, 0);
691 SIVAL(state->vwv+10, 0,
692 cli_session_setup_capabilities(state->cli)
693 | CAP_EXTENDED_SECURITY);
695 state->buf = (uint8_t *)talloc_memdup(state, state->blob.data,
696 thistime);
697 if (state->buf == NULL) {
698 return false;
700 state->blob.data += thistime;
701 state->blob.length -= thistime;
703 state->buf = smb_bytes_push_str(state->buf, cli_ucs2(state->cli),
704 "Unix", 5, NULL);
705 state->buf = smb_bytes_push_str(state->buf, cli_ucs2(state->cli),
706 "Samba", 6, NULL);
707 if (state->buf == NULL) {
708 return false;
710 subreq = cli_smb_send(state, state->ev, state->cli, SMBsesssetupX, 0,
711 12, state->vwv,
712 talloc_get_size(state->buf), state->buf);
713 if (subreq == NULL) {
714 return false;
716 *psubreq = subreq;
717 return true;
720 static void cli_sesssetup_blob_done(struct tevent_req *subreq)
722 struct tevent_req *req = tevent_req_callback_data(
723 subreq, struct tevent_req);
724 struct cli_sesssetup_blob_state *state = tevent_req_data(
725 req, struct cli_sesssetup_blob_state);
726 struct cli_state *cli = state->cli;
727 uint8_t wct;
728 uint16_t *vwv;
729 uint32_t num_bytes;
730 uint8_t *bytes;
731 NTSTATUS status;
732 uint8_t *p;
733 uint16_t blob_length;
735 status = cli_smb_recv(subreq, NULL, NULL, 1, &wct, &vwv,
736 &num_bytes, &bytes);
737 if (!NT_STATUS_IS_OK(status)
738 && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
739 TALLOC_FREE(subreq);
740 tevent_req_nterror(req, status);
741 return;
744 state->status = status;
745 TALLOC_FREE(state->buf);
747 state->inbuf = (char *)cli_smb_inbuf(subreq);
748 cli->vuid = SVAL(state->inbuf, smb_uid);
750 blob_length = SVAL(vwv+3, 0);
751 if (blob_length > num_bytes) {
752 TALLOC_FREE(subreq);
753 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
754 return;
756 state->ret_blob = data_blob_const(bytes, blob_length);
758 p = bytes + blob_length;
760 p += clistr_pull(state->inbuf, cli->server_os,
761 (char *)p, sizeof(fstring),
762 bytes+num_bytes-p, STR_TERMINATE);
763 p += clistr_pull(state->inbuf, cli->server_type,
764 (char *)p, sizeof(fstring),
765 bytes+num_bytes-p, STR_TERMINATE);
766 p += clistr_pull(state->inbuf, cli->server_domain,
767 (char *)p, sizeof(fstring),
768 bytes+num_bytes-p, STR_TERMINATE);
770 if (strstr(cli->server_type, "Samba")) {
771 cli->is_samba = True;
774 if (state->blob.length != 0) {
775 TALLOC_FREE(subreq);
777 * More to send
779 if (!cli_sesssetup_blob_next(state, &subreq)) {
780 tevent_req_nomem(NULL, req);
781 return;
783 tevent_req_set_callback(subreq, cli_sesssetup_blob_done, req);
784 return;
786 tevent_req_done(req);
789 static NTSTATUS cli_sesssetup_blob_recv(struct tevent_req *req,
790 TALLOC_CTX *mem_ctx,
791 DATA_BLOB *pblob,
792 char **pinbuf)
794 struct cli_sesssetup_blob_state *state = tevent_req_data(
795 req, struct cli_sesssetup_blob_state);
796 NTSTATUS status;
797 char *inbuf;
799 if (tevent_req_is_nterror(req, &status)) {
800 state->cli->vuid = 0;
801 return status;
804 inbuf = talloc_move(mem_ctx, &state->inbuf);
805 if (pblob != NULL) {
806 *pblob = state->ret_blob;
808 if (pinbuf != NULL) {
809 *pinbuf = inbuf;
811 /* could be NT_STATUS_MORE_PROCESSING_REQUIRED */
812 return state->status;
815 #ifdef HAVE_KRB5
817 /****************************************************************************
818 Use in-memory credentials cache
819 ****************************************************************************/
821 static void use_in_memory_ccache(void) {
822 setenv(KRB5_ENV_CCNAME, "MEMORY:cliconnect", 1);
825 /****************************************************************************
826 Do a spnego/kerberos encrypted session setup.
827 ****************************************************************************/
829 struct cli_session_setup_kerberos_state {
830 struct cli_state *cli;
831 DATA_BLOB negTokenTarg;
832 DATA_BLOB session_key_krb5;
833 ADS_STATUS ads_status;
836 static void cli_session_setup_kerberos_done(struct tevent_req *subreq);
838 static struct tevent_req *cli_session_setup_kerberos_send(
839 TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
840 const char *principal, const char *workgroup)
842 struct tevent_req *req, *subreq;
843 struct cli_session_setup_kerberos_state *state;
844 int rc;
846 DEBUG(2,("Doing kerberos session setup\n"));
848 req = tevent_req_create(mem_ctx, &state,
849 struct cli_session_setup_kerberos_state);
850 if (req == NULL) {
851 return NULL;
853 state->cli = cli;
854 state->ads_status = ADS_SUCCESS;
856 cli_temp_set_signing(cli);
859 * Ok, this is cheated: spnego_gen_negTokenTarg can block if
860 * we have to acquire a ticket. To be fixed later :-)
862 rc = spnego_gen_negTokenTarg(principal, 0, &state->negTokenTarg,
863 &state->session_key_krb5, 0, NULL);
864 if (rc) {
865 DEBUG(1, ("cli_session_setup_kerberos: "
866 "spnego_gen_negTokenTarg failed: %s\n",
867 error_message(rc)));
868 state->ads_status = ADS_ERROR_KRB5(rc);
869 tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
870 return tevent_req_post(req, ev);
873 #if 0
874 file_save("negTokenTarg.dat", state->negTokenTarg.data,
875 state->negTokenTarg.length);
876 #endif
878 subreq = cli_sesssetup_blob_send(state, ev, cli, state->negTokenTarg);
879 if (tevent_req_nomem(subreq, req)) {
880 return tevent_req_post(req, ev);
882 tevent_req_set_callback(subreq, cli_session_setup_kerberos_done, req);
883 return req;
886 static void cli_session_setup_kerberos_done(struct tevent_req *subreq)
888 struct tevent_req *req = tevent_req_callback_data(
889 subreq, struct tevent_req);
890 struct cli_session_setup_kerberos_state *state = tevent_req_data(
891 req, struct cli_session_setup_kerberos_state);
892 char *inbuf = NULL;
893 NTSTATUS status;
895 status = cli_sesssetup_blob_recv(subreq, talloc_tos(), NULL, &inbuf);
896 if (!NT_STATUS_IS_OK(status)) {
897 TALLOC_FREE(subreq);
898 tevent_req_nterror(req, status);
899 return;
902 cli_set_session_key(state->cli, state->session_key_krb5);
904 if (cli_simple_set_signing(state->cli, state->session_key_krb5,
905 data_blob_null)
906 && !cli_check_sign_mac(state->cli, inbuf, 1)) {
907 TALLOC_FREE(subreq);
908 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
909 return;
911 TALLOC_FREE(subreq);
912 tevent_req_done(req);
915 static ADS_STATUS cli_session_setup_kerberos_recv(struct tevent_req *req)
917 struct cli_session_setup_kerberos_state *state = tevent_req_data(
918 req, struct cli_session_setup_kerberos_state);
919 NTSTATUS status;
921 if (tevent_req_is_nterror(req, &status)) {
922 return ADS_ERROR_NT(status);
924 return state->ads_status;
927 static ADS_STATUS cli_session_setup_kerberos(struct cli_state *cli,
928 const char *principal,
929 const char *workgroup)
931 struct tevent_context *ev;
932 struct tevent_req *req;
933 ADS_STATUS status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
935 if (cli_has_async_calls(cli)) {
936 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
938 ev = tevent_context_init(talloc_tos());
939 if (ev == NULL) {
940 goto fail;
942 req = cli_session_setup_kerberos_send(ev, ev, cli, principal,
943 workgroup);
944 if (req == NULL) {
945 goto fail;
947 if (!tevent_req_poll(req, ev)) {
948 status = ADS_ERROR_SYSTEM(errno);
949 goto fail;
951 status = cli_session_setup_kerberos_recv(req);
952 fail:
953 TALLOC_FREE(ev);
954 return status;
956 #endif /* HAVE_KRB5 */
958 /****************************************************************************
959 Do a spnego/NTLMSSP encrypted session setup.
960 ****************************************************************************/
962 struct cli_session_setup_ntlmssp_state {
963 struct tevent_context *ev;
964 struct cli_state *cli;
965 struct ntlmssp_state *ntlmssp_state;
966 int turn;
967 DATA_BLOB blob_out;
970 static int cli_session_setup_ntlmssp_state_destructor(
971 struct cli_session_setup_ntlmssp_state *state)
973 if (state->ntlmssp_state != NULL) {
974 ntlmssp_end(&state->ntlmssp_state);
976 return 0;
979 static void cli_session_setup_ntlmssp_done(struct tevent_req *req);
981 static struct tevent_req *cli_session_setup_ntlmssp_send(
982 TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
983 const char *user, const char *pass, const char *domain)
985 struct tevent_req *req, *subreq;
986 struct cli_session_setup_ntlmssp_state *state;
987 NTSTATUS status;
988 DATA_BLOB blob_out;
990 req = tevent_req_create(mem_ctx, &state,
991 struct cli_session_setup_ntlmssp_state);
992 if (req == NULL) {
993 return NULL;
995 state->ev = ev;
996 state->cli = cli;
997 state->turn = 1;
999 state->ntlmssp_state = NULL;
1000 talloc_set_destructor(
1001 state, cli_session_setup_ntlmssp_state_destructor);
1003 cli_temp_set_signing(cli);
1005 status = ntlmssp_client_start(&state->ntlmssp_state);
1006 if (!NT_STATUS_IS_OK(status)) {
1007 goto fail;
1009 ntlmssp_want_feature(state->ntlmssp_state,
1010 NTLMSSP_FEATURE_SESSION_KEY);
1011 if (cli->use_ccache) {
1012 ntlmssp_want_feature(state->ntlmssp_state,
1013 NTLMSSP_FEATURE_CCACHE);
1015 status = ntlmssp_set_username(state->ntlmssp_state, user);
1016 if (!NT_STATUS_IS_OK(status)) {
1017 goto fail;
1019 status = ntlmssp_set_domain(state->ntlmssp_state, domain);
1020 if (!NT_STATUS_IS_OK(status)) {
1021 goto fail;
1023 status = ntlmssp_set_password(state->ntlmssp_state, pass);
1024 if (!NT_STATUS_IS_OK(status)) {
1025 goto fail;
1027 status = ntlmssp_update(state->ntlmssp_state, data_blob_null,
1028 &blob_out);
1029 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1030 goto fail;
1033 state->blob_out = gen_negTokenInit(OID_NTLMSSP, blob_out);
1034 data_blob_free(&blob_out);
1036 subreq = cli_sesssetup_blob_send(state, ev, cli, state->blob_out);
1037 if (tevent_req_nomem(subreq, req)) {
1038 return tevent_req_post(req, ev);
1040 tevent_req_set_callback(subreq, cli_session_setup_ntlmssp_done, req);
1041 return req;
1042 fail:
1043 tevent_req_nterror(req, status);
1044 return tevent_req_post(req, ev);
1047 static void cli_session_setup_ntlmssp_done(struct tevent_req *subreq)
1049 struct tevent_req *req = tevent_req_callback_data(
1050 subreq, struct tevent_req);
1051 struct cli_session_setup_ntlmssp_state *state = tevent_req_data(
1052 req, struct cli_session_setup_ntlmssp_state);
1053 DATA_BLOB blob_in, msg_in, blob_out;
1054 char *inbuf = NULL;
1055 bool parse_ret;
1056 NTSTATUS status;
1058 status = cli_sesssetup_blob_recv(subreq, talloc_tos(), &blob_in,
1059 &inbuf);
1060 TALLOC_FREE(subreq);
1061 data_blob_free(&state->blob_out);
1063 if (NT_STATUS_IS_OK(status)) {
1064 if (state->cli->server_domain[0] == '\0') {
1065 fstrcpy(state->cli->server_domain,
1066 state->ntlmssp_state->server_domain);
1068 cli_set_session_key(
1069 state->cli, state->ntlmssp_state->session_key);
1071 if (cli_simple_set_signing(
1072 state->cli, state->ntlmssp_state->session_key,
1073 data_blob_null)
1074 && !cli_check_sign_mac(state->cli, inbuf, 1)) {
1075 TALLOC_FREE(subreq);
1076 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1077 return;
1079 TALLOC_FREE(subreq);
1080 ntlmssp_end(&state->ntlmssp_state);
1081 tevent_req_done(req);
1082 return;
1084 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1085 tevent_req_nterror(req, status);
1086 return;
1089 if (blob_in.length == 0) {
1090 tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
1091 return;
1094 if ((state->turn == 1)
1095 && NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1096 DATA_BLOB tmp_blob = data_blob_null;
1097 /* the server might give us back two challenges */
1098 parse_ret = spnego_parse_challenge(blob_in, &msg_in,
1099 &tmp_blob);
1100 data_blob_free(&tmp_blob);
1101 } else {
1102 parse_ret = spnego_parse_auth_response(blob_in, status,
1103 OID_NTLMSSP, &msg_in);
1105 state->turn += 1;
1107 if (!parse_ret) {
1108 DEBUG(3,("Failed to parse auth response\n"));
1109 if (NT_STATUS_IS_OK(status)
1110 || NT_STATUS_EQUAL(status,
1111 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1112 tevent_req_nterror(
1113 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
1114 return;
1118 status = ntlmssp_update(state->ntlmssp_state, msg_in, &blob_out);
1120 if (!NT_STATUS_IS_OK(status)
1121 && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1122 TALLOC_FREE(subreq);
1123 ntlmssp_end(&state->ntlmssp_state);
1124 tevent_req_nterror(req, status);
1125 return;
1128 state->blob_out = spnego_gen_auth(blob_out);
1129 TALLOC_FREE(subreq);
1130 if (tevent_req_nomem(state->blob_out.data, req)) {
1131 return;
1134 subreq = cli_sesssetup_blob_send(state, state->ev, state->cli,
1135 state->blob_out);
1136 if (tevent_req_nomem(subreq, req)) {
1137 return;
1139 tevent_req_set_callback(subreq, cli_session_setup_ntlmssp_done, req);
1142 static NTSTATUS cli_session_setup_ntlmssp_recv(struct tevent_req *req)
1144 struct cli_session_setup_ntlmssp_state *state = tevent_req_data(
1145 req, struct cli_session_setup_ntlmssp_state);
1146 NTSTATUS status;
1148 if (tevent_req_is_nterror(req, &status)) {
1149 state->cli->vuid = 0;
1150 return status;
1152 return NT_STATUS_OK;
1155 static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli,
1156 const char *user,
1157 const char *pass,
1158 const char *domain)
1160 struct tevent_context *ev;
1161 struct tevent_req *req;
1162 NTSTATUS status = NT_STATUS_NO_MEMORY;
1164 if (cli_has_async_calls(cli)) {
1165 return NT_STATUS_INVALID_PARAMETER;
1167 ev = tevent_context_init(talloc_tos());
1168 if (ev == NULL) {
1169 goto fail;
1171 req = cli_session_setup_ntlmssp_send(ev, ev, cli, user, pass, domain);
1172 if (req == NULL) {
1173 goto fail;
1175 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1176 goto fail;
1178 status = cli_session_setup_ntlmssp_recv(req);
1179 fail:
1180 TALLOC_FREE(ev);
1181 if (!NT_STATUS_IS_OK(status)) {
1182 cli_set_error(cli, status);
1184 return status;
1187 /****************************************************************************
1188 Do a spnego encrypted session setup.
1190 user_domain: The shortname of the domain the user/machine is a member of.
1191 dest_realm: The realm we're connecting to, if NULL we use our default realm.
1192 ****************************************************************************/
1194 ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, const char *user,
1195 const char *pass, const char *user_domain,
1196 const char * dest_realm)
1198 char *principal = NULL;
1199 char *OIDs[ASN1_MAX_OIDS];
1200 int i;
1201 DATA_BLOB blob;
1202 const char *p = NULL;
1203 char *account = NULL;
1204 NTSTATUS status;
1206 DEBUG(3,("Doing spnego session setup (blob length=%lu)\n", (unsigned long)cli->secblob.length));
1208 /* the server might not even do spnego */
1209 if (cli->secblob.length <= 16) {
1210 DEBUG(3,("server didn't supply a full spnego negprot\n"));
1211 goto ntlmssp;
1214 #if 0
1215 file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
1216 #endif
1218 /* there is 16 bytes of GUID before the real spnego packet starts */
1219 blob = data_blob(cli->secblob.data+16, cli->secblob.length-16);
1221 /* The server sent us the first part of the SPNEGO exchange in the
1222 * negprot reply. It is WRONG to depend on the principal sent in the
1223 * negprot reply, but right now we do it. If we don't receive one,
1224 * we try to best guess, then fall back to NTLM. */
1225 if (!spnego_parse_negTokenInit(blob, OIDs, &principal)) {
1226 data_blob_free(&blob);
1227 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
1229 data_blob_free(&blob);
1231 /* make sure the server understands kerberos */
1232 for (i=0;OIDs[i];i++) {
1233 if (i == 0)
1234 DEBUG(3,("got OID=%s\n", OIDs[i]));
1235 else
1236 DEBUGADD(3,("got OID=%s\n", OIDs[i]));
1237 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
1238 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
1239 cli->got_kerberos_mechanism = True;
1241 talloc_free(OIDs[i]);
1244 DEBUG(3,("got principal=%s\n", principal ? principal : "<null>"));
1246 status = cli_set_username(cli, user);
1247 if (!NT_STATUS_IS_OK(status)) {
1248 return ADS_ERROR_NT(status);
1251 #ifdef HAVE_KRB5
1252 /* If password is set we reauthenticate to kerberos server
1253 * and do not store results */
1255 if (cli->got_kerberos_mechanism && cli->use_kerberos) {
1256 ADS_STATUS rc;
1258 if (pass && *pass) {
1259 int ret;
1261 use_in_memory_ccache();
1262 ret = kerberos_kinit_password(user, pass, 0 /* no time correction for now */, NULL);
1264 if (ret){
1265 TALLOC_FREE(principal);
1266 DEBUG(0, ("Kinit failed: %s\n", error_message(ret)));
1267 if (cli->fallback_after_kerberos)
1268 goto ntlmssp;
1269 return ADS_ERROR_KRB5(ret);
1273 /* If we get a bad principal, try to guess it if
1274 we have a valid host NetBIOS name.
1276 if (strequal(principal, ADS_IGNORE_PRINCIPAL)) {
1277 TALLOC_FREE(principal);
1280 if (principal == NULL &&
1281 !is_ipaddress(cli->desthost) &&
1282 !strequal(STAR_SMBSERVER,
1283 cli->desthost)) {
1284 char *realm = NULL;
1285 char *machine = NULL;
1286 char *host = NULL;
1287 DEBUG(3,("cli_session_setup_spnego: got a "
1288 "bad server principal, trying to guess ...\n"));
1290 host = strchr_m(cli->desthost, '.');
1291 if (host) {
1292 /* We had a '.' in the name. */
1293 machine = SMB_STRNDUP(cli->desthost,
1294 host - cli->desthost);
1295 } else {
1296 machine = SMB_STRDUP(cli->desthost);
1298 if (machine == NULL) {
1299 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1302 if (dest_realm) {
1303 realm = SMB_STRDUP(dest_realm);
1304 strupper_m(realm);
1305 } else {
1306 if (host) {
1307 /* DNS name. */
1308 realm = kerberos_get_realm_from_hostname(cli->desthost);
1309 } else {
1310 /* NetBIOS name - use our realm. */
1311 realm = kerberos_get_default_realm_from_ccache();
1315 if (realm && *realm) {
1316 if (host) {
1317 /* DNS name. */
1318 principal = talloc_asprintf(talloc_tos(),
1319 "cifs/%s@%s",
1320 cli->desthost,
1321 realm);
1322 } else {
1323 /* NetBIOS name, use machine account. */
1324 principal = talloc_asprintf(talloc_tos(),
1325 "%s$@%s",
1326 machine,
1327 realm);
1329 if (!principal) {
1330 SAFE_FREE(machine);
1331 SAFE_FREE(realm);
1332 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1334 DEBUG(3,("cli_session_setup_spnego: guessed "
1335 "server principal=%s\n",
1336 principal ? principal : "<null>"));
1338 SAFE_FREE(machine);
1339 SAFE_FREE(realm);
1342 if (principal) {
1343 rc = cli_session_setup_kerberos(cli, principal,
1344 dest_realm);
1345 if (ADS_ERR_OK(rc) || !cli->fallback_after_kerberos) {
1346 TALLOC_FREE(principal);
1347 return rc;
1351 #endif
1353 TALLOC_FREE(principal);
1355 ntlmssp:
1357 account = talloc_strdup(talloc_tos(), user);
1358 if (!account) {
1359 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1362 /* when falling back to ntlmssp while authenticating with a machine
1363 * account strip off the realm - gd */
1365 if ((p = strchr_m(user, '@')) != NULL) {
1366 account[PTR_DIFF(p,user)] = '\0';
1369 return ADS_ERROR_NT(cli_session_setup_ntlmssp(cli, account, pass, user_domain));
1372 /****************************************************************************
1373 Send a session setup. The username and workgroup is in UNIX character
1374 format and must be converted to DOS codepage format before sending. If the
1375 password is in plaintext, the same should be done.
1376 ****************************************************************************/
1378 NTSTATUS cli_session_setup(struct cli_state *cli,
1379 const char *user,
1380 const char *pass, int passlen,
1381 const char *ntpass, int ntpasslen,
1382 const char *workgroup)
1384 char *p;
1385 fstring user2;
1387 if (user) {
1388 fstrcpy(user2, user);
1389 } else {
1390 user2[0] ='\0';
1393 if (!workgroup) {
1394 workgroup = "";
1397 /* allow for workgroups as part of the username */
1398 if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/')) ||
1399 (p=strchr_m(user2,*lp_winbind_separator()))) {
1400 *p = 0;
1401 user = p+1;
1402 workgroup = user2;
1405 if (cli->protocol < PROTOCOL_LANMAN1) {
1406 return NT_STATUS_OK;
1409 /* now work out what sort of session setup we are going to
1410 do. I have split this into separate functions to make the
1411 flow a bit easier to understand (tridge) */
1413 /* if its an older server then we have to use the older request format */
1415 if (cli->protocol < PROTOCOL_NT1) {
1416 if (!lp_client_lanman_auth() && passlen != 24 && (*pass)) {
1417 DEBUG(1, ("Server requested LM password but 'client lanman auth'"
1418 " is disabled\n"));
1419 return NT_STATUS_ACCESS_DENIED;
1422 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0 &&
1423 !lp_client_plaintext_auth() && (*pass)) {
1424 DEBUG(1, ("Server requested plaintext password but "
1425 "'client plaintext auth' is disabled\n"));
1426 return NT_STATUS_ACCESS_DENIED;
1429 return cli_session_setup_lanman2(cli, user, pass, passlen,
1430 workgroup);
1433 /* if no user is supplied then we have to do an anonymous connection.
1434 passwords are ignored */
1436 if (!user || !*user)
1437 return cli_session_setup_guest(cli);
1439 /* if the server is share level then send a plaintext null
1440 password at this point. The password is sent in the tree
1441 connect */
1443 if ((cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) == 0)
1444 return cli_session_setup_plaintext(cli, user, "", workgroup);
1446 /* if the server doesn't support encryption then we have to use
1447 plaintext. The second password is ignored */
1449 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) {
1450 if (!lp_client_plaintext_auth() && (*pass)) {
1451 DEBUG(1, ("Server requested plaintext password but "
1452 "'client plaintext auth' is disabled\n"));
1453 return NT_STATUS_ACCESS_DENIED;
1455 return cli_session_setup_plaintext(cli, user, pass, workgroup);
1458 /* if the server supports extended security then use SPNEGO */
1460 if (cli->capabilities & CAP_EXTENDED_SECURITY) {
1461 ADS_STATUS status = cli_session_setup_spnego(cli, user, pass,
1462 workgroup, NULL);
1463 if (!ADS_ERR_OK(status)) {
1464 DEBUG(3, ("SPNEGO login failed: %s\n", ads_errstr(status)));
1465 return ads_ntstatus(status);
1467 } else {
1468 NTSTATUS status;
1470 /* otherwise do a NT1 style session setup */
1471 status = cli_session_setup_nt1(cli, user, pass, passlen,
1472 ntpass, ntpasslen, workgroup);
1473 if (!NT_STATUS_IS_OK(status)) {
1474 DEBUG(3,("cli_session_setup: NT1 session setup "
1475 "failed: %s\n", nt_errstr(status)));
1476 return status;
1480 if (strstr(cli->server_type, "Samba")) {
1481 cli->is_samba = True;
1484 return NT_STATUS_OK;
1487 /****************************************************************************
1488 Send a uloggoff.
1489 *****************************************************************************/
1491 struct cli_ulogoff_state {
1492 struct cli_state *cli;
1493 uint16_t vwv[2];
1496 static void cli_ulogoff_done(struct tevent_req *subreq);
1498 struct tevent_req *cli_ulogoff_send(TALLOC_CTX *mem_ctx,
1499 struct tevent_context *ev,
1500 struct cli_state *cli)
1502 struct tevent_req *req, *subreq;
1503 struct cli_ulogoff_state *state;
1505 req = tevent_req_create(mem_ctx, &state, struct cli_ulogoff_state);
1506 if (req == NULL) {
1507 return NULL;
1509 state->cli = cli;
1511 SCVAL(state->vwv+0, 0, 0xFF);
1512 SCVAL(state->vwv+1, 0, 0);
1513 SSVAL(state->vwv+2, 0, 0);
1515 subreq = cli_smb_send(state, ev, cli, SMBulogoffX, 0, 2, state->vwv,
1516 0, NULL);
1517 if (tevent_req_nomem(subreq, req)) {
1518 return tevent_req_post(req, ev);
1520 tevent_req_set_callback(subreq, cli_ulogoff_done, req);
1521 return req;
1524 static void cli_ulogoff_done(struct tevent_req *subreq)
1526 struct tevent_req *req = tevent_req_callback_data(
1527 subreq, struct tevent_req);
1528 struct cli_ulogoff_state *state = tevent_req_data(
1529 req, struct cli_ulogoff_state);
1530 NTSTATUS status;
1532 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1533 if (!NT_STATUS_IS_OK(status)) {
1534 tevent_req_nterror(req, status);
1535 return;
1537 state->cli->vuid = -1;
1538 tevent_req_done(req);
1541 NTSTATUS cli_ulogoff_recv(struct tevent_req *req)
1543 return tevent_req_simple_recv_ntstatus(req);
1546 NTSTATUS cli_ulogoff(struct cli_state *cli)
1548 struct tevent_context *ev;
1549 struct tevent_req *req;
1550 NTSTATUS status = NT_STATUS_NO_MEMORY;
1552 if (cli_has_async_calls(cli)) {
1553 return NT_STATUS_INVALID_PARAMETER;
1555 ev = tevent_context_init(talloc_tos());
1556 if (ev == NULL) {
1557 goto fail;
1559 req = cli_ulogoff_send(ev, ev, cli);
1560 if (req == NULL) {
1561 goto fail;
1563 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1564 goto fail;
1566 status = cli_ulogoff_recv(req);
1567 fail:
1568 TALLOC_FREE(ev);
1569 if (!NT_STATUS_IS_OK(status)) {
1570 cli_set_error(cli, status);
1572 return status;
1575 /****************************************************************************
1576 Send a tconX.
1577 ****************************************************************************/
1579 struct cli_tcon_andx_state {
1580 struct cli_state *cli;
1581 uint16_t vwv[4];
1582 struct iovec bytes;
1585 static void cli_tcon_andx_done(struct tevent_req *subreq);
1587 struct tevent_req *cli_tcon_andx_create(TALLOC_CTX *mem_ctx,
1588 struct event_context *ev,
1589 struct cli_state *cli,
1590 const char *share, const char *dev,
1591 const char *pass, int passlen,
1592 struct tevent_req **psmbreq)
1594 struct tevent_req *req, *subreq;
1595 struct cli_tcon_andx_state *state;
1596 fstring pword;
1597 uint16_t *vwv;
1598 char *tmp = NULL;
1599 uint8_t *bytes;
1601 *psmbreq = NULL;
1603 req = tevent_req_create(mem_ctx, &state, struct cli_tcon_andx_state);
1604 if (req == NULL) {
1605 return NULL;
1607 state->cli = cli;
1608 vwv = state->vwv;
1610 fstrcpy(cli->share, share);
1612 /* in user level security don't send a password now */
1613 if (cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) {
1614 passlen = 1;
1615 pass = "";
1616 } else if (pass == NULL) {
1617 DEBUG(1, ("Server not using user level security and no "
1618 "password supplied.\n"));
1619 goto access_denied;
1622 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) &&
1623 *pass && passlen != 24) {
1624 if (!lp_client_lanman_auth()) {
1625 DEBUG(1, ("Server requested LANMAN password "
1626 "(share-level security) but "
1627 "'client lanman auth' is disabled\n"));
1628 goto access_denied;
1632 * Non-encrypted passwords - convert to DOS codepage before
1633 * encryption.
1635 passlen = 24;
1636 SMBencrypt(pass, cli->secblob.data, (uchar *)pword);
1637 } else {
1638 if((cli->sec_mode & (NEGOTIATE_SECURITY_USER_LEVEL
1639 |NEGOTIATE_SECURITY_CHALLENGE_RESPONSE))
1640 == 0) {
1641 if (!lp_client_plaintext_auth() && (*pass)) {
1642 DEBUG(1, ("Server requested plaintext "
1643 "password but 'client plaintext "
1644 "auth' is disabled\n"));
1645 goto access_denied;
1649 * Non-encrypted passwords - convert to DOS codepage
1650 * before using.
1652 passlen = clistr_push(cli, pword, pass, sizeof(pword),
1653 STR_TERMINATE);
1654 if (passlen == -1) {
1655 DEBUG(1, ("clistr_push(pword) failed\n"));
1656 goto access_denied;
1658 } else {
1659 if (passlen) {
1660 memcpy(pword, pass, passlen);
1665 SCVAL(vwv+0, 0, 0xFF);
1666 SCVAL(vwv+0, 1, 0);
1667 SSVAL(vwv+1, 0, 0);
1668 SSVAL(vwv+2, 0, TCONX_FLAG_EXTENDED_RESPONSE);
1669 SSVAL(vwv+3, 0, passlen);
1671 if (passlen) {
1672 bytes = (uint8_t *)talloc_memdup(state, pword, passlen);
1673 } else {
1674 bytes = talloc_array(state, uint8_t, 0);
1678 * Add the sharename
1680 tmp = talloc_asprintf_strupper_m(talloc_tos(), "\\\\%s\\%s",
1681 cli->desthost, share);
1682 if (tmp == NULL) {
1683 TALLOC_FREE(req);
1684 return NULL;
1686 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), tmp, strlen(tmp)+1,
1687 NULL);
1688 TALLOC_FREE(tmp);
1691 * Add the devicetype
1693 tmp = talloc_strdup_upper(talloc_tos(), dev);
1694 if (tmp == NULL) {
1695 TALLOC_FREE(req);
1696 return NULL;
1698 bytes = smb_bytes_push_str(bytes, false, tmp, strlen(tmp)+1, NULL);
1699 TALLOC_FREE(tmp);
1701 if (bytes == NULL) {
1702 TALLOC_FREE(req);
1703 return NULL;
1706 state->bytes.iov_base = (void *)bytes;
1707 state->bytes.iov_len = talloc_get_size(bytes);
1709 subreq = cli_smb_req_create(state, ev, cli, SMBtconX, 0, 4, vwv,
1710 1, &state->bytes);
1711 if (subreq == NULL) {
1712 TALLOC_FREE(req);
1713 return NULL;
1715 tevent_req_set_callback(subreq, cli_tcon_andx_done, req);
1716 *psmbreq = subreq;
1717 return req;
1719 access_denied:
1720 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1721 return tevent_req_post(req, ev);
1724 struct tevent_req *cli_tcon_andx_send(TALLOC_CTX *mem_ctx,
1725 struct event_context *ev,
1726 struct cli_state *cli,
1727 const char *share, const char *dev,
1728 const char *pass, int passlen)
1730 struct tevent_req *req, *subreq;
1731 NTSTATUS status;
1733 req = cli_tcon_andx_create(mem_ctx, ev, cli, share, dev, pass, passlen,
1734 &subreq);
1735 if (req == NULL) {
1736 return NULL;
1738 if (subreq == NULL) {
1739 return req;
1741 status = cli_smb_req_send(subreq);
1742 if (!NT_STATUS_IS_OK(status)) {
1743 tevent_req_nterror(req, status);
1744 return tevent_req_post(req, ev);
1746 return req;
1749 static void cli_tcon_andx_done(struct tevent_req *subreq)
1751 struct tevent_req *req = tevent_req_callback_data(
1752 subreq, struct tevent_req);
1753 struct cli_tcon_andx_state *state = tevent_req_data(
1754 req, struct cli_tcon_andx_state);
1755 struct cli_state *cli = state->cli;
1756 char *inbuf = (char *)cli_smb_inbuf(subreq);
1757 uint8_t wct;
1758 uint16_t *vwv;
1759 uint32_t num_bytes;
1760 uint8_t *bytes;
1761 NTSTATUS status;
1763 status = cli_smb_recv(subreq, NULL, NULL, 0, &wct, &vwv,
1764 &num_bytes, &bytes);
1765 if (!NT_STATUS_IS_OK(status)) {
1766 TALLOC_FREE(subreq);
1767 tevent_req_nterror(req, status);
1768 return;
1771 clistr_pull(inbuf, cli->dev, bytes, sizeof(fstring), num_bytes,
1772 STR_TERMINATE|STR_ASCII);
1774 if ((cli->protocol >= PROTOCOL_NT1) && (num_bytes == 3)) {
1775 /* almost certainly win95 - enable bug fixes */
1776 cli->win95 = True;
1780 * Make sure that we have the optional support 16-bit field. WCT > 2.
1781 * Avoids issues when connecting to Win9x boxes sharing files
1784 cli->dfsroot = false;
1786 if ((wct > 2) && (cli->protocol >= PROTOCOL_LANMAN2)) {
1787 cli->dfsroot = ((SVAL(vwv+2, 0) & SMB_SHARE_IN_DFS) != 0);
1790 cli->cnum = SVAL(inbuf,smb_tid);
1791 tevent_req_done(req);
1794 NTSTATUS cli_tcon_andx_recv(struct tevent_req *req)
1796 return tevent_req_simple_recv_ntstatus(req);
1799 NTSTATUS cli_tcon_andx(struct cli_state *cli, const char *share,
1800 const char *dev, const char *pass, int passlen)
1802 TALLOC_CTX *frame = talloc_stackframe();
1803 struct event_context *ev;
1804 struct tevent_req *req;
1805 NTSTATUS status = NT_STATUS_OK;
1807 if (cli_has_async_calls(cli)) {
1809 * Can't use sync call while an async call is in flight
1811 status = NT_STATUS_INVALID_PARAMETER;
1812 goto fail;
1815 ev = event_context_init(frame);
1816 if (ev == NULL) {
1817 status = NT_STATUS_NO_MEMORY;
1818 goto fail;
1821 req = cli_tcon_andx_send(frame, ev, cli, share, dev, pass, passlen);
1822 if (req == NULL) {
1823 status = NT_STATUS_NO_MEMORY;
1824 goto fail;
1827 if (!tevent_req_poll(req, ev)) {
1828 status = map_nt_error_from_unix(errno);
1829 goto fail;
1832 status = cli_tcon_andx_recv(req);
1833 fail:
1834 TALLOC_FREE(frame);
1835 if (!NT_STATUS_IS_OK(status)) {
1836 cli_set_error(cli, status);
1838 return status;
1841 /****************************************************************************
1842 Send a tree disconnect.
1843 ****************************************************************************/
1845 struct cli_tdis_state {
1846 struct cli_state *cli;
1849 static void cli_tdis_done(struct tevent_req *subreq);
1851 struct tevent_req *cli_tdis_send(TALLOC_CTX *mem_ctx,
1852 struct tevent_context *ev,
1853 struct cli_state *cli)
1855 struct tevent_req *req, *subreq;
1856 struct cli_tdis_state *state;
1858 req = tevent_req_create(mem_ctx, &state, struct cli_tdis_state);
1859 if (req == NULL) {
1860 return NULL;
1862 state->cli = cli;
1864 subreq = cli_smb_send(state, ev, cli, SMBtdis, 0, 0, NULL, 0, NULL);
1865 if (tevent_req_nomem(subreq, req)) {
1866 return tevent_req_post(req, ev);
1868 tevent_req_set_callback(subreq, cli_tdis_done, req);
1869 return req;
1872 static void cli_tdis_done(struct tevent_req *subreq)
1874 struct tevent_req *req = tevent_req_callback_data(
1875 subreq, struct tevent_req);
1876 struct cli_tdis_state *state = tevent_req_data(
1877 req, struct cli_tdis_state);
1878 NTSTATUS status;
1880 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1881 TALLOC_FREE(subreq);
1882 if (!NT_STATUS_IS_OK(status)) {
1883 tevent_req_nterror(req, status);
1884 return;
1886 state->cli->cnum = -1;
1887 tevent_req_done(req);
1890 NTSTATUS cli_tdis_recv(struct tevent_req *req)
1892 return tevent_req_simple_recv_ntstatus(req);
1895 NTSTATUS cli_tdis(struct cli_state *cli)
1897 struct tevent_context *ev;
1898 struct tevent_req *req;
1899 NTSTATUS status = NT_STATUS_NO_MEMORY;
1901 if (cli_has_async_calls(cli)) {
1902 return NT_STATUS_INVALID_PARAMETER;
1904 ev = tevent_context_init(talloc_tos());
1905 if (ev == NULL) {
1906 goto fail;
1908 req = cli_tdis_send(ev, ev, cli);
1909 if (req == NULL) {
1910 goto fail;
1912 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1913 goto fail;
1915 status = cli_tdis_recv(req);
1916 fail:
1917 TALLOC_FREE(ev);
1918 if (!NT_STATUS_IS_OK(status)) {
1919 cli_set_error(cli, status);
1921 return status;
1924 /****************************************************************************
1925 Send a negprot command.
1926 ****************************************************************************/
1928 void cli_negprot_sendsync(struct cli_state *cli)
1930 char *p;
1931 int numprots;
1933 if (cli->protocol < PROTOCOL_NT1)
1934 cli->use_spnego = False;
1936 memset(cli->outbuf,'\0',smb_size);
1938 /* setup the protocol strings */
1939 cli_set_message(cli->outbuf,0,0,True);
1941 p = smb_buf(cli->outbuf);
1942 for (numprots=0; numprots < ARRAY_SIZE(prots); numprots++) {
1943 if (prots[numprots].prot > cli->protocol) {
1944 break;
1946 *p++ = 2;
1947 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
1950 SCVAL(cli->outbuf,smb_com,SMBnegprot);
1951 cli_setup_bcc(cli, p);
1952 cli_setup_packet(cli);
1954 SCVAL(smb_buf(cli->outbuf),0,2);
1956 cli_send_smb(cli);
1959 /****************************************************************************
1960 Send a negprot command.
1961 ****************************************************************************/
1963 struct cli_negprot_state {
1964 struct cli_state *cli;
1967 static void cli_negprot_done(struct tevent_req *subreq);
1969 struct tevent_req *cli_negprot_send(TALLOC_CTX *mem_ctx,
1970 struct event_context *ev,
1971 struct cli_state *cli)
1973 struct tevent_req *req, *subreq;
1974 struct cli_negprot_state *state;
1975 uint8_t *bytes = NULL;
1976 int numprots;
1977 uint16_t cnum;
1979 req = tevent_req_create(mem_ctx, &state, struct cli_negprot_state);
1980 if (req == NULL) {
1981 return NULL;
1983 state->cli = cli;
1985 if (cli->protocol < PROTOCOL_NT1)
1986 cli->use_spnego = False;
1988 /* setup the protocol strings */
1989 for (numprots=0; numprots < ARRAY_SIZE(prots); numprots++) {
1990 uint8_t c = 2;
1991 if (prots[numprots].prot > cli->protocol) {
1992 break;
1994 bytes = (uint8_t *)talloc_append_blob(
1995 state, bytes, data_blob_const(&c, sizeof(c)));
1996 if (tevent_req_nomem(bytes, req)) {
1997 return tevent_req_post(req, ev);
1999 bytes = smb_bytes_push_str(bytes, false,
2000 prots[numprots].name,
2001 strlen(prots[numprots].name)+1,
2002 NULL);
2003 if (tevent_req_nomem(bytes, req)) {
2004 return tevent_req_post(req, ev);
2008 cnum = cli->cnum;
2010 cli->cnum = 0;
2011 subreq = cli_smb_send(state, ev, cli, SMBnegprot, 0, 0, NULL,
2012 talloc_get_size(bytes), bytes);
2013 cli->cnum = cnum;
2015 if (tevent_req_nomem(subreq, req)) {
2016 return tevent_req_post(req, ev);
2018 tevent_req_set_callback(subreq, cli_negprot_done, req);
2019 return req;
2022 static void cli_negprot_done(struct tevent_req *subreq)
2024 struct tevent_req *req = tevent_req_callback_data(
2025 subreq, struct tevent_req);
2026 struct cli_negprot_state *state = tevent_req_data(
2027 req, struct cli_negprot_state);
2028 struct cli_state *cli = state->cli;
2029 uint8_t wct;
2030 uint16_t *vwv;
2031 uint32_t num_bytes;
2032 uint8_t *bytes;
2033 NTSTATUS status;
2034 uint16_t protnum;
2036 status = cli_smb_recv(subreq, NULL, NULL, 1, &wct, &vwv,
2037 &num_bytes, &bytes);
2038 if (!NT_STATUS_IS_OK(status)) {
2039 TALLOC_FREE(subreq);
2040 tevent_req_nterror(req, status);
2041 return;
2044 protnum = SVAL(vwv, 0);
2046 if ((protnum >= ARRAY_SIZE(prots))
2047 || (prots[protnum].prot > cli->protocol)) {
2048 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2049 return;
2052 cli->protocol = prots[protnum].prot;
2054 if ((cli->protocol < PROTOCOL_NT1) &&
2055 client_is_signing_mandatory(cli)) {
2056 DEBUG(0,("cli_negprot: SMB signing is mandatory and the selected protocol level doesn't support it.\n"));
2057 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
2058 return;
2061 if (cli->protocol >= PROTOCOL_NT1) {
2062 struct timespec ts;
2063 bool negotiated_smb_signing = false;
2065 /* NT protocol */
2066 cli->sec_mode = CVAL(vwv + 1, 0);
2067 cli->max_mux = SVAL(vwv + 1, 1);
2068 cli->max_xmit = IVAL(vwv + 3, 1);
2069 cli->sesskey = IVAL(vwv + 7, 1);
2070 cli->serverzone = SVALS(vwv + 15, 1);
2071 cli->serverzone *= 60;
2072 /* this time arrives in real GMT */
2073 ts = interpret_long_date(((char *)(vwv+11))+1);
2074 cli->servertime = ts.tv_sec;
2075 cli->secblob = data_blob(bytes, num_bytes);
2076 cli->capabilities = IVAL(vwv + 9, 1);
2077 if (cli->capabilities & CAP_RAW_MODE) {
2078 cli->readbraw_supported = True;
2079 cli->writebraw_supported = True;
2081 /* work out if they sent us a workgroup */
2082 if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
2083 smb_buflen(cli->inbuf) > 8) {
2084 clistr_pull(cli->inbuf, cli->server_domain,
2085 bytes+8, sizeof(cli->server_domain),
2086 num_bytes-8,
2087 STR_UNICODE|STR_NOALIGN);
2091 * As signing is slow we only turn it on if either the client or
2092 * the server require it. JRA.
2095 if (cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED) {
2096 /* Fail if server says signing is mandatory and we don't want to support it. */
2097 if (!client_is_signing_allowed(cli)) {
2098 DEBUG(0,("cli_negprot: SMB signing is mandatory and we have disabled it.\n"));
2099 tevent_req_nterror(req,
2100 NT_STATUS_ACCESS_DENIED);
2101 return;
2103 negotiated_smb_signing = true;
2104 } else if (client_is_signing_mandatory(cli) && client_is_signing_allowed(cli)) {
2105 /* Fail if client says signing is mandatory and the server doesn't support it. */
2106 if (!(cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED)) {
2107 DEBUG(1,("cli_negprot: SMB signing is mandatory and the server doesn't support it.\n"));
2108 tevent_req_nterror(req,
2109 NT_STATUS_ACCESS_DENIED);
2110 return;
2112 negotiated_smb_signing = true;
2113 } else if (cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) {
2114 negotiated_smb_signing = true;
2117 if (negotiated_smb_signing) {
2118 cli_set_signing_negotiated(cli);
2121 if (cli->capabilities & (CAP_LARGE_READX|CAP_LARGE_WRITEX)) {
2122 SAFE_FREE(cli->outbuf);
2123 SAFE_FREE(cli->inbuf);
2124 cli->outbuf = (char *)SMB_MALLOC(CLI_SAMBA_MAX_LARGE_READX_SIZE+LARGE_WRITEX_HDR_SIZE+SAFETY_MARGIN);
2125 cli->inbuf = (char *)SMB_MALLOC(CLI_SAMBA_MAX_LARGE_READX_SIZE+LARGE_WRITEX_HDR_SIZE+SAFETY_MARGIN);
2126 cli->bufsize = CLI_SAMBA_MAX_LARGE_READX_SIZE + LARGE_WRITEX_HDR_SIZE;
2129 } else if (cli->protocol >= PROTOCOL_LANMAN1) {
2130 cli->use_spnego = False;
2131 cli->sec_mode = SVAL(vwv + 1, 0);
2132 cli->max_xmit = SVAL(vwv + 2, 0);
2133 cli->max_mux = SVAL(vwv + 3, 0);
2134 cli->sesskey = IVAL(vwv + 6, 0);
2135 cli->serverzone = SVALS(vwv + 10, 0);
2136 cli->serverzone *= 60;
2137 /* this time is converted to GMT by make_unix_date */
2138 cli->servertime = cli_make_unix_date(
2139 cli, (char *)(vwv + 8));
2140 cli->readbraw_supported = ((SVAL(vwv + 5, 0) & 0x1) != 0);
2141 cli->writebraw_supported = ((SVAL(vwv + 5, 0) & 0x2) != 0);
2142 cli->secblob = data_blob(bytes, num_bytes);
2143 } else {
2144 /* the old core protocol */
2145 cli->use_spnego = False;
2146 cli->sec_mode = 0;
2147 cli->serverzone = get_time_zone(time(NULL));
2150 cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
2152 /* a way to force ascii SMB */
2153 if (getenv("CLI_FORCE_ASCII"))
2154 cli->capabilities &= ~CAP_UNICODE;
2156 tevent_req_done(req);
2159 NTSTATUS cli_negprot_recv(struct tevent_req *req)
2161 return tevent_req_simple_recv_ntstatus(req);
2164 NTSTATUS cli_negprot(struct cli_state *cli)
2166 TALLOC_CTX *frame = talloc_stackframe();
2167 struct event_context *ev;
2168 struct tevent_req *req;
2169 NTSTATUS status = NT_STATUS_OK;
2171 if (cli_has_async_calls(cli)) {
2173 * Can't use sync call while an async call is in flight
2175 status = NT_STATUS_INVALID_PARAMETER;
2176 goto fail;
2179 ev = event_context_init(frame);
2180 if (ev == NULL) {
2181 status = NT_STATUS_NO_MEMORY;
2182 goto fail;
2185 req = cli_negprot_send(frame, ev, cli);
2186 if (req == NULL) {
2187 status = NT_STATUS_NO_MEMORY;
2188 goto fail;
2191 if (!tevent_req_poll(req, ev)) {
2192 status = map_nt_error_from_unix(errno);
2193 goto fail;
2196 status = cli_negprot_recv(req);
2197 fail:
2198 TALLOC_FREE(frame);
2199 if (!NT_STATUS_IS_OK(status)) {
2200 cli_set_error(cli, status);
2202 return status;
2205 /****************************************************************************
2206 Send a session request. See rfc1002.txt 4.3 and 4.3.2.
2207 ****************************************************************************/
2209 bool cli_session_request(struct cli_state *cli,
2210 struct nmb_name *calling, struct nmb_name *called)
2212 char *p;
2213 int len = 4;
2214 char *tmp;
2216 /* 445 doesn't have session request */
2217 if (cli->port == 445)
2218 return True;
2220 memcpy(&(cli->calling), calling, sizeof(*calling));
2221 memcpy(&(cli->called ), called , sizeof(*called ));
2223 /* put in the destination name */
2225 tmp = name_mangle(talloc_tos(), cli->called.name,
2226 cli->called.name_type);
2227 if (tmp == NULL) {
2228 return false;
2231 p = cli->outbuf+len;
2232 memcpy(p, tmp, name_len(tmp));
2233 len += name_len(tmp);
2234 TALLOC_FREE(tmp);
2236 /* and my name */
2238 tmp = name_mangle(talloc_tos(), cli->calling.name,
2239 cli->calling.name_type);
2240 if (tmp == NULL) {
2241 return false;
2244 p = cli->outbuf+len;
2245 memcpy(p, tmp, name_len(tmp));
2246 len += name_len(tmp);
2247 TALLOC_FREE(tmp);
2249 /* send a session request (RFC 1002) */
2250 /* setup the packet length
2251 * Remove four bytes from the length count, since the length
2252 * field in the NBT Session Service header counts the number
2253 * of bytes which follow. The cli_send_smb() function knows
2254 * about this and accounts for those four bytes.
2255 * CRH.
2257 len -= 4;
2258 _smb_setlen(cli->outbuf,len);
2259 SCVAL(cli->outbuf,0,0x81);
2261 cli_send_smb(cli);
2262 DEBUG(5,("Sent session request\n"));
2264 if (!cli_receive_smb(cli))
2265 return False;
2267 if (CVAL(cli->inbuf,0) == 0x84) {
2268 /* C. Hoch 9/14/95 Start */
2269 /* For information, here is the response structure.
2270 * We do the byte-twiddling to for portability.
2271 struct RetargetResponse{
2272 unsigned char type;
2273 unsigned char flags;
2274 int16 length;
2275 int32 ip_addr;
2276 int16 port;
2279 uint16_t port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
2280 struct in_addr dest_ip;
2281 NTSTATUS status;
2283 /* SESSION RETARGET */
2284 putip((char *)&dest_ip,cli->inbuf+4);
2285 in_addr_to_sockaddr_storage(&cli->dest_ss, dest_ip);
2287 status = open_socket_out(&cli->dest_ss, port,
2288 LONG_CONNECT_TIMEOUT, &cli->fd);
2289 if (!NT_STATUS_IS_OK(status)) {
2290 return False;
2293 DEBUG(3,("Retargeted\n"));
2295 set_socket_options(cli->fd, lp_socket_options());
2297 /* Try again */
2299 static int depth;
2300 bool ret;
2301 if (depth > 4) {
2302 DEBUG(0,("Retarget recursion - failing\n"));
2303 return False;
2305 depth++;
2306 ret = cli_session_request(cli, calling, called);
2307 depth--;
2308 return ret;
2310 } /* C. Hoch 9/14/95 End */
2312 if (CVAL(cli->inbuf,0) != 0x82) {
2313 /* This is the wrong place to put the error... JRA. */
2314 cli->rap_error = CVAL(cli->inbuf,4);
2315 return False;
2317 return(True);
2320 struct fd_struct {
2321 int fd;
2324 static void smb_sock_connected(struct tevent_req *req)
2326 struct fd_struct *pfd = tevent_req_callback_data(
2327 req, struct fd_struct);
2328 int fd;
2329 NTSTATUS status;
2331 status = open_socket_out_defer_recv(req, &fd);
2332 if (NT_STATUS_IS_OK(status)) {
2333 pfd->fd = fd;
2337 static NTSTATUS open_smb_socket(const struct sockaddr_storage *pss,
2338 uint16_t *port, int timeout, int *pfd)
2340 struct event_context *ev;
2341 struct tevent_req *r139, *r445;
2342 struct fd_struct *fd139, *fd445;
2343 NTSTATUS status = NT_STATUS_NO_MEMORY;
2345 if (*port != 0) {
2346 return open_socket_out(pss, *port, timeout, pfd);
2349 ev = event_context_init(talloc_tos());
2350 if (ev == NULL) {
2351 return NT_STATUS_NO_MEMORY;
2354 fd139 = talloc(ev, struct fd_struct);
2355 if (fd139 == NULL) {
2356 goto done;
2358 fd139->fd = -1;
2360 fd445 = talloc(ev, struct fd_struct);
2361 if (fd445 == NULL) {
2362 goto done;
2364 fd445->fd = -1;
2366 r445 = open_socket_out_defer_send(ev, ev, timeval_set(0, 0),
2367 pss, 445, timeout);
2368 r139 = open_socket_out_defer_send(ev, ev, timeval_set(0, 3000),
2369 pss, 139, timeout);
2370 if ((r445 == NULL) || (r139 == NULL)) {
2371 goto done;
2373 tevent_req_set_callback(r445, smb_sock_connected, fd445);
2374 tevent_req_set_callback(r139, smb_sock_connected, fd139);
2376 while ((fd445->fd == -1) && (fd139->fd == -1)
2377 && (tevent_req_is_in_progress(r139)
2378 || tevent_req_is_in_progress(r445))) {
2379 event_loop_once(ev);
2382 if ((fd139->fd != -1) && (fd445->fd != -1)) {
2383 close(fd139->fd);
2384 fd139->fd = -1;
2387 if (fd445->fd != -1) {
2388 *port = 445;
2389 *pfd = fd445->fd;
2390 status = NT_STATUS_OK;
2391 goto done;
2393 if (fd139->fd != -1) {
2394 *port = 139;
2395 *pfd = fd139->fd;
2396 status = NT_STATUS_OK;
2397 goto done;
2400 status = open_socket_out_defer_recv(r445, &fd445->fd);
2401 done:
2402 TALLOC_FREE(ev);
2403 return status;
2406 /****************************************************************************
2407 Open the client sockets.
2408 ****************************************************************************/
2410 NTSTATUS cli_connect(struct cli_state *cli,
2411 const char *host,
2412 struct sockaddr_storage *dest_ss)
2415 int name_type = 0x20;
2416 TALLOC_CTX *frame = talloc_stackframe();
2417 unsigned int num_addrs = 0;
2418 unsigned int i = 0;
2419 struct sockaddr_storage *ss_arr = NULL;
2420 char *p = NULL;
2422 /* reasonable default hostname */
2423 if (!host) {
2424 host = STAR_SMBSERVER;
2427 fstrcpy(cli->desthost, host);
2429 /* allow hostnames of the form NAME#xx and do a netbios lookup */
2430 if ((p = strchr(cli->desthost, '#'))) {
2431 name_type = strtol(p+1, NULL, 16);
2432 *p = 0;
2435 if (!dest_ss || is_zero_addr((struct sockaddr *)dest_ss)) {
2436 NTSTATUS status =resolve_name_list(frame,
2437 cli->desthost,
2438 name_type,
2439 &ss_arr,
2440 &num_addrs);
2441 if (!NT_STATUS_IS_OK(status)) {
2442 TALLOC_FREE(frame);
2443 return NT_STATUS_BAD_NETWORK_NAME;
2445 } else {
2446 num_addrs = 1;
2447 ss_arr = TALLOC_P(frame, struct sockaddr_storage);
2448 if (!ss_arr) {
2449 TALLOC_FREE(frame);
2450 return NT_STATUS_NO_MEMORY;
2452 *ss_arr = *dest_ss;
2455 for (i = 0; i < num_addrs; i++) {
2456 cli->dest_ss = ss_arr[i];
2457 if (getenv("LIBSMB_PROG")) {
2458 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
2459 } else {
2460 uint16_t port = cli->port;
2461 NTSTATUS status;
2462 status = open_smb_socket(&cli->dest_ss, &port,
2463 cli->timeout, &cli->fd);
2464 if (NT_STATUS_IS_OK(status)) {
2465 cli->port = port;
2468 if (cli->fd == -1) {
2469 char addr[INET6_ADDRSTRLEN];
2470 print_sockaddr(addr, sizeof(addr), &ss_arr[i]);
2471 DEBUG(2,("Error connecting to %s (%s)\n",
2472 dest_ss?addr:host,strerror(errno)));
2473 } else {
2474 /* Exit from loop on first connection. */
2475 break;
2479 if (cli->fd == -1) {
2480 TALLOC_FREE(frame);
2481 return map_nt_error_from_unix(errno);
2484 if (dest_ss) {
2485 *dest_ss = cli->dest_ss;
2488 set_socket_options(cli->fd, lp_socket_options());
2490 TALLOC_FREE(frame);
2491 return NT_STATUS_OK;
2495 establishes a connection to after the negprot.
2496 @param output_cli A fully initialised cli structure, non-null only on success
2497 @param dest_host The netbios name of the remote host
2498 @param dest_ss (optional) The the destination IP, NULL for name based lookup
2499 @param port (optional) The destination port (0 for default)
2500 @param retry bool. Did this connection fail with a retryable error ?
2503 NTSTATUS cli_start_connection(struct cli_state **output_cli,
2504 const char *my_name,
2505 const char *dest_host,
2506 struct sockaddr_storage *dest_ss, int port,
2507 int signing_state, int flags,
2508 bool *retry)
2510 NTSTATUS nt_status;
2511 struct nmb_name calling;
2512 struct nmb_name called;
2513 struct cli_state *cli;
2514 struct sockaddr_storage ss;
2516 if (retry)
2517 *retry = False;
2519 if (!my_name)
2520 my_name = global_myname();
2522 if (!(cli = cli_initialise_ex(signing_state))) {
2523 return NT_STATUS_NO_MEMORY;
2526 make_nmb_name(&calling, my_name, 0x0);
2527 make_nmb_name(&called , dest_host, 0x20);
2529 cli_set_port(cli, port);
2530 cli_set_timeout(cli, 10000); /* 10 seconds. */
2532 if (dest_ss) {
2533 ss = *dest_ss;
2534 } else {
2535 zero_sockaddr(&ss);
2538 again:
2540 DEBUG(3,("Connecting to host=%s\n", dest_host));
2542 nt_status = cli_connect(cli, dest_host, &ss);
2543 if (!NT_STATUS_IS_OK(nt_status)) {
2544 char addr[INET6_ADDRSTRLEN];
2545 print_sockaddr(addr, sizeof(addr), &ss);
2546 DEBUG(1,("cli_start_connection: failed to connect to %s (%s). Error %s\n",
2547 nmb_namestr(&called), addr, nt_errstr(nt_status) ));
2548 cli_shutdown(cli);
2549 return nt_status;
2552 if (retry)
2553 *retry = True;
2555 if (!cli_session_request(cli, &calling, &called)) {
2556 char *p;
2557 DEBUG(1,("session request to %s failed (%s)\n",
2558 called.name, cli_errstr(cli)));
2559 if ((p=strchr(called.name, '.')) && !is_ipaddress(called.name)) {
2560 *p = 0;
2561 goto again;
2563 if (strcmp(called.name, STAR_SMBSERVER)) {
2564 make_nmb_name(&called , STAR_SMBSERVER, 0x20);
2565 goto again;
2567 return NT_STATUS_BAD_NETWORK_NAME;
2570 if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO)
2571 cli->use_spnego = False;
2572 else if (flags & CLI_FULL_CONNECTION_USE_KERBEROS)
2573 cli->use_kerberos = True;
2575 if ((flags & CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS) &&
2576 cli->use_kerberos) {
2577 cli->fallback_after_kerberos = true;
2579 if (flags & CLI_FULL_CONNECTION_USE_CCACHE) {
2580 cli->use_ccache = true;
2583 nt_status = cli_negprot(cli);
2584 if (!NT_STATUS_IS_OK(nt_status)) {
2585 DEBUG(1, ("failed negprot: %s\n", nt_errstr(nt_status)));
2586 cli_shutdown(cli);
2587 return nt_status;
2590 *output_cli = cli;
2591 return NT_STATUS_OK;
2596 establishes a connection right up to doing tconX, password specified.
2597 @param output_cli A fully initialised cli structure, non-null only on success
2598 @param dest_host The netbios name of the remote host
2599 @param dest_ip (optional) The the destination IP, NULL for name based lookup
2600 @param port (optional) The destination port (0 for default)
2601 @param service (optional) The share to make the connection to. Should be 'unqualified' in any way.
2602 @param service_type The 'type' of serivice.
2603 @param user Username, unix string
2604 @param domain User's domain
2605 @param password User's password, unencrypted unix string.
2606 @param retry bool. Did this connection fail with a retryable error ?
2609 NTSTATUS cli_full_connection(struct cli_state **output_cli,
2610 const char *my_name,
2611 const char *dest_host,
2612 struct sockaddr_storage *dest_ss, int port,
2613 const char *service, const char *service_type,
2614 const char *user, const char *domain,
2615 const char *password, int flags,
2616 int signing_state,
2617 bool *retry)
2619 NTSTATUS nt_status;
2620 struct cli_state *cli = NULL;
2621 int pw_len = password ? strlen(password)+1 : 0;
2623 *output_cli = NULL;
2625 if (password == NULL) {
2626 password = "";
2629 nt_status = cli_start_connection(&cli, my_name, dest_host,
2630 dest_ss, port, signing_state,
2631 flags, retry);
2633 if (!NT_STATUS_IS_OK(nt_status)) {
2634 return nt_status;
2637 cli->use_oplocks = ((flags & CLI_FULL_CONNECTION_OPLOCKS) != 0);
2638 cli->use_level_II_oplocks =
2639 ((flags & CLI_FULL_CONNECTION_LEVEL_II_OPLOCKS) != 0);
2641 nt_status = cli_session_setup(cli, user, password, pw_len, password,
2642 pw_len, domain);
2643 if (!NT_STATUS_IS_OK(nt_status)) {
2645 if (!(flags & CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK)) {
2646 DEBUG(1,("failed session setup with %s\n",
2647 nt_errstr(nt_status)));
2648 cli_shutdown(cli);
2649 return nt_status;
2652 nt_status = cli_session_setup(cli, "", "", 0, "", 0, domain);
2653 if (!NT_STATUS_IS_OK(nt_status)) {
2654 DEBUG(1,("anonymous failed session setup with %s\n",
2655 nt_errstr(nt_status)));
2656 cli_shutdown(cli);
2657 return nt_status;
2661 if (service) {
2662 nt_status = cli_tcon_andx(cli, service, service_type, password,
2663 pw_len);
2664 if (!NT_STATUS_IS_OK(nt_status)) {
2665 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(nt_status)));
2666 cli_shutdown(cli);
2667 if (NT_STATUS_IS_OK(nt_status)) {
2668 nt_status = NT_STATUS_UNSUCCESSFUL;
2670 return nt_status;
2674 nt_status = cli_init_creds(cli, user, domain, password);
2675 if (!NT_STATUS_IS_OK(nt_status)) {
2676 cli_shutdown(cli);
2677 return nt_status;
2680 *output_cli = cli;
2681 return NT_STATUS_OK;
2684 /****************************************************************************
2685 Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
2686 ****************************************************************************/
2688 bool attempt_netbios_session_request(struct cli_state **ppcli, const char *srchost, const char *desthost,
2689 struct sockaddr_storage *pdest_ss)
2691 struct nmb_name calling, called;
2693 make_nmb_name(&calling, srchost, 0x0);
2696 * If the called name is an IP address
2697 * then use *SMBSERVER immediately.
2700 if(is_ipaddress(desthost)) {
2701 make_nmb_name(&called, STAR_SMBSERVER, 0x20);
2702 } else {
2703 make_nmb_name(&called, desthost, 0x20);
2706 if (!cli_session_request(*ppcli, &calling, &called)) {
2707 NTSTATUS status;
2708 struct nmb_name smbservername;
2710 make_nmb_name(&smbservername, STAR_SMBSERVER, 0x20);
2713 * If the name wasn't *SMBSERVER then
2714 * try with *SMBSERVER if the first name fails.
2717 if (nmb_name_equal(&called, &smbservername)) {
2720 * The name used was *SMBSERVER, don't bother with another name.
2723 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
2724 with error %s.\n", desthost, cli_errstr(*ppcli) ));
2725 return False;
2728 /* Try again... */
2729 cli_shutdown(*ppcli);
2731 *ppcli = cli_initialise();
2732 if (!*ppcli) {
2733 /* Out of memory... */
2734 return False;
2737 status = cli_connect(*ppcli, desthost, pdest_ss);
2738 if (!NT_STATUS_IS_OK(status) ||
2739 !cli_session_request(*ppcli, &calling, &smbservername)) {
2740 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
2741 name *SMBSERVER with error %s\n", desthost, cli_errstr(*ppcli) ));
2742 return False;
2746 return True;
2749 /****************************************************************************
2750 Send an old style tcon.
2751 ****************************************************************************/
2752 NTSTATUS cli_raw_tcon(struct cli_state *cli,
2753 const char *service, const char *pass, const char *dev,
2754 uint16 *max_xmit, uint16 *tid)
2756 char *p;
2758 if (!lp_client_plaintext_auth() && (*pass)) {
2759 DEBUG(1, ("Server requested plaintext password but 'client "
2760 "plaintext auth' is disabled\n"));
2761 return NT_STATUS_ACCESS_DENIED;
2764 memset(cli->outbuf,'\0',smb_size);
2765 memset(cli->inbuf,'\0',smb_size);
2767 cli_set_message(cli->outbuf, 0, 0, True);
2768 SCVAL(cli->outbuf,smb_com,SMBtcon);
2769 cli_setup_packet(cli);
2771 p = smb_buf(cli->outbuf);
2772 *p++ = 4; p += clistr_push(cli, p, service, -1, STR_TERMINATE | STR_NOALIGN);
2773 *p++ = 4; p += clistr_push(cli, p, pass, -1, STR_TERMINATE | STR_NOALIGN);
2774 *p++ = 4; p += clistr_push(cli, p, dev, -1, STR_TERMINATE | STR_NOALIGN);
2776 cli_setup_bcc(cli, p);
2778 cli_send_smb(cli);
2779 if (!cli_receive_smb(cli)) {
2780 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
2783 if (cli_is_error(cli)) {
2784 return cli_nt_error(cli);
2787 *max_xmit = SVAL(cli->inbuf, smb_vwv0);
2788 *tid = SVAL(cli->inbuf, smb_vwv1);
2790 return NT_STATUS_OK;
2793 /* Return a cli_state pointing at the IPC$ share for the given server */
2795 struct cli_state *get_ipc_connect(char *server,
2796 struct sockaddr_storage *server_ss,
2797 const struct user_auth_info *user_info)
2799 struct cli_state *cli;
2800 NTSTATUS nt_status;
2801 uint32_t flags = CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK;
2803 if (user_info->use_kerberos) {
2804 flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
2807 nt_status = cli_full_connection(&cli, NULL, server, server_ss, 0, "IPC$", "IPC",
2808 user_info->username ? user_info->username : "",
2809 lp_workgroup(),
2810 user_info->password ? user_info->password : "",
2811 flags,
2812 Undefined, NULL);
2814 if (NT_STATUS_IS_OK(nt_status)) {
2815 return cli;
2816 } else if (is_ipaddress(server)) {
2817 /* windows 9* needs a correct NMB name for connections */
2818 fstring remote_name;
2820 if (name_status_find("*", 0, 0, server_ss, remote_name)) {
2821 cli = get_ipc_connect(remote_name, server_ss, user_info);
2822 if (cli)
2823 return cli;
2826 return NULL;
2830 * Given the IP address of a master browser on the network, return its
2831 * workgroup and connect to it.
2833 * This function is provided to allow additional processing beyond what
2834 * get_ipc_connect_master_ip_bcast() does, e.g. to retrieve the list of master
2835 * browsers and obtain each master browsers' list of domains (in case the
2836 * first master browser is recently on the network and has not yet
2837 * synchronized with other master browsers and therefore does not yet have the
2838 * entire network browse list)
2841 struct cli_state *get_ipc_connect_master_ip(TALLOC_CTX *ctx,
2842 struct ip_service *mb_ip,
2843 const struct user_auth_info *user_info,
2844 char **pp_workgroup_out)
2846 char addr[INET6_ADDRSTRLEN];
2847 fstring name;
2848 struct cli_state *cli;
2849 struct sockaddr_storage server_ss;
2851 *pp_workgroup_out = NULL;
2853 print_sockaddr(addr, sizeof(addr), &mb_ip->ss);
2854 DEBUG(99, ("Looking up name of master browser %s\n",
2855 addr));
2858 * Do a name status query to find out the name of the master browser.
2859 * We use <01><02>__MSBROWSE__<02>#01 if *#00 fails because a domain
2860 * master browser will not respond to a wildcard query (or, at least,
2861 * an NT4 server acting as the domain master browser will not).
2863 * We might be able to use ONLY the query on MSBROWSE, but that's not
2864 * yet been tested with all Windows versions, so until it is, leave
2865 * the original wildcard query as the first choice and fall back to
2866 * MSBROWSE if the wildcard query fails.
2868 if (!name_status_find("*", 0, 0x1d, &mb_ip->ss, name) &&
2869 !name_status_find(MSBROWSE, 1, 0x1d, &mb_ip->ss, name)) {
2871 DEBUG(99, ("Could not retrieve name status for %s\n",
2872 addr));
2873 return NULL;
2876 if (!find_master_ip(name, &server_ss)) {
2877 DEBUG(99, ("Could not find master ip for %s\n", name));
2878 return NULL;
2881 *pp_workgroup_out = talloc_strdup(ctx, name);
2883 DEBUG(4, ("found master browser %s, %s\n", name, addr));
2885 print_sockaddr(addr, sizeof(addr), &server_ss);
2886 cli = get_ipc_connect(addr, &server_ss, user_info);
2888 return cli;
2892 * Return the IP address and workgroup of a master browser on the network, and
2893 * connect to it.
2896 struct cli_state *get_ipc_connect_master_ip_bcast(TALLOC_CTX *ctx,
2897 const struct user_auth_info *user_info,
2898 char **pp_workgroup_out)
2900 struct ip_service *ip_list;
2901 struct cli_state *cli;
2902 int i, count;
2904 *pp_workgroup_out = NULL;
2906 DEBUG(99, ("Do broadcast lookup for workgroups on local network\n"));
2908 /* Go looking for workgroups by broadcasting on the local network */
2910 if (!NT_STATUS_IS_OK(name_resolve_bcast(MSBROWSE, 1, &ip_list,
2911 &count))) {
2912 DEBUG(99, ("No master browsers responded\n"));
2913 return False;
2916 for (i = 0; i < count; i++) {
2917 char addr[INET6_ADDRSTRLEN];
2918 print_sockaddr(addr, sizeof(addr), &ip_list[i].ss);
2919 DEBUG(99, ("Found master browser %s\n", addr));
2921 cli = get_ipc_connect_master_ip(ctx, &ip_list[i],
2922 user_info, pp_workgroup_out);
2923 if (cli)
2924 return(cli);
2927 return NULL;