client connect/disconnect routines
Copyright (C) Andrew Tridgell 1994-1998
Copyright (C) Andrew Bartlett 2001-2003
-
+ Copyright (C) Volker Lendecke 2011
+ Copyright (C) Jeremy Allison 2011
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
+#include "libsmb/libsmb.h"
+#include "popt_common.h"
#include "../libcli/auth/libcli_auth.h"
#include "../libcli/auth/spnego.h"
#include "smb_krb5.h"
+#include "../libcli/auth/ntlmssp.h"
+#include "libads/kerberos_proto.h"
+#include "krb5_env.h"
+#include "../lib/util/tevent_ntstatus.h"
+#include "async_smb.h"
+#include "libsmb/nmblib.h"
+#include "read_smb.h"
static const struct {
int prot;
#define STAR_SMBSERVER "*SMBSERVER"
+/********************************************************
+ Utility function to ensure we always return at least
+ a valid char * pointer to an empty string for the
+ cli->server_os, cli->server_type and cli->server_domain
+ strings.
+*******************************************************/
+
+static NTSTATUS smb_bytes_talloc_string(struct cli_state *cli,
+ char *inbuf,
+ char **dest,
+ uint8_t *src,
+ size_t srclen,
+ ssize_t *destlen)
+{
+ *destlen = clistr_pull_talloc(cli,
+ inbuf,
+ SVAL(inbuf, smb_flg2),
+ dest,
+ (char *)src,
+ srclen,
+ STR_TERMINATE);
+ if (*destlen == -1) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (*dest == NULL) {
+ *dest = talloc_strdup(cli, "");
+ if (*dest == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+ return NT_STATUS_OK;
+}
+
/**
* Set the user session key for a connection
* @param cli The cli structure to add it too
Do an old lanman2 style session setup.
****************************************************************************/
-static NTSTATUS cli_session_setup_lanman2(struct cli_state *cli,
- const char *user,
- const char *pass, size_t passlen,
- const char *workgroup)
+struct cli_session_setup_lanman2_state {
+ struct cli_state *cli;
+ uint16_t vwv[10];
+ const char *user;
+};
+
+static void cli_session_setup_lanman2_done(struct tevent_req *subreq);
+
+static struct tevent_req *cli_session_setup_lanman2_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ struct cli_state *cli, const char *user,
+ const char *pass, size_t passlen,
+ const char *workgroup)
{
- DATA_BLOB session_key = data_blob_null;
+ struct tevent_req *req, *subreq;
+ struct cli_session_setup_lanman2_state *state;
DATA_BLOB lm_response = data_blob_null;
- NTSTATUS status;
- fstring pword;
- char *p;
+ uint16_t *vwv;
+ uint8_t *bytes;
+ char *tmp;
- if (passlen > sizeof(pword)-1) {
- return NT_STATUS_INVALID_PARAMETER;
+ req = tevent_req_create(mem_ctx, &state,
+ struct cli_session_setup_lanman2_state);
+ if (req == NULL) {
+ return NULL;
}
+ state->cli = cli;
+ state->user = user;
+ vwv = state->vwv;
- /* LANMAN servers predate NT status codes and Unicode and ignore those
- smb flags so we must disable the corresponding default capabilities
- that would otherwise cause the Unicode and NT Status flags to be
- set (and even returned by the server) */
+ /*
+ * LANMAN servers predate NT status codes and Unicode and
+ * ignore those smb flags so we must disable the corresponding
+ * default capabilities that would otherwise cause the Unicode
+ * and NT Status flags to be set (and even returned by the
+ * server)
+ */
cli->capabilities &= ~(CAP_UNICODE | CAP_STATUS32);
- /* if in share level security then don't send a password now */
- if (!(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL))
+ /*
+ * if in share level security then don't send a password now
+ */
+ if (!(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL)) {
passlen = 0;
+ }
- if (passlen > 0 && (cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen != 24) {
- /* Encrypted mode needed, and non encrypted password supplied. */
+ if (passlen > 0
+ && (cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)
+ && passlen != 24) {
+ /*
+ * Encrypted mode needed, and non encrypted password
+ * supplied.
+ */
lm_response = data_blob(NULL, 24);
- if (!SMBencrypt(pass, cli->secblob.data,(uchar *)lm_response.data)) {
- DEBUG(1, ("Password is > 14 chars in length, and is therefore incompatible with Lanman authentication\n"));
- return NT_STATUS_ACCESS_DENIED;
+ if (tevent_req_nomem(lm_response.data, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ if (!SMBencrypt(pass, cli->secblob.data,
+ (uint8_t *)lm_response.data)) {
+ DEBUG(1, ("Password is > 14 chars in length, and is "
+ "therefore incompatible with Lanman "
+ "authentication\n"));
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return tevent_req_post(req, ev);
}
- } else if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen == 24) {
- /* Encrypted mode needed, and encrypted password supplied. */
+ } else if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)
+ && passlen == 24) {
+ /*
+ * Encrypted mode needed, and encrypted password
+ * supplied.
+ */
lm_response = data_blob(pass, passlen);
+ if (tevent_req_nomem(lm_response.data, req)) {
+ return tevent_req_post(req, ev);
+ }
} else if (passlen > 0) {
- /* Plaintext mode needed, assume plaintext supplied. */
- passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
+ uint8_t *buf;
+ size_t converted_size;
+ /*
+ * Plaintext mode needed, assume plaintext supplied.
+ */
+ buf = talloc_array(talloc_tos(), uint8_t, 0);
+ buf = smb_bytes_push_str(buf, cli_ucs2(cli), pass, passlen+1,
+ &converted_size);
+ if (tevent_req_nomem(buf, req)) {
+ return tevent_req_post(req, ev);
+ }
lm_response = data_blob(pass, passlen);
+ TALLOC_FREE(buf);
+ if (tevent_req_nomem(lm_response.data, req)) {
+ return tevent_req_post(req, ev);
+ }
}
- /* send a session setup command */
- memset(cli->outbuf,'\0',smb_size);
- cli_set_message(cli->outbuf,10, 0, True);
- SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
- cli_setup_packet(cli);
-
- SCVAL(cli->outbuf,smb_vwv0,0xFF);
- SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
- SSVAL(cli->outbuf,smb_vwv3,2);
- SSVAL(cli->outbuf,smb_vwv4,1);
- SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
- SSVAL(cli->outbuf,smb_vwv7,lm_response.length);
-
- p = smb_buf(cli->outbuf);
- memcpy(p,lm_response.data,lm_response.length);
- p += lm_response.length;
- p += clistr_push(cli, p, user, -1, STR_TERMINATE|STR_UPPER);
- p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
- p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
- p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
- cli_setup_bcc(cli, p);
-
- if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
- return cli_nt_error(cli);
- }
-
- show_msg(cli->inbuf);
-
- if (cli_is_error(cli)) {
- return cli_nt_error(cli);
- }
-
- /* use the returned vuid from now on */
- cli->vuid = SVAL(cli->inbuf,smb_uid);
- status = cli_set_username(cli, user);
+ SCVAL(vwv+0, 0, 0xff);
+ SCVAL(vwv+0, 1, 0);
+ SSVAL(vwv+1, 0, 0);
+ SSVAL(vwv+2, 0, CLI_BUFFER_SIZE);
+ SSVAL(vwv+3, 0, 2);
+ SSVAL(vwv+4, 0, 1);
+ SIVAL(vwv+5, 0, cli->sesskey);
+ SSVAL(vwv+7, 0, lm_response.length);
+
+ bytes = talloc_array(state, uint8_t, lm_response.length);
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
+ }
+ if (lm_response.length != 0) {
+ memcpy(bytes, lm_response.data, lm_response.length);
+ }
+ data_blob_free(&lm_response);
+
+ tmp = talloc_strdup_upper(talloc_tos(), user);
+ if (tevent_req_nomem(tmp, req)) {
+ return tevent_req_post(req, ev);
+ }
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), tmp, strlen(tmp)+1,
+ NULL);
+ TALLOC_FREE(tmp);
+
+ tmp = talloc_strdup_upper(talloc_tos(), workgroup);
+ if (tevent_req_nomem(tmp, req)) {
+ return tevent_req_post(req, ev);
+ }
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), tmp, strlen(tmp)+1,
+ NULL);
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "Unix", 5, NULL);
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "Samba", 6, NULL);
+
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = cli_smb_send(state, ev, cli, SMBsesssetupX, 0, 10, vwv,
+ talloc_get_size(bytes), bytes);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_session_setup_lanman2_done, req);
+ return req;
+}
+
+static void cli_session_setup_lanman2_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_session_setup_lanman2_state *state = tevent_req_data(
+ req, struct cli_session_setup_lanman2_state);
+ struct cli_state *cli = state->cli;
+ uint32_t num_bytes;
+ uint8_t *in;
+ char *inbuf;
+ uint8_t *bytes;
+ uint8_t *p;
+ NTSTATUS status;
+ ssize_t ret;
+ uint8_t wct;
+ uint16_t *vwv;
+
+ status = cli_smb_recv(subreq, state, &in, 3, &wct, &vwv,
+ &num_bytes, &bytes);
+ TALLOC_FREE(subreq);
if (!NT_STATUS_IS_OK(status)) {
- return status;
+ tevent_req_nterror(req, status);
+ return;
}
- if (session_key.data) {
- /* Have plaintext orginal */
- cli_set_session_key(cli, session_key);
+ inbuf = (char *)in;
+ p = bytes;
+
+ cli->vuid = SVAL(inbuf, smb_uid);
+ cli->is_guestlogin = ((SVAL(vwv+2, 0) & 1) != 0);
+
+ status = smb_bytes_talloc_string(cli,
+ inbuf,
+ &cli->server_os,
+ p,
+ bytes+num_bytes-p,
+ &ret);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
}
+ p += ret;
- return NT_STATUS_OK;
+ status = smb_bytes_talloc_string(cli,
+ inbuf,
+ &cli->server_type,
+ p,
+ bytes+num_bytes-p,
+ &ret);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ p += ret;
+
+ status = smb_bytes_talloc_string(cli,
+ inbuf,
+ &cli->server_domain,
+ p,
+ bytes+num_bytes-p,
+ &ret);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ p += ret;
+
+ if (strstr(cli->server_type, "Samba")) {
+ cli->is_samba = True;
+ }
+ status = cli_set_username(cli, state->user);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ tevent_req_done(req);
+}
+
+static NTSTATUS cli_session_setup_lanman2_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+static NTSTATUS cli_session_setup_lanman2(struct cli_state *cli, const char *user,
+ const char *pass, size_t passlen,
+ const char *workgroup)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct event_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (cli_has_async_calls(cli)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ev = event_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = cli_session_setup_lanman2_send(frame, ev, cli, user, pass, passlen,
+ workgroup);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = cli_session_setup_lanman2_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
}
/****************************************************************************
struct cli_session_setup_guest_state {
struct cli_state *cli;
- uint16_t vwv[16];
+ uint16_t vwv[13];
struct iovec bytes;
};
req, struct cli_session_setup_guest_state);
struct cli_state *cli = state->cli;
uint32_t num_bytes;
+ uint8_t *in;
char *inbuf;
uint8_t *bytes;
uint8_t *p;
NTSTATUS status;
+ ssize_t ret;
+ uint8_t wct;
+ uint16_t *vwv;
- status = cli_smb_recv(subreq, 0, NULL, NULL, &num_bytes, &bytes);
+ status = cli_smb_recv(subreq, state, &in, 3, &wct, &vwv,
+ &num_bytes, &bytes);
+ TALLOC_FREE(subreq);
if (!NT_STATUS_IS_OK(status)) {
- TALLOC_FREE(subreq);
tevent_req_nterror(req, status);
return;
}
- inbuf = (char *)cli_smb_inbuf(subreq);
+ inbuf = (char *)in;
p = bytes;
cli->vuid = SVAL(inbuf, smb_uid);
+ cli->is_guestlogin = ((SVAL(vwv+2, 0) & 1) != 0);
+
+ status = smb_bytes_talloc_string(cli,
+ inbuf,
+ &cli->server_os,
+ p,
+ bytes+num_bytes-p,
+ &ret);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ p += ret;
+
+ status = smb_bytes_talloc_string(cli,
+ inbuf,
+ &cli->server_type,
+ p,
+ bytes+num_bytes-p,
+ &ret);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ p += ret;
+
+ status = smb_bytes_talloc_string(cli,
+ inbuf,
+ &cli->server_domain,
+ p,
+ bytes+num_bytes-p,
+ &ret);
- p += clistr_pull(inbuf, cli->server_os, (char *)p, sizeof(fstring),
- bytes+num_bytes-p, STR_TERMINATE);
- p += clistr_pull(inbuf, cli->server_type, (char *)p, sizeof(fstring),
- bytes+num_bytes-p, STR_TERMINATE);
- p += clistr_pull(inbuf, cli->server_domain, (char *)p, sizeof(fstring),
- bytes+num_bytes-p, STR_TERMINATE);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ p += ret;
if (strstr(cli->server_type, "Samba")) {
cli->is_samba = True;
}
- TALLOC_FREE(subreq);
-
status = cli_set_username(cli, "");
if (!NT_STATUS_IS_OK(status)) {
tevent_req_nterror(req, status);
status = cli_session_setup_guest_recv(req);
fail:
TALLOC_FREE(frame);
- if (!NT_STATUS_IS_OK(status)) {
- cli_set_error(cli, status);
- }
return status;
}
Do a NT1 plaintext session setup.
****************************************************************************/
-static NTSTATUS cli_session_setup_plaintext(struct cli_state *cli,
- const char *user, const char *pass,
- const char *workgroup)
+struct cli_session_setup_plain_state {
+ struct cli_state *cli;
+ uint16_t vwv[13];
+ const char *user;
+};
+
+static void cli_session_setup_plain_done(struct tevent_req *subreq);
+
+static struct tevent_req *cli_session_setup_plain_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ struct cli_state *cli,
+ const char *user, const char *pass, const char *workgroup)
{
- uint32 capabilities = cli_session_setup_capabilities(cli);
- char *p;
- NTSTATUS status;
- fstring lanman;
-
- fstr_sprintf( lanman, "Samba %s", samba_version_string());
-
- memset(cli->outbuf, '\0', smb_size);
- cli_set_message(cli->outbuf,13,0,True);
- SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
- cli_setup_packet(cli);
-
- SCVAL(cli->outbuf,smb_vwv0,0xFF);
- SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
- SSVAL(cli->outbuf,smb_vwv3,2);
- SSVAL(cli->outbuf,smb_vwv4,cli->pid);
- SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
- SSVAL(cli->outbuf,smb_vwv8,0);
- SIVAL(cli->outbuf,smb_vwv11,capabilities);
- p = smb_buf(cli->outbuf);
-
- /* check wether to send the ASCII or UNICODE version of the password */
-
- if ( (capabilities & CAP_UNICODE) == 0 ) {
- p += clistr_push(cli, p, pass, -1, STR_TERMINATE); /* password */
- SSVAL(cli->outbuf,smb_vwv7,PTR_DIFF(p, smb_buf(cli->outbuf)));
- }
- else {
- /* For ucs2 passwords clistr_push calls ucs2_align, which causes
- * the space taken by the unicode password to be one byte too
- * long (as we're on an odd byte boundary here). Reduce the
- * count by 1 to cope with this. Fixes smbclient against NetApp
- * servers which can't cope. Fix from
- * bryan.kolodziej@allenlund.com in bug #3840.
- */
- p += clistr_push(cli, p, pass, -1, STR_UNICODE|STR_TERMINATE); /* unicode password */
- SSVAL(cli->outbuf,smb_vwv8,PTR_DIFF(p, smb_buf(cli->outbuf))-1);
- }
-
- p += clistr_push(cli, p, user, -1, STR_TERMINATE); /* username */
- p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE); /* workgroup */
- p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
- p += clistr_push(cli, p, lanman, -1, STR_TERMINATE);
- cli_setup_bcc(cli, p);
-
- if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
- return cli_nt_error(cli);
- }
-
- show_msg(cli->inbuf);
-
- if (cli_is_error(cli)) {
- return cli_nt_error(cli);
- }
-
- cli->vuid = SVAL(cli->inbuf,smb_uid);
- p = smb_buf(cli->inbuf);
- p += clistr_pull(cli->inbuf, cli->server_os, p, sizeof(fstring),
- -1, STR_TERMINATE);
- p += clistr_pull(cli->inbuf, cli->server_type, p, sizeof(fstring),
- -1, STR_TERMINATE);
- p += clistr_pull(cli->inbuf, cli->server_domain, p, sizeof(fstring),
- -1, STR_TERMINATE);
- status = cli_set_username(cli, user);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
- if (strstr(cli->server_type, "Samba")) {
- cli->is_samba = True;
- }
+ struct tevent_req *req, *subreq;
+ struct cli_session_setup_plain_state *state;
+ uint16_t *vwv;
+ uint8_t *bytes;
+ size_t passlen;
+ char *version;
- return NT_STATUS_OK;
-}
+ req = tevent_req_create(mem_ctx, &state,
+ struct cli_session_setup_plain_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->cli = cli;
+ state->user = user;
+ vwv = state->vwv;
-/****************************************************************************
- do a NT1 NTLM/LM encrypted session setup - for when extended security
- is not negotiated.
- @param cli client state to create do session setup on
- @param user username
- @param pass *either* cleartext password (passlen !=24) or LM response.
- @param ntpass NT response, implies ntpasslen >=24, implies pass is not clear
- @param workgroup The user's domain.
-****************************************************************************/
+ SCVAL(vwv+0, 0, 0xff);
+ SCVAL(vwv+0, 1, 0);
+ SSVAL(vwv+1, 0, 0);
+ SSVAL(vwv+2, 0, CLI_BUFFER_SIZE);
+ SSVAL(vwv+3, 0, 2);
+ SSVAL(vwv+4, 0, cli->pid);
+ SIVAL(vwv+5, 0, cli->sesskey);
+ SSVAL(vwv+7, 0, 0);
+ SSVAL(vwv+8, 0, 0);
+ SSVAL(vwv+9, 0, 0);
+ SSVAL(vwv+10, 0, 0);
+ SIVAL(vwv+11, 0, cli_session_setup_capabilities(cli));
-static NTSTATUS cli_session_setup_nt1(struct cli_state *cli, const char *user,
- const char *pass, size_t passlen,
- const char *ntpass, size_t ntpasslen,
- const char *workgroup)
-{
- uint32 capabilities = cli_session_setup_capabilities(cli);
- DATA_BLOB lm_response = data_blob_null;
- DATA_BLOB nt_response = data_blob_null;
- DATA_BLOB session_key = data_blob_null;
- NTSTATUS result;
- char *p;
- bool ok;
+ bytes = talloc_array(state, uint8_t, 0);
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), pass, strlen(pass)+1,
+ &passlen);
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
+ }
+ SSVAL(vwv + (cli_ucs2(cli) ? 8 : 7), 0, passlen);
- if (passlen == 0) {
- /* do nothing - guest login */
- } else if (passlen != 24) {
- if (lp_client_ntlmv2_auth()) {
- DATA_BLOB server_chal;
- DATA_BLOB names_blob;
- server_chal = data_blob(cli->secblob.data, MIN(cli->secblob.length, 8));
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+ user, strlen(user)+1, NULL);
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+ workgroup, strlen(workgroup)+1, NULL);
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+ "Unix", 5, NULL);
- /* note that the 'workgroup' here is a best guess - we don't know
- the server's domain at this point. The 'server name' is also
- dodgy...
- */
- names_blob = NTLMv2_generate_names_blob(NULL, cli->called.name, workgroup);
+ version = talloc_asprintf(talloc_tos(), "Samba %s",
+ samba_version_string());
+ if (tevent_req_nomem(version, req)){
+ return tevent_req_post(req, ev);
+ }
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+ version, strlen(version)+1, NULL);
+ TALLOC_FREE(version);
- if (!SMBNTLMv2encrypt(NULL, user, workgroup, pass, &server_chal,
- &names_blob,
- &lm_response, &nt_response, NULL, &session_key)) {
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = cli_smb_send(state, ev, cli, SMBsesssetupX, 0, 13, vwv,
+ talloc_get_size(bytes), bytes);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_session_setup_plain_done, req);
+ return req;
+}
+
+static void cli_session_setup_plain_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_session_setup_plain_state *state = tevent_req_data(
+ req, struct cli_session_setup_plain_state);
+ struct cli_state *cli = state->cli;
+ uint32_t num_bytes;
+ uint8_t *in;
+ char *inbuf;
+ uint8_t *bytes;
+ uint8_t *p;
+ NTSTATUS status;
+ ssize_t ret;
+ uint8_t wct;
+ uint16_t *vwv;
+
+ status = cli_smb_recv(subreq, state, &in, 3, &wct, &vwv,
+ &num_bytes, &bytes);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ inbuf = (char *)in;
+ p = bytes;
+
+ cli->vuid = SVAL(inbuf, smb_uid);
+ cli->is_guestlogin = ((SVAL(vwv+2, 0) & 1) != 0);
+
+ status = smb_bytes_talloc_string(cli,
+ inbuf,
+ &cli->server_os,
+ p,
+ bytes+num_bytes-p,
+ &ret);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ p += ret;
+
+ status = smb_bytes_talloc_string(cli,
+ inbuf,
+ &cli->server_type,
+ p,
+ bytes+num_bytes-p,
+ &ret);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ p += ret;
+
+ status = smb_bytes_talloc_string(cli,
+ inbuf,
+ &cli->server_domain,
+ p,
+ bytes+num_bytes-p,
+ &ret);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ p += ret;
+
+ status = cli_set_username(cli, state->user);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ if (strstr(cli->server_type, "Samba")) {
+ cli->is_samba = True;
+ }
+ tevent_req_done(req);
+}
+
+static NTSTATUS cli_session_setup_plain_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+static NTSTATUS cli_session_setup_plain(struct cli_state *cli,
+ const char *user, const char *pass,
+ const char *workgroup)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct event_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (cli_has_async_calls(cli)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ev = event_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = cli_session_setup_plain_send(frame, ev, cli, user, pass,
+ workgroup);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = cli_session_setup_plain_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+/****************************************************************************
+ do a NT1 NTLM/LM encrypted session setup - for when extended security
+ is not negotiated.
+ @param cli client state to create do session setup on
+ @param user username
+ @param pass *either* cleartext password (passlen !=24) or LM response.
+ @param ntpass NT response, implies ntpasslen >=24, implies pass is not clear
+ @param workgroup The user's domain.
+****************************************************************************/
+
+struct cli_session_setup_nt1_state {
+ struct cli_state *cli;
+ uint16_t vwv[13];
+ DATA_BLOB response;
+ DATA_BLOB session_key;
+ const char *user;
+};
+
+static void cli_session_setup_nt1_done(struct tevent_req *subreq);
+
+static struct tevent_req *cli_session_setup_nt1_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ struct cli_state *cli, const char *user,
+ const char *pass, size_t passlen,
+ const char *ntpass, size_t ntpasslen,
+ const char *workgroup)
+{
+ struct tevent_req *req, *subreq;
+ struct cli_session_setup_nt1_state *state;
+ DATA_BLOB lm_response = data_blob_null;
+ DATA_BLOB nt_response = data_blob_null;
+ DATA_BLOB session_key = data_blob_null;
+ uint16_t *vwv;
+ uint8_t *bytes;
+ char *workgroup_upper;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct cli_session_setup_nt1_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->cli = cli;
+ state->user = user;
+ vwv = state->vwv;
+
+ if (passlen == 0) {
+ /* do nothing - guest login */
+ } else if (passlen != 24) {
+ if (lp_client_ntlmv2_auth()) {
+ DATA_BLOB server_chal;
+ DATA_BLOB names_blob;
+
+ server_chal = data_blob(cli->secblob.data,
+ MIN(cli->secblob.length, 8));
+ if (tevent_req_nomem(server_chal.data, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ /*
+ * note that the 'workgroup' here is a best
+ * guess - we don't know the server's domain
+ * at this point. The 'server name' is also
+ * dodgy...
+ */
+ names_blob = NTLMv2_generate_names_blob(
+ NULL, cli->called.name, workgroup);
+
+ if (tevent_req_nomem(names_blob.data, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ if (!SMBNTLMv2encrypt(NULL, user, workgroup, pass,
+ &server_chal, &names_blob,
+ &lm_response, &nt_response,
+ NULL, &session_key)) {
data_blob_free(&names_blob);
data_blob_free(&server_chal);
- return NT_STATUS_ACCESS_DENIED;
+ tevent_req_nterror(
+ req, NT_STATUS_ACCESS_DENIED);
+ return tevent_req_post(req, ev);
}
data_blob_free(&names_blob);
data_blob_free(&server_chal);
nt_response = data_blob_null;
#else
nt_response = data_blob(NULL, 24);
- SMBNTencrypt(pass,cli->secblob.data,nt_response.data);
+ if (tevent_req_nomem(nt_response.data, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ SMBNTencrypt(pass, cli->secblob.data,
+ nt_response.data);
#endif
/* non encrypted password supplied. Ignore ntpass. */
if (lp_client_lanman_auth()) {
+
lm_response = data_blob(NULL, 24);
- if (!SMBencrypt(pass,cli->secblob.data, lm_response.data)) {
- /* Oops, the LM response is invalid, just put
- the NT response there instead */
+ if (tevent_req_nomem(lm_response.data, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ if (!SMBencrypt(pass,cli->secblob.data,
+ lm_response.data)) {
+ /*
+ * Oops, the LM response is
+ * invalid, just put the NT
+ * response there instead
+ */
data_blob_free(&lm_response);
- lm_response = data_blob(nt_response.data, nt_response.length);
+ lm_response = data_blob(
+ nt_response.data,
+ nt_response.length);
}
} else {
- /* LM disabled, place NT# in LM field instead */
- lm_response = data_blob(nt_response.data, nt_response.length);
+ /*
+ * LM disabled, place NT# in LM field
+ * instead
+ */
+ lm_response = data_blob(
+ nt_response.data, nt_response.length);
+ }
+
+ if (tevent_req_nomem(lm_response.data, req)) {
+ return tevent_req_post(req, ev);
}
session_key = data_blob(NULL, 16);
+ if (tevent_req_nomem(session_key.data, req)) {
+ return tevent_req_post(req, ev);
+ }
#ifdef LANMAN_ONLY
E_deshash(pass, session_key.data);
memset(&session_key.data[8], '\0', 8);
signing because we don't have original key */
lm_response = data_blob(pass, passlen);
- nt_response = data_blob(ntpass, ntpasslen);
- }
-
- /* send a session setup command */
- memset(cli->outbuf,'\0',smb_size);
-
- cli_set_message(cli->outbuf,13,0,True);
- SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
- cli_setup_packet(cli);
-
- SCVAL(cli->outbuf,smb_vwv0,0xFF);
- SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
- SSVAL(cli->outbuf,smb_vwv3,2);
- SSVAL(cli->outbuf,smb_vwv4,cli->pid);
- SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
- SSVAL(cli->outbuf,smb_vwv7,lm_response.length);
- SSVAL(cli->outbuf,smb_vwv8,nt_response.length);
- SIVAL(cli->outbuf,smb_vwv11,capabilities);
- p = smb_buf(cli->outbuf);
- if (lm_response.length) {
- memcpy(p,lm_response.data, lm_response.length); p += lm_response.length;
- }
- if (nt_response.length) {
- memcpy(p,nt_response.data, nt_response.length); p += nt_response.length;
- }
- p += clistr_push(cli, p, user, -1, STR_TERMINATE);
-
- /* Upper case here might help some NTLMv2 implementations */
- p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
- p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
- p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
- cli_setup_bcc(cli, p);
-
- if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
- result = cli_nt_error(cli);
- goto end;
- }
-
- /* show_msg(cli->inbuf); */
+ if (tevent_req_nomem(lm_response.data, req)) {
+ return tevent_req_post(req, ev);
+ }
- if (cli_is_error(cli)) {
- result = cli_nt_error(cli);
- goto end;
+ nt_response = data_blob(ntpass, ntpasslen);
+ if (tevent_req_nomem(nt_response.data, req)) {
+ return tevent_req_post(req, ev);
+ }
}
#ifdef LANMAN_ONLY
- ok = cli_simple_set_signing(cli, session_key, lm_response);
+ state->response = data_blob_talloc(
+ state, lm_response.data, lm_response.length);
#else
- ok = cli_simple_set_signing(cli, session_key, nt_response);
+ state->response = data_blob_talloc(
+ state, nt_response.data, nt_response.length);
#endif
- if (ok) {
- if (!cli_check_sign_mac(cli, cli->inbuf, 1)) {
- result = NT_STATUS_ACCESS_DENIED;
- goto end;
+ if (tevent_req_nomem(state->response.data, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ if (session_key.data) {
+ state->session_key = data_blob_talloc(
+ state, session_key.data, session_key.length);
+ if (tevent_req_nomem(state->session_key.data, req)) {
+ return tevent_req_post(req, ev);
}
}
+ data_blob_free(&session_key);
- /* use the returned vuid from now on */
- cli->vuid = SVAL(cli->inbuf,smb_uid);
-
- p = smb_buf(cli->inbuf);
- p += clistr_pull(cli->inbuf, cli->server_os, p, sizeof(fstring),
- -1, STR_TERMINATE);
- p += clistr_pull(cli->inbuf, cli->server_type, p, sizeof(fstring),
- -1, STR_TERMINATE);
- p += clistr_pull(cli->inbuf, cli->server_domain, p, sizeof(fstring),
- -1, STR_TERMINATE);
+ SCVAL(vwv+0, 0, 0xff);
+ SCVAL(vwv+0, 1, 0);
+ SSVAL(vwv+1, 0, 0);
+ SSVAL(vwv+2, 0, CLI_BUFFER_SIZE);
+ SSVAL(vwv+3, 0, 2);
+ SSVAL(vwv+4, 0, cli->pid);
+ SIVAL(vwv+5, 0, cli->sesskey);
+ SSVAL(vwv+7, 0, lm_response.length);
+ SSVAL(vwv+8, 0, nt_response.length);
+ SSVAL(vwv+9, 0, 0);
+ SSVAL(vwv+10, 0, 0);
+ SIVAL(vwv+11, 0, cli_session_setup_capabilities(cli));
- if (strstr(cli->server_type, "Samba")) {
- cli->is_samba = True;
+ bytes = talloc_array(state, uint8_t,
+ lm_response.length + nt_response.length);
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
}
-
- result = cli_set_username(cli, user);
- if (!NT_STATUS_IS_OK(result)) {
- goto end;
+ if (lm_response.length != 0) {
+ memcpy(bytes, lm_response.data, lm_response.length);
}
-
- if (session_key.data) {
- /* Have plaintext orginal */
- cli_set_session_key(cli, session_key);
+ if (nt_response.length != 0) {
+ memcpy(bytes + lm_response.length,
+ nt_response.data, nt_response.length);
}
-
- result = NT_STATUS_OK;
-end:
data_blob_free(&lm_response);
data_blob_free(&nt_response);
- data_blob_free(&session_key);
- return result;
-}
-/****************************************************************************
- Send a extended security session setup blob
-****************************************************************************/
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+ user, strlen(user)+1, NULL);
-static bool cli_session_setup_blob_send(struct cli_state *cli, DATA_BLOB blob)
-{
- uint32 capabilities = cli_session_setup_capabilities(cli);
- char *p;
+ /*
+ * Upper case here might help some NTLMv2 implementations
+ */
+ workgroup_upper = talloc_strdup_upper(talloc_tos(), workgroup);
+ if (tevent_req_nomem(workgroup_upper, req)) {
+ return tevent_req_post(req, ev);
+ }
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+ workgroup_upper, strlen(workgroup_upper)+1,
+ NULL);
+ TALLOC_FREE(workgroup_upper);
- capabilities |= CAP_EXTENDED_SECURITY;
-
- /* send a session setup command */
- memset(cli->outbuf,'\0',smb_size);
-
- cli_set_message(cli->outbuf,12,0,True);
- SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
-
- cli_setup_packet(cli);
-
- SCVAL(cli->outbuf,smb_vwv0,0xFF);
- SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
- SSVAL(cli->outbuf,smb_vwv3,2);
- SSVAL(cli->outbuf,smb_vwv4,1);
- SIVAL(cli->outbuf,smb_vwv5,0);
- SSVAL(cli->outbuf,smb_vwv7,blob.length);
- SIVAL(cli->outbuf,smb_vwv10,capabilities);
- p = smb_buf(cli->outbuf);
- memcpy(p, blob.data, blob.length);
- p += blob.length;
- p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
- p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
- cli_setup_bcc(cli, p);
- return cli_send_smb(cli);
-}
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "Unix", 5, NULL);
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "Samba", 6, NULL);
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
+ }
-/****************************************************************************
- Send a extended security session setup blob, returning a reply blob.
-****************************************************************************/
+ subreq = cli_smb_send(state, ev, cli, SMBsesssetupX, 0, 13, vwv,
+ talloc_get_size(bytes), bytes);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_session_setup_nt1_done, req);
+ return req;
+}
-static DATA_BLOB cli_session_setup_blob_receive(struct cli_state *cli)
+static void cli_session_setup_nt1_done(struct tevent_req *subreq)
{
- DATA_BLOB blob2 = data_blob_null;
- char *p;
- size_t len;
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_session_setup_nt1_state *state = tevent_req_data(
+ req, struct cli_session_setup_nt1_state);
+ struct cli_state *cli = state->cli;
+ uint32_t num_bytes;
+ uint8_t *in;
+ char *inbuf;
+ uint8_t *bytes;
+ uint8_t *p;
+ NTSTATUS status;
+ ssize_t ret;
+ uint8_t wct;
+ uint16_t *vwv;
- if (!cli_receive_smb(cli))
- return blob2;
+ status = cli_smb_recv(subreq, state, &in, 3, &wct, &vwv,
+ &num_bytes, &bytes);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
- show_msg(cli->inbuf);
+ inbuf = (char *)in;
+ p = bytes;
- if (cli_is_error(cli) && !NT_STATUS_EQUAL(cli_nt_error(cli),
- NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- return blob2;
+ cli->vuid = SVAL(inbuf, smb_uid);
+ cli->is_guestlogin = ((SVAL(vwv+2, 0) & 1) != 0);
+
+ status = smb_bytes_talloc_string(cli,
+ inbuf,
+ &cli->server_os,
+ p,
+ bytes+num_bytes-p,
+ &ret);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
}
+ p += ret;
- /* use the returned vuid from now on */
- cli->vuid = SVAL(cli->inbuf,smb_uid);
+ status = smb_bytes_talloc_string(cli,
+ inbuf,
+ &cli->server_type,
+ p,
+ bytes+num_bytes-p,
+ &ret);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ p += ret;
+
+ status = smb_bytes_talloc_string(cli,
+ inbuf,
+ &cli->server_domain,
+ p,
+ bytes+num_bytes-p,
+ &ret);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ p += ret;
- p = smb_buf(cli->inbuf);
+ if (strstr(cli->server_type, "Samba")) {
+ cli->is_samba = True;
+ }
- blob2 = data_blob(p, SVAL(cli->inbuf, smb_vwv3));
+ status = cli_set_username(cli, state->user);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ if (cli_simple_set_signing(cli, state->session_key, state->response)
+ && !cli_check_sign_mac(cli, (char *)in, 1)) {
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
+ }
+ if (state->session_key.data) {
+ /* Have plaintext orginal */
+ cli_set_session_key(cli, state->session_key);
+ }
+ tevent_req_done(req);
+}
- p += blob2.length;
- p += clistr_pull(cli->inbuf, cli->server_os, p, sizeof(fstring),
- -1, STR_TERMINATE);
+static NTSTATUS cli_session_setup_nt1_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
- /* w2k with kerberos doesn't properly null terminate this field */
- len = smb_bufrem(cli->inbuf, p);
- if (p + len < cli->inbuf + cli->bufsize+SAFETY_MARGIN - 2) {
- char *end_of_buf = p + len;
+static NTSTATUS cli_session_setup_nt1(struct cli_state *cli, const char *user,
+ const char *pass, size_t passlen,
+ const char *ntpass, size_t ntpasslen,
+ const char *workgroup)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct event_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
- SSVAL(p, len, 0);
- /* Now it's null terminated. */
- p += clistr_pull(cli->inbuf, cli->server_type, p, sizeof(fstring),
- -1, STR_TERMINATE);
- /*
- * See if there's another string. If so it's the
- * server domain (part of the 'standard' Samba
- * server signature).
- */
- if (p < end_of_buf) {
- p += clistr_pull(cli->inbuf, cli->server_domain, p, sizeof(fstring),
- -1, STR_TERMINATE);
- }
- } else {
+ if (cli_has_async_calls(cli)) {
/*
- * No room to null terminate so we can't see if there
- * is another string (server_domain) afterwards.
+ * Can't use sync call while an async call is in flight
*/
- p += clistr_pull(cli->inbuf, cli->server_type, p, sizeof(fstring),
- len, 0);
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ev = event_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
}
- return blob2;
+ req = cli_session_setup_nt1_send(frame, ev, cli, user, pass, passlen,
+ ntpass, ntpasslen, workgroup);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = cli_session_setup_nt1_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
}
-#ifdef HAVE_KRB5
-/****************************************************************************
- Send a extended security session setup blob, returning a reply blob.
-****************************************************************************/
-
/* The following is calculated from :
* (smb_size-4) = 35
* (smb_wcnt * 2) = 24 (smb_wcnt == 12 in cli_session_setup_blob_send() )
#define BASE_SESSSETUP_BLOB_PACKET_SIZE (35 + 24 + 22)
-static bool cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob)
+struct cli_sesssetup_blob_state {
+ struct tevent_context *ev;
+ struct cli_state *cli;
+ DATA_BLOB blob;
+ uint16_t max_blob_size;
+ uint16_t vwv[12];
+ uint8_t *buf;
+
+ NTSTATUS status;
+ char *inbuf;
+ DATA_BLOB ret_blob;
+};
+
+static bool cli_sesssetup_blob_next(struct cli_sesssetup_blob_state *state,
+ struct tevent_req **psubreq);
+static void cli_sesssetup_blob_done(struct tevent_req *subreq);
+
+static struct tevent_req *cli_sesssetup_blob_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli,
+ DATA_BLOB blob)
{
- int32 remaining = blob.length;
- int32 cur = 0;
- DATA_BLOB send_blob = data_blob_null;
- int32 max_blob_size = 0;
- DATA_BLOB receive_blob = data_blob_null;
+ struct tevent_req *req, *subreq;
+ struct cli_sesssetup_blob_state *state;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct cli_sesssetup_blob_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->blob = blob;
+ state->cli = cli;
if (cli->max_xmit < BASE_SESSSETUP_BLOB_PACKET_SIZE + 1) {
- DEBUG(0,("cli_session_setup_blob: cli->max_xmit too small "
- "(was %u, need minimum %u)\n",
- (unsigned int)cli->max_xmit,
- BASE_SESSSETUP_BLOB_PACKET_SIZE));
- cli_set_nt_error(cli, NT_STATUS_INVALID_PARAMETER);
- return False;
+ DEBUG(1, ("cli_session_setup_blob: cli->max_xmit too small "
+ "(was %u, need minimum %u)\n",
+ (unsigned int)cli->max_xmit,
+ BASE_SESSSETUP_BLOB_PACKET_SIZE));
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
}
+ state->max_blob_size =
+ MIN(cli->max_xmit - BASE_SESSSETUP_BLOB_PACKET_SIZE, 0xFFFF);
- max_blob_size = cli->max_xmit - BASE_SESSSETUP_BLOB_PACKET_SIZE;
+ if (!cli_sesssetup_blob_next(state, &subreq)) {
+ tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_sesssetup_blob_done, req);
+ return req;
+}
- while ( remaining > 0) {
- if (remaining >= max_blob_size) {
- send_blob.length = max_blob_size;
- remaining -= max_blob_size;
- } else {
- send_blob.length = remaining;
- remaining = 0;
- }
+static bool cli_sesssetup_blob_next(struct cli_sesssetup_blob_state *state,
+ struct tevent_req **psubreq)
+{
+ struct tevent_req *subreq;
+ uint16_t thistime;
+
+ SCVAL(state->vwv+0, 0, 0xFF);
+ SCVAL(state->vwv+0, 1, 0);
+ SSVAL(state->vwv+1, 0, 0);
+ SSVAL(state->vwv+2, 0, CLI_BUFFER_SIZE);
+ SSVAL(state->vwv+3, 0, 2);
+ SSVAL(state->vwv+4, 0, 1);
+ SIVAL(state->vwv+5, 0, 0);
+
+ thistime = MIN(state->blob.length, state->max_blob_size);
+ SSVAL(state->vwv+7, 0, thistime);
+
+ SSVAL(state->vwv+8, 0, 0);
+ SSVAL(state->vwv+9, 0, 0);
+ SIVAL(state->vwv+10, 0,
+ cli_session_setup_capabilities(state->cli)
+ | CAP_EXTENDED_SECURITY);
+
+ state->buf = (uint8_t *)talloc_memdup(state, state->blob.data,
+ thistime);
+ if (state->buf == NULL) {
+ return false;
+ }
+ state->blob.data += thistime;
+ state->blob.length -= thistime;
- send_blob.data = &blob.data[cur];
- cur += send_blob.length;
+ state->buf = smb_bytes_push_str(state->buf, cli_ucs2(state->cli),
+ "Unix", 5, NULL);
+ state->buf = smb_bytes_push_str(state->buf, cli_ucs2(state->cli),
+ "Samba", 6, NULL);
+ if (state->buf == NULL) {
+ return false;
+ }
+ subreq = cli_smb_send(state, state->ev, state->cli, SMBsesssetupX, 0,
+ 12, state->vwv,
+ talloc_get_size(state->buf), state->buf);
+ if (subreq == NULL) {
+ return false;
+ }
+ *psubreq = subreq;
+ return true;
+}
- DEBUG(10, ("cli_session_setup_blob: Remaining (%u) sending (%u) current (%u)\n",
- (unsigned int)remaining,
- (unsigned int)send_blob.length,
- (unsigned int)cur ));
+static void cli_sesssetup_blob_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_sesssetup_blob_state *state = tevent_req_data(
+ req, struct cli_sesssetup_blob_state);
+ struct cli_state *cli = state->cli;
+ uint8_t wct;
+ uint16_t *vwv;
+ uint32_t num_bytes;
+ uint8_t *bytes;
+ NTSTATUS status;
+ uint8_t *p;
+ uint16_t blob_length;
+ uint8_t *inbuf;
+ ssize_t ret;
- if (!cli_session_setup_blob_send(cli, send_blob)) {
- DEBUG(0, ("cli_session_setup_blob: send failed\n"));
- return False;
- }
+ status = cli_smb_recv(subreq, state, &inbuf, 4, &wct, &vwv,
+ &num_bytes, &bytes);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)
+ && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ state->status = status;
+ TALLOC_FREE(state->buf);
+
+ state->inbuf = (char *)inbuf;
+ cli->vuid = SVAL(state->inbuf, smb_uid);
+ cli->is_guestlogin = ((SVAL(vwv+2, 0) & 1) != 0);
+
+ blob_length = SVAL(vwv+3, 0);
+ if (blob_length > num_bytes) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+ state->ret_blob = data_blob_const(bytes, blob_length);
+
+ p = bytes + blob_length;
- receive_blob = cli_session_setup_blob_receive(cli);
- data_blob_free(&receive_blob);
+ status = smb_bytes_talloc_string(cli,
+ (char *)inbuf,
+ &cli->server_os,
+ p,
+ bytes+num_bytes-p,
+ &ret);
- if (cli_is_error(cli) &&
- !NT_STATUS_EQUAL( cli_get_nt_error(cli),
- NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- DEBUG(0, ("cli_session_setup_blob: receive failed "
- "(%s)\n", nt_errstr(cli_get_nt_error(cli))));
- cli->vuid = 0;
- return False;
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ p += ret;
+
+ status = smb_bytes_talloc_string(cli,
+ (char *)inbuf,
+ &cli->server_type,
+ p,
+ bytes+num_bytes-p,
+ &ret);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ p += ret;
+
+ status = smb_bytes_talloc_string(cli,
+ (char *)inbuf,
+ &cli->server_domain,
+ p,
+ bytes+num_bytes-p,
+ &ret);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+ p += ret;
+
+ if (strstr(cli->server_type, "Samba")) {
+ cli->is_samba = True;
+ }
+
+ if (state->blob.length != 0) {
+ /*
+ * More to send
+ */
+ if (!cli_sesssetup_blob_next(state, &subreq)) {
+ tevent_req_oom(req);
+ return;
}
+ tevent_req_set_callback(subreq, cli_sesssetup_blob_done, req);
+ return;
+ }
+ tevent_req_done(req);
+}
+
+static NTSTATUS cli_sesssetup_blob_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *pblob,
+ char **pinbuf)
+{
+ struct cli_sesssetup_blob_state *state = tevent_req_data(
+ req, struct cli_sesssetup_blob_state);
+ NTSTATUS status;
+ char *inbuf;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ state->cli->vuid = 0;
+ return status;
}
- return True;
+ inbuf = talloc_move(mem_ctx, &state->inbuf);
+ if (pblob != NULL) {
+ *pblob = state->ret_blob;
+ }
+ if (pinbuf != NULL) {
+ *pinbuf = inbuf;
+ }
+ /* could be NT_STATUS_MORE_PROCESSING_REQUIRED */
+ return state->status;
}
+#ifdef HAVE_KRB5
+
/****************************************************************************
Use in-memory credentials cache
****************************************************************************/
Do a spnego/kerberos encrypted session setup.
****************************************************************************/
-static ADS_STATUS cli_session_setup_kerberos(struct cli_state *cli, const char *principal, const char *workgroup)
-{
+struct cli_session_setup_kerberos_state {
+ struct cli_state *cli;
DATA_BLOB negTokenTarg;
DATA_BLOB session_key_krb5;
- NTSTATUS nt_status;
- int rc;
+ ADS_STATUS ads_status;
+};
- cli_temp_set_signing(cli);
+static void cli_session_setup_kerberos_done(struct tevent_req *subreq);
+
+static struct tevent_req *cli_session_setup_kerberos_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
+ const char *principal)
+{
+ struct tevent_req *req, *subreq;
+ struct cli_session_setup_kerberos_state *state;
+ int rc;
DEBUG(2,("Doing kerberos session setup\n"));
- /* generate the encapsulated kerberos5 ticket */
- rc = spnego_gen_negTokenTarg(principal, 0, &negTokenTarg, &session_key_krb5, 0, NULL);
+ req = tevent_req_create(mem_ctx, &state,
+ struct cli_session_setup_kerberos_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->cli = cli;
+ state->ads_status = ADS_SUCCESS;
+
+ cli_temp_set_signing(cli);
+ /*
+ * Ok, this is cheating: spnego_gen_krb5_negTokenInit can block if
+ * we have to acquire a ticket. To be fixed later :-)
+ */
+ rc = spnego_gen_krb5_negTokenInit(state, principal, 0, &state->negTokenTarg,
+ &state->session_key_krb5, 0, NULL);
if (rc) {
- DEBUG(1, ("cli_session_setup_kerberos: spnego_gen_negTokenTarg failed: %s\n",
- error_message(rc)));
- return ADS_ERROR_KRB5(rc);
+ DEBUG(1, ("cli_session_setup_kerberos: "
+ "spnego_gen_krb5_negTokenInit failed: %s\n",
+ error_message(rc)));
+ state->ads_status = ADS_ERROR_KRB5(rc);
+ tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
+ return tevent_req_post(req, ev);
}
#if 0
- file_save("negTokenTarg.dat", negTokenTarg.data, negTokenTarg.length);
+ file_save("negTokenTarg.dat", state->negTokenTarg.data,
+ state->negTokenTarg.length);
#endif
- if (!cli_session_setup_blob(cli, negTokenTarg)) {
- nt_status = cli_nt_error(cli);
- goto nt_error;
+ subreq = cli_sesssetup_blob_send(state, ev, cli, state->negTokenTarg);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
}
+ tevent_req_set_callback(subreq, cli_session_setup_kerberos_done, req);
+ return req;
+}
- if (cli_is_error(cli)) {
- nt_status = cli_nt_error(cli);
- if (NT_STATUS_IS_OK(nt_status)) {
- nt_status = NT_STATUS_UNSUCCESSFUL;
- }
- goto nt_error;
- }
+static void cli_session_setup_kerberos_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_session_setup_kerberos_state *state = tevent_req_data(
+ req, struct cli_session_setup_kerberos_state);
+ char *inbuf = NULL;
+ NTSTATUS status;
- cli_set_session_key(cli, session_key_krb5);
+ status = cli_sesssetup_blob_recv(subreq, talloc_tos(), NULL, &inbuf);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(subreq);
+ tevent_req_nterror(req, status);
+ return;
+ }
- if (cli_simple_set_signing(
- cli, session_key_krb5, data_blob_null)) {
+ cli_set_session_key(state->cli, state->session_key_krb5);
- if (!cli_check_sign_mac(cli, cli->inbuf, 1)) {
- nt_status = NT_STATUS_ACCESS_DENIED;
- goto nt_error;
- }
+ if (cli_simple_set_signing(state->cli, state->session_key_krb5,
+ data_blob_null)
+ && !cli_check_sign_mac(state->cli, inbuf, 1)) {
+ TALLOC_FREE(subreq);
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
}
+ TALLOC_FREE(subreq);
+ tevent_req_done(req);
+}
+
+static ADS_STATUS cli_session_setup_kerberos_recv(struct tevent_req *req)
+{
+ struct cli_session_setup_kerberos_state *state = tevent_req_data(
+ req, struct cli_session_setup_kerberos_state);
+ NTSTATUS status;
- data_blob_free(&negTokenTarg);
- data_blob_free(&session_key_krb5);
+ if (tevent_req_is_nterror(req, &status)) {
+ return ADS_ERROR_NT(status);
+ }
+ return state->ads_status;
+}
- return ADS_ERROR_NT(NT_STATUS_OK);
+static ADS_STATUS cli_session_setup_kerberos(struct cli_state *cli,
+ const char *principal)
+{
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ ADS_STATUS status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
-nt_error:
- data_blob_free(&negTokenTarg);
- data_blob_free(&session_key_krb5);
- cli->vuid = 0;
- return ADS_ERROR_NT(nt_status);
+ if (cli_has_async_calls(cli)) {
+ return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
+ ev = tevent_context_init(talloc_tos());
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = cli_session_setup_kerberos_send(ev, ev, cli, principal);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll(req, ev)) {
+ status = ADS_ERROR_SYSTEM(errno);
+ goto fail;
+ }
+ status = cli_session_setup_kerberos_recv(req);
+fail:
+ TALLOC_FREE(ev);
+ return status;
}
#endif /* HAVE_KRB5 */
-
/****************************************************************************
Do a spnego/NTLMSSP encrypted session setup.
****************************************************************************/
-static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, const char *user,
- const char *pass, const char *domain)
-{
+struct cli_session_setup_ntlmssp_state {
+ struct tevent_context *ev;
+ struct cli_state *cli;
struct ntlmssp_state *ntlmssp_state;
- NTSTATUS nt_status;
- int turn = 1;
- DATA_BLOB msg1;
- DATA_BLOB blob = data_blob_null;
- DATA_BLOB blob_in = data_blob_null;
- DATA_BLOB blob_out = data_blob_null;
+ int turn;
+ DATA_BLOB blob_out;
+};
- cli_temp_set_signing(cli);
+static int cli_session_setup_ntlmssp_state_destructor(
+ struct cli_session_setup_ntlmssp_state *state)
+{
+ if (state->ntlmssp_state != NULL) {
+ TALLOC_FREE(state->ntlmssp_state);
+ }
+ return 0;
+}
- if (!NT_STATUS_IS_OK(nt_status = ntlmssp_client_start(&ntlmssp_state))) {
- return nt_status;
+static void cli_session_setup_ntlmssp_done(struct tevent_req *req);
+
+static struct tevent_req *cli_session_setup_ntlmssp_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
+ const char *user, const char *pass, const char *domain)
+{
+ struct tevent_req *req, *subreq;
+ struct cli_session_setup_ntlmssp_state *state;
+ NTSTATUS status;
+ DATA_BLOB blob_out;
+ const char *OIDs_ntlm[] = {OID_NTLMSSP, NULL};
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct cli_session_setup_ntlmssp_state);
+ if (req == NULL) {
+ return NULL;
}
- ntlmssp_want_feature(ntlmssp_state, NTLMSSP_FEATURE_SESSION_KEY);
+ state->ev = ev;
+ state->cli = cli;
+ state->turn = 1;
- if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, user))) {
- return nt_status;
+ state->ntlmssp_state = NULL;
+ talloc_set_destructor(
+ state, cli_session_setup_ntlmssp_state_destructor);
+
+ cli_temp_set_signing(cli);
+
+ status = ntlmssp_client_start(state,
+ lp_netbios_name(),
+ lp_workgroup(),
+ lp_client_ntlmv2_auth(),
+ &state->ntlmssp_state);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
}
- if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, domain))) {
- return nt_status;
+ ntlmssp_want_feature(state->ntlmssp_state,
+ NTLMSSP_FEATURE_SESSION_KEY);
+ if (cli->use_ccache) {
+ ntlmssp_want_feature(state->ntlmssp_state,
+ NTLMSSP_FEATURE_CCACHE);
}
- if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_password(ntlmssp_state, pass))) {
- return nt_status;
+ status = ntlmssp_set_username(state->ntlmssp_state, user);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+ status = ntlmssp_set_domain(state->ntlmssp_state, domain);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+ status = ntlmssp_set_password(state->ntlmssp_state, pass);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+ status = ntlmssp_update(state->ntlmssp_state, data_blob_null,
+ &blob_out);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ goto fail;
}
- do {
- nt_status = ntlmssp_update(ntlmssp_state,
- blob_in, &blob_out);
- data_blob_free(&blob_in);
- if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) || NT_STATUS_IS_OK(nt_status)) {
- if (turn == 1) {
- /* and wrap it in a SPNEGO wrapper */
- msg1 = gen_negTokenInit(OID_NTLMSSP, blob_out);
- } else {
- /* wrap it in SPNEGO */
- msg1 = spnego_gen_auth(blob_out);
- }
+ state->blob_out = spnego_gen_negTokenInit(state, OIDs_ntlm, &blob_out, NULL);
+ data_blob_free(&blob_out);
- /* now send that blob on its way */
- if (!cli_session_setup_blob_send(cli, msg1)) {
- DEBUG(3, ("Failed to send NTLMSSP/SPNEGO blob to server!\n"));
- nt_status = NT_STATUS_UNSUCCESSFUL;
- } else {
- blob = cli_session_setup_blob_receive(cli);
-
- nt_status = cli_nt_error(cli);
- if (cli_is_error(cli) && NT_STATUS_IS_OK(nt_status)) {
- if (cli->smb_rw_error == SMB_READ_BAD_SIG) {
- nt_status = NT_STATUS_ACCESS_DENIED;
- } else {
- nt_status = NT_STATUS_UNSUCCESSFUL;
- }
- }
- }
- data_blob_free(&msg1);
- }
+ subreq = cli_sesssetup_blob_send(state, ev, cli, state->blob_out);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_session_setup_ntlmssp_done, req);
+ return req;
+fail:
+ tevent_req_nterror(req, status);
+ return tevent_req_post(req, ev);
+}
- if (!blob.length) {
- if (NT_STATUS_IS_OK(nt_status)) {
- nt_status = NT_STATUS_UNSUCCESSFUL;
- }
- } else if ((turn == 1) &&
- NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- DATA_BLOB tmp_blob = data_blob_null;
- /* the server might give us back two challenges */
- if (!spnego_parse_challenge(blob, &blob_in,
- &tmp_blob)) {
- DEBUG(3,("Failed to parse challenges\n"));
- nt_status = NT_STATUS_INVALID_PARAMETER;
- }
- data_blob_free(&tmp_blob);
- } else {
- if (!spnego_parse_auth_response(blob, nt_status, OID_NTLMSSP,
- &blob_in)) {
- DEBUG(3,("Failed to parse auth response\n"));
- if (NT_STATUS_IS_OK(nt_status)
- || NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED))
- nt_status = NT_STATUS_INVALID_PARAMETER;
+static void cli_session_setup_ntlmssp_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_session_setup_ntlmssp_state *state = tevent_req_data(
+ req, struct cli_session_setup_ntlmssp_state);
+ DATA_BLOB blob_in, msg_in, blob_out;
+ char *inbuf = NULL;
+ bool parse_ret;
+ NTSTATUS status;
+
+ status = cli_sesssetup_blob_recv(subreq, talloc_tos(), &blob_in,
+ &inbuf);
+ TALLOC_FREE(subreq);
+ data_blob_free(&state->blob_out);
+
+ if (NT_STATUS_IS_OK(status)) {
+ if (state->cli->server_domain[0] == '\0') {
+ TALLOC_FREE(state->cli->server_domain);
+ state->cli->server_domain = talloc_strdup(state->cli,
+ state->ntlmssp_state->server.netbios_domain);
+ if (state->cli->server_domain == NULL) {
+ TALLOC_FREE(subreq);
+ tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
}
}
- data_blob_free(&blob);
- data_blob_free(&blob_out);
- turn++;
- } while (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED));
+ cli_set_session_key(
+ state->cli, state->ntlmssp_state->session_key);
- data_blob_free(&blob_in);
+ if (cli_simple_set_signing(
+ state->cli, state->ntlmssp_state->session_key,
+ data_blob_null)
+ && !cli_check_sign_mac(state->cli, inbuf, 1)) {
+ TALLOC_FREE(subreq);
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
+ }
+ TALLOC_FREE(subreq);
+ TALLOC_FREE(state->ntlmssp_state);
+ tevent_req_done(req);
+ return;
+ }
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
- if (NT_STATUS_IS_OK(nt_status)) {
+ if (blob_in.length == 0) {
+ tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
+ return;
+ }
- if (cli->server_domain[0] == '\0') {
- fstrcpy(cli->server_domain, ntlmssp_state->server_domain);
+ if ((state->turn == 1)
+ && NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ DATA_BLOB tmp_blob = data_blob_null;
+ /* the server might give us back two challenges */
+ parse_ret = spnego_parse_challenge(state, blob_in, &msg_in,
+ &tmp_blob);
+ data_blob_free(&tmp_blob);
+ } else {
+ parse_ret = spnego_parse_auth_response(state, blob_in, status,
+ OID_NTLMSSP, &msg_in);
+ }
+ state->turn += 1;
+
+ if (!parse_ret) {
+ DEBUG(3,("Failed to parse auth response\n"));
+ if (NT_STATUS_IS_OK(status)
+ || NT_STATUS_EQUAL(status,
+ NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ tevent_req_nterror(
+ req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
}
- cli_set_session_key(cli, ntlmssp_state->session_key);
+ }
- if (cli_simple_set_signing(
- cli, ntlmssp_state->session_key, data_blob_null)) {
+ status = ntlmssp_update(state->ntlmssp_state, msg_in, &blob_out);
- if (!cli_check_sign_mac(cli, cli->inbuf, 1)) {
- nt_status = NT_STATUS_ACCESS_DENIED;
- }
- }
+ if (!NT_STATUS_IS_OK(status)
+ && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ TALLOC_FREE(subreq);
+ TALLOC_FREE(state->ntlmssp_state);
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ state->blob_out = spnego_gen_auth(state, blob_out);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nomem(state->blob_out.data, req)) {
+ return;
}
- /* we have a reference conter on ntlmssp_state, if we are signing
- then the state will be kept by the signing engine */
+ subreq = cli_sesssetup_blob_send(state, state->ev, state->cli,
+ state->blob_out);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, cli_session_setup_ntlmssp_done, req);
+}
- ntlmssp_end(&ntlmssp_state);
+static NTSTATUS cli_session_setup_ntlmssp_recv(struct tevent_req *req)
+{
+ struct cli_session_setup_ntlmssp_state *state = tevent_req_data(
+ req, struct cli_session_setup_ntlmssp_state);
+ NTSTATUS status;
- if (!NT_STATUS_IS_OK(nt_status)) {
- cli->vuid = 0;
+ if (tevent_req_is_nterror(req, &status)) {
+ state->cli->vuid = 0;
+ return status;
+ }
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli,
+ const char *user,
+ const char *pass,
+ const char *domain)
+{
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (cli_has_async_calls(cli)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ ev = tevent_context_init(talloc_tos());
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = cli_session_setup_ntlmssp_send(ev, ev, cli, user, pass, domain);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
}
- return nt_status;
+ status = cli_session_setup_ntlmssp_recv(req);
+fail:
+ TALLOC_FREE(ev);
+ return status;
}
/****************************************************************************
* negprot reply. It is WRONG to depend on the principal sent in the
* negprot reply, but right now we do it. If we don't receive one,
* we try to best guess, then fall back to NTLM. */
- if (!spnego_parse_negTokenInit(blob, OIDs, &principal)) {
+ if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &principal, NULL) ||
+ OIDs[0] == NULL) {
data_blob_free(&blob);
return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
}
status = cli_set_username(cli, user);
if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(principal);
return ADS_ERROR_NT(status);
}
}
}
- /* If we get a bad principal, try to guess it if
- we have a valid host NetBIOS name.
+ /* We may not be allowed to use the server-supplied SPNEGO principal, or it may not have been supplied to us
*/
- if (strequal(principal, ADS_IGNORE_PRINCIPAL)) {
+ if (!lp_client_use_spnego_principal() || strequal(principal, ADS_IGNORE_PRINCIPAL)) {
TALLOC_FREE(principal);
}
!strequal(STAR_SMBSERVER,
cli->desthost)) {
char *realm = NULL;
- char *machine = NULL;
char *host = NULL;
- DEBUG(3,("cli_session_setup_spnego: got a "
- "bad server principal, trying to guess ...\n"));
+ DEBUG(3,("cli_session_setup_spnego: using target "
+ "hostname not SPNEGO principal\n"));
host = strchr_m(cli->desthost, '.');
- if (host) {
- machine = SMB_STRNDUP(cli->desthost,
- host - cli->desthost);
- } else {
- machine = SMB_STRDUP(cli->desthost);
- }
- if (machine == NULL) {
- return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
- }
-
if (dest_realm) {
realm = SMB_STRDUP(dest_realm);
+ if (!realm) {
+ return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
strupper_m(realm);
} else {
- realm = kerberos_get_default_realm_from_ccache();
+ if (host) {
+ /* DNS name. */
+ realm = kerberos_get_realm_from_hostname(cli->desthost);
+ } else {
+ /* NetBIOS name - use our realm. */
+ realm = kerberos_get_default_realm_from_ccache();
+ }
}
- if (realm && *realm) {
- principal = talloc_asprintf(NULL, "%s$@%s",
- machine, realm);
- if (!principal) {
- SAFE_FREE(machine);
- SAFE_FREE(realm);
+
+ if (realm == NULL || *realm == '\0') {
+ realm = SMB_STRDUP(lp_realm());
+ if (!realm) {
return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
}
- DEBUG(3,("cli_session_setup_spnego: guessed "
- "server principal=%s\n",
- principal ? principal : "<null>"));
+ strupper_m(realm);
+ DEBUG(3,("cli_session_setup_spnego: cannot "
+ "get realm from dest_realm %s, "
+ "desthost %s. Using default "
+ "smb.conf realm %s\n",
+ dest_realm ? dest_realm : "<null>",
+ cli->desthost,
+ realm));
}
- SAFE_FREE(machine);
+
+ principal = talloc_asprintf(talloc_tos(),
+ "cifs/%s@%s",
+ cli->desthost,
+ realm);
+ if (!principal) {
+ SAFE_FREE(realm);
+ return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+ DEBUG(3,("cli_session_setup_spnego: guessed "
+ "server principal=%s\n",
+ principal ? principal : "<null>"));
+
SAFE_FREE(realm);
}
if (principal) {
- rc = cli_session_setup_kerberos(cli, principal,
- dest_realm);
+ rc = cli_session_setup_kerberos(cli, principal);
if (ADS_ERR_OK(rc) || !cli->fallback_after_kerberos) {
TALLOC_FREE(principal);
return rc;
const char *workgroup)
{
char *p;
- fstring user2;
+ char *user2;
if (user) {
- fstrcpy(user2, user);
+ user2 = talloc_strdup(talloc_tos(), user);
} else {
- user2[0] ='\0';
+ user2 = talloc_strdup(talloc_tos(), "");
+ }
+ if (user2 == NULL) {
+ return NT_STATUS_NO_MEMORY;
}
if (!workgroup) {
(p=strchr_m(user2,*lp_winbind_separator()))) {
*p = 0;
user = p+1;
+ strupper_m(user2);
workgroup = user2;
}
if (cli->protocol < PROTOCOL_NT1) {
if (!lp_client_lanman_auth() && passlen != 24 && (*pass)) {
- DEBUG(1, ("Server requested LM password but 'client lanman auth'"
- " is disabled\n"));
+ DEBUG(1, ("Server requested LM password but 'client lanman auth = no'"
+ " or 'client ntlmv2 auth = yes'\n"));
return NT_STATUS_ACCESS_DENIED;
}
if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0 &&
!lp_client_plaintext_auth() && (*pass)) {
- DEBUG(1, ("Server requested plaintext password but "
- "'client plaintext auth' is disabled\n"));
+ DEBUG(1, ("Server requested LM password but 'client plaintext auth = no'"
+ " or 'client ntlmv2 auth = yes'\n"));
return NT_STATUS_ACCESS_DENIED;
}
connect */
if ((cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) == 0)
- return cli_session_setup_plaintext(cli, user, "", workgroup);
+ return cli_session_setup_plain(cli, user, "", workgroup);
/* if the server doesn't support encryption then we have to use
plaintext. The second password is ignored */
if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) {
if (!lp_client_plaintext_auth() && (*pass)) {
- DEBUG(1, ("Server requested plaintext password but "
- "'client plaintext auth' is disabled\n"));
+ DEBUG(1, ("Server requested LM password but 'client plaintext auth = no'"
+ " or 'client ntlmv2 auth = yes'\n"));
return NT_STATUS_ACCESS_DENIED;
}
- return cli_session_setup_plaintext(cli, user, pass, workgroup);
+ return cli_session_setup_plain(cli, user, pass, workgroup);
}
/* if the server supports extended security then use SPNEGO */
Send a uloggoff.
*****************************************************************************/
-bool cli_ulogoff(struct cli_state *cli)
+struct cli_ulogoff_state {
+ struct cli_state *cli;
+ uint16_t vwv[3];
+};
+
+static void cli_ulogoff_done(struct tevent_req *subreq);
+
+struct tevent_req *cli_ulogoff_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli)
{
- memset(cli->outbuf,'\0',smb_size);
- cli_set_message(cli->outbuf,2,0,True);
- SCVAL(cli->outbuf,smb_com,SMBulogoffX);
- cli_setup_packet(cli);
- SSVAL(cli->outbuf,smb_vwv0,0xFF);
- SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
+ struct tevent_req *req, *subreq;
+ struct cli_ulogoff_state *state;
+
+ req = tevent_req_create(mem_ctx, &state, struct cli_ulogoff_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->cli = cli;
+
+ SCVAL(state->vwv+0, 0, 0xFF);
+ SCVAL(state->vwv+1, 0, 0);
+ SSVAL(state->vwv+2, 0, 0);
+
+ subreq = cli_smb_send(state, ev, cli, SMBulogoffX, 0, 2, state->vwv,
+ 0, NULL);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_ulogoff_done, req);
+ return req;
+}
- cli_send_smb(cli);
- if (!cli_receive_smb(cli))
- return False;
+static void cli_ulogoff_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_ulogoff_state *state = tevent_req_data(
+ req, struct cli_ulogoff_state);
+ NTSTATUS status;
- if (cli_is_error(cli)) {
- return False;
+ status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
}
+ state->cli->vuid = -1;
+ tevent_req_done(req);
+}
+
+NTSTATUS cli_ulogoff_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS cli_ulogoff(struct cli_state *cli)
+{
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
- cli->vuid = -1;
- return True;
+ if (cli_has_async_calls(cli)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ ev = tevent_context_init(talloc_tos());
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = cli_ulogoff_send(ev, ev, cli);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = cli_ulogoff_recv(req);
+fail:
+ TALLOC_FREE(ev);
+ return status;
}
/****************************************************************************
{
struct tevent_req *req, *subreq;
struct cli_tcon_andx_state *state;
- fstring pword;
+ uint8_t p24[24];
uint16_t *vwv;
char *tmp = NULL;
uint8_t *bytes;
+ *psmbreq = NULL;
+
req = tevent_req_create(mem_ctx, &state, struct cli_tcon_andx_state);
if (req == NULL) {
return NULL;
state->cli = cli;
vwv = state->vwv;
- fstrcpy(cli->share, share);
+ cli->share = talloc_strdup(cli, share);
+ if (!cli->share) {
+ return NULL;
+ }
/* in user level security don't send a password now */
if (cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) {
if (!lp_client_lanman_auth()) {
DEBUG(1, ("Server requested LANMAN password "
"(share-level security) but "
- "'client lanman auth' is disabled\n"));
+ "'client lanman auth = no' or 'client ntlmv2 auth = yes'\n"));
goto access_denied;
}
* Non-encrypted passwords - convert to DOS codepage before
* encryption.
*/
+ SMBencrypt(pass, cli->secblob.data, p24);
passlen = 24;
- SMBencrypt(pass, cli->secblob.data, (uchar *)pword);
+ pass = (const char *)p24;
} else {
if((cli->sec_mode & (NEGOTIATE_SECURITY_USER_LEVEL
|NEGOTIATE_SECURITY_CHALLENGE_RESPONSE))
== 0) {
+ char *tmp_pass;
+
if (!lp_client_plaintext_auth() && (*pass)) {
DEBUG(1, ("Server requested plaintext "
- "password but 'client plaintext "
- "auth' is disabled\n"));
+ "password but "
+ "'client lanman auth = no' or 'client ntlmv2 auth = yes'\n"));
goto access_denied;
}
* Non-encrypted passwords - convert to DOS codepage
* before using.
*/
- passlen = clistr_push(cli, pword, pass, sizeof(pword),
- STR_TERMINATE);
- if (passlen == -1) {
- DEBUG(1, ("clistr_push(pword) failed\n"));
- goto access_denied;
+ tmp_pass = talloc_array(talloc_tos(), char, 128);
+ if (tmp_pass == NULL) {
+ tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
+ return tevent_req_post(req, ev);
}
- } else {
- if (passlen) {
- memcpy(pword, pass, passlen);
+ passlen = clistr_push(cli,
+ tmp_pass,
+ pass,
+ talloc_get_size(tmp_pass),
+ STR_TERMINATE);
+ if (passlen == -1) {
+ tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
+ return tevent_req_post(req, ev);
}
+ pass = tmp_pass;
}
}
SSVAL(vwv+2, 0, TCONX_FLAG_EXTENDED_RESPONSE);
SSVAL(vwv+3, 0, passlen);
- if (passlen) {
- bytes = (uint8_t *)talloc_memdup(state, pword, passlen);
+ if (passlen && pass) {
+ bytes = (uint8_t *)talloc_memdup(state, pass, passlen);
} else {
bytes = talloc_array(state, uint8_t, 0);
}
if (req == NULL) {
return NULL;
}
+ if (subreq == NULL) {
+ return req;
+ }
status = cli_smb_req_send(subreq);
if (!NT_STATUS_IS_OK(status)) {
tevent_req_nterror(req, status);
struct cli_tcon_andx_state *state = tevent_req_data(
req, struct cli_tcon_andx_state);
struct cli_state *cli = state->cli;
- char *inbuf = (char *)cli_smb_inbuf(subreq);
+ uint8_t *in;
+ char *inbuf;
uint8_t wct;
uint16_t *vwv;
uint32_t num_bytes;
uint8_t *bytes;
NTSTATUS status;
- status = cli_smb_recv(subreq, 0, &wct, &vwv, &num_bytes, &bytes);
+ status = cli_smb_recv(subreq, state, &in, 0, &wct, &vwv,
+ &num_bytes, &bytes);
+ TALLOC_FREE(subreq);
if (!NT_STATUS_IS_OK(status)) {
- TALLOC_FREE(subreq);
tevent_req_nterror(req, status);
return;
}
- clistr_pull(inbuf, cli->dev, bytes, sizeof(fstring), num_bytes,
- STR_TERMINATE|STR_ASCII);
+ inbuf = (char *)in;
+
+ if (num_bytes) {
+ if (clistr_pull_talloc(cli,
+ inbuf,
+ SVAL(inbuf, smb_flg2),
+ &cli->dev,
+ bytes,
+ num_bytes,
+ STR_TERMINATE|STR_ASCII) == -1) {
+ tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ } else {
+ cli->dev = talloc_strdup(cli, "");
+ if (cli->dev == NULL) {
+ tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ }
if ((cli->protocol >= PROTOCOL_NT1) && (num_bytes == 3)) {
/* almost certainly win95 - enable bug fixes */
status = cli_tcon_andx_recv(req);
fail:
TALLOC_FREE(frame);
- if (!NT_STATUS_IS_OK(status)) {
- cli_set_error(cli, status);
- }
return status;
}
Send a tree disconnect.
****************************************************************************/
-bool cli_tdis(struct cli_state *cli)
-{
- memset(cli->outbuf,'\0',smb_size);
- cli_set_message(cli->outbuf,0,0,True);
- SCVAL(cli->outbuf,smb_com,SMBtdis);
- SSVAL(cli->outbuf,smb_tid,cli->cnum);
- cli_setup_packet(cli);
+struct cli_tdis_state {
+ struct cli_state *cli;
+};
+
+static void cli_tdis_done(struct tevent_req *subreq);
- cli_send_smb(cli);
- if (!cli_receive_smb(cli))
- return False;
+struct tevent_req *cli_tdis_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli)
+{
+ struct tevent_req *req, *subreq;
+ struct cli_tdis_state *state;
- if (cli_is_error(cli)) {
- return False;
+ req = tevent_req_create(mem_ctx, &state, struct cli_tdis_state);
+ if (req == NULL) {
+ return NULL;
}
+ state->cli = cli;
- cli->cnum = -1;
- return True;
+ subreq = cli_smb_send(state, ev, cli, SMBtdis, 0, 0, NULL, 0, NULL);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_tdis_done, req);
+ return req;
}
-/****************************************************************************
- Send a negprot command.
-****************************************************************************/
-
-void cli_negprot_sendsync(struct cli_state *cli)
+static void cli_tdis_done(struct tevent_req *subreq)
{
- char *p;
- int numprots;
-
- if (cli->protocol < PROTOCOL_NT1)
- cli->use_spnego = False;
-
- memset(cli->outbuf,'\0',smb_size);
-
- /* setup the protocol strings */
- cli_set_message(cli->outbuf,0,0,True);
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_tdis_state *state = tevent_req_data(
+ req, struct cli_tdis_state);
+ NTSTATUS status;
- p = smb_buf(cli->outbuf);
- for (numprots=0; numprots < ARRAY_SIZE(prots); numprots++) {
- if (prots[numprots].prot > cli->protocol) {
- break;
- }
- *p++ = 2;
- p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
+ status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
}
+ state->cli->cnum = -1;
+ tevent_req_done(req);
+}
- SCVAL(cli->outbuf,smb_com,SMBnegprot);
- cli_setup_bcc(cli, p);
- cli_setup_packet(cli);
+NTSTATUS cli_tdis_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
- SCVAL(smb_buf(cli->outbuf),0,2);
+NTSTATUS cli_tdis(struct cli_state *cli)
+{
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
- cli_send_smb(cli);
+ if (cli_has_async_calls(cli)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ ev = tevent_context_init(talloc_tos());
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = cli_tdis_send(ev, ev, cli);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = cli_tdis_recv(req);
+fail:
+ TALLOC_FREE(ev);
+ return status;
}
/****************************************************************************
uint8_t *bytes;
NTSTATUS status;
uint16_t protnum;
+ uint8_t *inbuf;
- status = cli_smb_recv(subreq, 1, &wct, &vwv, &num_bytes, &bytes);
+ status = cli_smb_recv(subreq, state, &inbuf, 1, &wct, &vwv,
+ &num_bytes, &bytes);
+ TALLOC_FREE(subreq);
if (!NT_STATUS_IS_OK(status)) {
- TALLOC_FREE(subreq);
tevent_req_nterror(req, status);
return;
}
}
/* work out if they sent us a workgroup */
if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
- smb_buflen(cli->inbuf) > 8) {
- clistr_pull(cli->inbuf, cli->server_domain,
- bytes+8, sizeof(cli->server_domain),
- num_bytes-8,
- STR_UNICODE|STR_NOALIGN);
+ smb_buflen(inbuf) > 8) {
+ ssize_t ret;
+ status = smb_bytes_talloc_string(
+ cli, (char *)inbuf, &cli->server_domain,
+ bytes + 8, num_bytes - 8, &ret);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
}
/*
SAFE_FREE(cli->inbuf);
cli->outbuf = (char *)SMB_MALLOC(CLI_SAMBA_MAX_LARGE_READX_SIZE+LARGE_WRITEX_HDR_SIZE+SAFETY_MARGIN);
cli->inbuf = (char *)SMB_MALLOC(CLI_SAMBA_MAX_LARGE_READX_SIZE+LARGE_WRITEX_HDR_SIZE+SAFETY_MARGIN);
+ if (!cli->outbuf || !cli->inbuf) {
+ tevent_req_nterror(req,
+ NT_STATUS_NO_MEMORY);
+ return;
+ }
cli->bufsize = CLI_SAMBA_MAX_LARGE_READX_SIZE + LARGE_WRITEX_HDR_SIZE;
}
cli->serverzone = SVALS(vwv + 10, 0);
cli->serverzone *= 60;
/* this time is converted to GMT by make_unix_date */
- cli->servertime = cli_make_unix_date(
- cli, (char *)(vwv + 8));
+ cli->servertime = make_unix_date(
+ (char *)(vwv + 8), cli->serverzone);
cli->readbraw_supported = ((SVAL(vwv + 5, 0) & 0x1) != 0);
cli->writebraw_supported = ((SVAL(vwv + 5, 0) & 0x2) != 0);
cli->secblob = data_blob(bytes, num_bytes);
status = cli_negprot_recv(req);
fail:
TALLOC_FREE(frame);
- if (!NT_STATUS_IS_OK(status)) {
- cli_set_error(cli, status);
- }
return status;
}
-/****************************************************************************
- Send a session request. See rfc1002.txt 4.3 and 4.3.2.
-****************************************************************************/
-
-bool cli_session_request(struct cli_state *cli,
- struct nmb_name *calling, struct nmb_name *called)
-{
- char *p;
- int len = 4;
- char *tmp;
-
- /* 445 doesn't have session request */
- if (cli->port == 445)
- return True;
-
- memcpy(&(cli->calling), calling, sizeof(*calling));
- memcpy(&(cli->called ), called , sizeof(*called ));
-
- /* put in the destination name */
-
- tmp = name_mangle(talloc_tos(), cli->called.name,
- cli->called.name_type);
- if (tmp == NULL) {
- return false;
- }
-
- p = cli->outbuf+len;
- memcpy(p, tmp, name_len(tmp));
- len += name_len(tmp);
- TALLOC_FREE(tmp);
-
- /* and my name */
-
- tmp = name_mangle(talloc_tos(), cli->calling.name,
- cli->calling.name_type);
- if (tmp == NULL) {
- return false;
- }
-
- p = cli->outbuf+len;
- memcpy(p, tmp, name_len(tmp));
- len += name_len(tmp);
- TALLOC_FREE(tmp);
-
- /* send a session request (RFC 1002) */
- /* setup the packet length
- * Remove four bytes from the length count, since the length
- * field in the NBT Session Service header counts the number
- * of bytes which follow. The cli_send_smb() function knows
- * about this and accounts for those four bytes.
- * CRH.
- */
- len -= 4;
- _smb_setlen(cli->outbuf,len);
- SCVAL(cli->outbuf,0,0x81);
-
- cli_send_smb(cli);
- DEBUG(5,("Sent session request\n"));
-
- if (!cli_receive_smb(cli))
- return False;
-
- if (CVAL(cli->inbuf,0) == 0x84) {
- /* C. Hoch 9/14/95 Start */
- /* For information, here is the response structure.
- * We do the byte-twiddling to for portability.
- struct RetargetResponse{
- unsigned char type;
- unsigned char flags;
- int16 length;
- int32 ip_addr;
- int16 port;
- };
- */
- uint16_t port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
- struct in_addr dest_ip;
- NTSTATUS status;
-
- /* SESSION RETARGET */
- putip((char *)&dest_ip,cli->inbuf+4);
- in_addr_to_sockaddr_storage(&cli->dest_ss, dest_ip);
-
- status = open_socket_out(&cli->dest_ss, port,
- LONG_CONNECT_TIMEOUT, &cli->fd);
- if (!NT_STATUS_IS_OK(status)) {
- return False;
- }
-
- DEBUG(3,("Retargeted\n"));
-
- set_socket_options(cli->fd, lp_socket_options());
-
- /* Try again */
- {
- static int depth;
- bool ret;
- if (depth > 4) {
- DEBUG(0,("Retarget recursion - failing\n"));
- return False;
- }
- depth++;
- ret = cli_session_request(cli, calling, called);
- depth--;
- return ret;
- }
- } /* C. Hoch 9/14/95 End */
-
- if (CVAL(cli->inbuf,0) != 0x82) {
- /* This is the wrong place to put the error... JRA. */
- cli->rap_error = CVAL(cli->inbuf,4);
- return False;
- }
- return(True);
-}
-
-struct fd_struct {
- int fd;
-};
-
-static void smb_sock_connected(struct tevent_req *req)
+static NTSTATUS cli_connect_sock(const char *host, int name_type,
+ const struct sockaddr_storage *pss,
+ const char *myname, uint16_t port,
+ int sec_timeout, int *pfd, uint16_t *pport)
{
- struct fd_struct *pfd = tevent_req_callback_data(
- req, struct fd_struct);
- int fd;
+ TALLOC_CTX *frame = talloc_stackframe();
+ const char *prog;
+ unsigned int i, num_addrs;
+ const char **called_names;
+ const char **calling_names;
+ int *called_types;
NTSTATUS status;
+ int fd;
- status = open_socket_out_defer_recv(req, &fd);
- if (NT_STATUS_IS_OK(status)) {
- pfd->fd = fd;
- }
-}
-
-static NTSTATUS open_smb_socket(const struct sockaddr_storage *pss,
- uint16_t *port, int timeout, int *pfd)
-{
- struct event_context *ev;
- struct tevent_req *r139, *r445;
- struct fd_struct *fd139, *fd445;
- NTSTATUS status = NT_STATUS_NO_MEMORY;
-
- if (*port != 0) {
- return open_socket_out(pss, *port, timeout, pfd);
- }
-
- ev = event_context_init(talloc_tos());
- if (ev == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
-
- fd139 = talloc(ev, struct fd_struct);
- if (fd139 == NULL) {
+ prog = getenv("LIBSMB_PROG");
+ if (prog != NULL) {
+ fd = sock_exec(prog);
+ if (fd == -1) {
+ return map_nt_error_from_unix(errno);
+ }
+ port = 0;
goto done;
}
- fd139->fd = -1;
- fd445 = talloc(ev, struct fd_struct);
- if (fd445 == NULL) {
- goto done;
+ if ((pss == NULL) || is_zero_addr(pss)) {
+ struct sockaddr_storage *addrs;
+ status = resolve_name_list(talloc_tos(), host, name_type,
+ &addrs, &num_addrs);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+ pss = addrs;
+ } else {
+ num_addrs = 1;
}
- fd445->fd = -1;
- r445 = open_socket_out_defer_send(ev, ev, timeval_set(0, 0),
- pss, 445, timeout);
- r139 = open_socket_out_defer_send(ev, ev, timeval_set(0, 3000),
- pss, 139, timeout);
- if ((r445 == NULL) || (r139 == NULL)) {
- goto done;
+ called_names = talloc_array(talloc_tos(), const char *, num_addrs);
+ if (called_names == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
}
- tevent_req_set_callback(r445, smb_sock_connected, fd445);
- tevent_req_set_callback(r139, smb_sock_connected, fd139);
-
- while ((fd445->fd == -1) && (fd139->fd == -1)
- && (tevent_req_is_in_progress(r139)
- || tevent_req_is_in_progress(r445))) {
- event_loop_once(ev);
+ called_types = talloc_array(talloc_tos(), int, num_addrs);
+ if (called_types == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
}
-
- if ((fd139->fd != -1) && (fd445->fd != -1)) {
- close(fd139->fd);
- fd139->fd = -1;
+ calling_names = talloc_array(talloc_tos(), const char *, num_addrs);
+ if (calling_names == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
}
-
- if (fd445->fd != -1) {
- *port = 445;
- *pfd = fd445->fd;
- status = NT_STATUS_OK;
- goto done;
+ for (i=0; i<num_addrs; i++) {
+ called_names[i] = host;
+ called_types[i] = name_type;
+ calling_names[i] = myname;
}
- if (fd139->fd != -1) {
- *port = 139;
- *pfd = fd139->fd;
- status = NT_STATUS_OK;
- goto done;
+ status = smbsock_any_connect(pss, called_names, called_types,
+ calling_names, NULL, num_addrs, port,
+ sec_timeout, &fd, NULL, &port);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
}
-
- status = open_socket_out_defer_recv(r445, &fd445->fd);
- done:
- TALLOC_FREE(ev);
+ set_socket_options(fd, lp_socket_options());
+done:
+ *pfd = fd;
+ *pport = port;
+ status = NT_STATUS_OK;
+fail:
+ TALLOC_FREE(frame);
return status;
}
-/****************************************************************************
- Open the client sockets.
-****************************************************************************/
-
-NTSTATUS cli_connect(struct cli_state *cli,
- const char *host,
- struct sockaddr_storage *dest_ss)
-
+NTSTATUS cli_connect_nb(const char *host, struct sockaddr_storage *pss,
+ uint16_t port, int name_type, const char *myname,
+ int signing_state, struct cli_state **pcli)
{
- int name_type = 0x20;
TALLOC_CTX *frame = talloc_stackframe();
- unsigned int num_addrs = 0;
- unsigned int i = 0;
- struct sockaddr_storage *ss_arr = NULL;
- char *p = NULL;
+ struct cli_state *cli;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+ int fd = -1;
+ char *desthost;
+ char *p;
+ socklen_t length;
+ int ret;
- /* reasonable default hostname */
- if (!host) {
- host = STAR_SMBSERVER;
+ desthost = talloc_strdup(talloc_tos(), host);
+ if (desthost == NULL) {
+ goto fail;
}
- fstrcpy(cli->desthost, host);
-
- /* allow hostnames of the form NAME#xx and do a netbios lookup */
- if ((p = strchr(cli->desthost, '#'))) {
+ p = strchr(host, '#');
+ if (p != NULL) {
name_type = strtol(p+1, NULL, 16);
- *p = 0;
- }
-
- if (!dest_ss || is_zero_addr((struct sockaddr *)dest_ss)) {
- NTSTATUS status =resolve_name_list(frame,
- cli->desthost,
- name_type,
- &ss_arr,
- &num_addrs);
- if (!NT_STATUS_IS_OK(status)) {
- TALLOC_FREE(frame);
- return NT_STATUS_BAD_NETWORK_NAME;
- }
- } else {
- num_addrs = 1;
- ss_arr = TALLOC_P(frame, struct sockaddr_storage);
- if (!ss_arr) {
- TALLOC_FREE(frame);
- return NT_STATUS_NO_MEMORY;
+ host = talloc_strndup(talloc_tos(), host, p - host);
+ if (host == NULL) {
+ goto fail;
}
- *ss_arr = *dest_ss;
}
- for (i = 0; i < num_addrs; i++) {
- cli->dest_ss = ss_arr[i];
- if (getenv("LIBSMB_PROG")) {
- cli->fd = sock_exec(getenv("LIBSMB_PROG"));
- } else {
- uint16_t port = cli->port;
- NTSTATUS status;
- status = open_smb_socket(&cli->dest_ss, &port,
- cli->timeout, &cli->fd);
- if (NT_STATUS_IS_OK(status)) {
- cli->port = port;
- }
- }
- if (cli->fd == -1) {
- char addr[INET6_ADDRSTRLEN];
- print_sockaddr(addr, sizeof(addr), &ss_arr[i]);
- DEBUG(2,("Error connecting to %s (%s)\n",
- dest_ss?addr:host,strerror(errno)));
- } else {
- /* Exit from loop on first connection. */
- break;
- }
+ cli = cli_initialise_ex(signing_state);
+ if (cli == NULL) {
+ goto fail;
}
+ cli->desthost = talloc_move(cli, &desthost);
- if (cli->fd == -1) {
- TALLOC_FREE(frame);
- return map_nt_error_from_unix(errno);
+ status = cli_connect_sock(host, name_type, pss, myname, port, 20, &fd,
+ &port);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_shutdown(cli);
+ goto fail;
}
+ cli->fd = fd;
+ cli->port = port;
- if (dest_ss) {
- *dest_ss = cli->dest_ss;
+ length = sizeof(cli->dest_ss);
+ ret = getpeername(fd, (struct sockaddr *)(void *)&cli->dest_ss,
+ &length);
+ if (ret == -1) {
+ status = map_nt_error_from_unix(errno);
+ cli_shutdown(cli);
+ goto fail;
}
- set_socket_options(cli->fd, lp_socket_options());
+ if (pss != NULL) {
+ *pss = cli->dest_ss;
+ }
+ *pcli = cli;
+ status = NT_STATUS_OK;
+fail:
TALLOC_FREE(frame);
- return NT_STATUS_OK;
+ return status;
}
/**
@param dest_host The netbios name of the remote host
@param dest_ss (optional) The the destination IP, NULL for name based lookup
@param port (optional) The destination port (0 for default)
- @param retry bool. Did this connection fail with a retryable error ?
-
*/
NTSTATUS cli_start_connection(struct cli_state **output_cli,
const char *my_name,
const char *dest_host,
struct sockaddr_storage *dest_ss, int port,
- int signing_state, int flags,
- bool *retry)
+ int signing_state, int flags)
{
NTSTATUS nt_status;
- struct nmb_name calling;
- struct nmb_name called;
struct cli_state *cli;
- struct sockaddr_storage ss;
-
- if (retry)
- *retry = False;
- if (!my_name)
- my_name = global_myname();
-
- if (!(cli = cli_initialise_ex(signing_state))) {
- return NT_STATUS_NO_MEMORY;
- }
-
- make_nmb_name(&calling, my_name, 0x0);
- make_nmb_name(&called , dest_host, 0x20);
-
- cli_set_port(cli, port);
- cli_set_timeout(cli, 10000); /* 10 seconds. */
-
- if (dest_ss) {
- ss = *dest_ss;
- } else {
- zero_sockaddr(&ss);
- }
-
-again:
-
- DEBUG(3,("Connecting to host=%s\n", dest_host));
-
- nt_status = cli_connect(cli, dest_host, &ss);
+ nt_status = cli_connect_nb(dest_host, dest_ss, port, 0x20, my_name,
+ signing_state, &cli);
if (!NT_STATUS_IS_OK(nt_status)) {
- char addr[INET6_ADDRSTRLEN];
- print_sockaddr(addr, sizeof(addr), &ss);
- DEBUG(1,("cli_start_connection: failed to connect to %s (%s). Error %s\n",
- nmb_namestr(&called), addr, nt_errstr(nt_status) ));
- cli_shutdown(cli);
+ DEBUG(10, ("cli_connect_nb failed: %s\n",
+ nt_errstr(nt_status)));
return nt_status;
}
- if (retry)
- *retry = True;
-
- if (!cli_session_request(cli, &calling, &called)) {
- char *p;
- DEBUG(1,("session request to %s failed (%s)\n",
- called.name, cli_errstr(cli)));
- if ((p=strchr(called.name, '.')) && !is_ipaddress(called.name)) {
- *p = 0;
- goto again;
- }
- if (strcmp(called.name, STAR_SMBSERVER)) {
- make_nmb_name(&called , STAR_SMBSERVER, 0x20);
- goto again;
- }
- return NT_STATUS_BAD_NETWORK_NAME;
- }
-
if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO)
cli->use_spnego = False;
else if (flags & CLI_FULL_CONNECTION_USE_KERBEROS)
cli->use_kerberos) {
cli->fallback_after_kerberos = true;
}
+ if (flags & CLI_FULL_CONNECTION_USE_CCACHE) {
+ cli->use_ccache = true;
+ }
nt_status = cli_negprot(cli);
if (!NT_STATUS_IS_OK(nt_status)) {
@param user Username, unix string
@param domain User's domain
@param password User's password, unencrypted unix string.
- @param retry bool. Did this connection fail with a retryable error ?
*/
NTSTATUS cli_full_connection(struct cli_state **output_cli,
const char *service, const char *service_type,
const char *user, const char *domain,
const char *password, int flags,
- int signing_state,
- bool *retry)
+ int signing_state)
{
NTSTATUS nt_status;
struct cli_state *cli = NULL;
nt_status = cli_start_connection(&cli, my_name, dest_host,
dest_ss, port, signing_state,
- flags, retry);
+ flags);
if (!NT_STATUS_IS_OK(nt_status)) {
return nt_status;
return NT_STATUS_OK;
}
-/****************************************************************************
- Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
-****************************************************************************/
-
-bool attempt_netbios_session_request(struct cli_state **ppcli, const char *srchost, const char *desthost,
- struct sockaddr_storage *pdest_ss)
-{
- struct nmb_name calling, called;
-
- make_nmb_name(&calling, srchost, 0x0);
-
- /*
- * If the called name is an IP address
- * then use *SMBSERVER immediately.
- */
-
- if(is_ipaddress(desthost)) {
- make_nmb_name(&called, STAR_SMBSERVER, 0x20);
- } else {
- make_nmb_name(&called, desthost, 0x20);
- }
-
- if (!cli_session_request(*ppcli, &calling, &called)) {
- NTSTATUS status;
- struct nmb_name smbservername;
-
- make_nmb_name(&smbservername, STAR_SMBSERVER, 0x20);
-
- /*
- * If the name wasn't *SMBSERVER then
- * try with *SMBSERVER if the first name fails.
- */
-
- if (nmb_name_equal(&called, &smbservername)) {
-
- /*
- * The name used was *SMBSERVER, don't bother with another name.
- */
-
- DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
-with error %s.\n", desthost, cli_errstr(*ppcli) ));
- return False;
- }
-
- /* Try again... */
- cli_shutdown(*ppcli);
-
- *ppcli = cli_initialise();
- if (!*ppcli) {
- /* Out of memory... */
- return False;
- }
-
- status = cli_connect(*ppcli, desthost, pdest_ss);
- if (!NT_STATUS_IS_OK(status) ||
- !cli_session_request(*ppcli, &calling, &smbservername)) {
- DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
-name *SMBSERVER with error %s\n", desthost, cli_errstr(*ppcli) ));
- return False;
- }
- }
-
- return True;
-}
-
/****************************************************************************
Send an old style tcon.
****************************************************************************/
const char *service, const char *pass, const char *dev,
uint16 *max_xmit, uint16 *tid)
{
- char *p;
+ struct tevent_req *req;
+ uint16_t *ret_vwv;
+ uint8_t *bytes;
+ NTSTATUS status;
if (!lp_client_plaintext_auth() && (*pass)) {
DEBUG(1, ("Server requested plaintext password but 'client "
return NT_STATUS_ACCESS_DENIED;
}
- memset(cli->outbuf,'\0',smb_size);
- memset(cli->inbuf,'\0',smb_size);
-
- cli_set_message(cli->outbuf, 0, 0, True);
- SCVAL(cli->outbuf,smb_com,SMBtcon);
- cli_setup_packet(cli);
-
- p = smb_buf(cli->outbuf);
- *p++ = 4; p += clistr_push(cli, p, service, -1, STR_TERMINATE | STR_NOALIGN);
- *p++ = 4; p += clistr_push(cli, p, pass, -1, STR_TERMINATE | STR_NOALIGN);
- *p++ = 4; p += clistr_push(cli, p, dev, -1, STR_TERMINATE | STR_NOALIGN);
-
- cli_setup_bcc(cli, p);
-
- cli_send_smb(cli);
- if (!cli_receive_smb(cli)) {
- return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
- }
-
- if (cli_is_error(cli)) {
- return cli_nt_error(cli);
+ bytes = talloc_array(talloc_tos(), uint8_t, 0);
+ bytes = smb_bytes_push_bytes(bytes, 4, NULL, 0);
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+ service, strlen(service)+1, NULL);
+ bytes = smb_bytes_push_bytes(bytes, 4, NULL, 0);
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+ pass, strlen(pass)+1, NULL);
+ bytes = smb_bytes_push_bytes(bytes, 4, NULL, 0);
+ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
+ dev, strlen(dev)+1, NULL);
+
+ status = cli_smb(talloc_tos(), cli, SMBtcon, 0, 0, NULL,
+ talloc_get_size(bytes), bytes, &req,
+ 2, NULL, &ret_vwv, NULL, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
}
- *max_xmit = SVAL(cli->inbuf, smb_vwv0);
- *tid = SVAL(cli->inbuf, smb_vwv1);
+ *max_xmit = SVAL(ret_vwv + 0, 0);
+ *tid = SVAL(ret_vwv + 1, 0);
return NT_STATUS_OK;
}
lp_workgroup(),
user_info->password ? user_info->password : "",
flags,
- Undefined, NULL);
+ Undefined);
if (NT_STATUS_IS_OK(nt_status)) {
return cli;
*/
struct cli_state *get_ipc_connect_master_ip(TALLOC_CTX *ctx,
- struct ip_service *mb_ip,
+ struct sockaddr_storage *mb_ip,
const struct user_auth_info *user_info,
char **pp_workgroup_out)
{
*pp_workgroup_out = NULL;
- print_sockaddr(addr, sizeof(addr), &mb_ip->ss);
+ print_sockaddr(addr, sizeof(addr), mb_ip);
DEBUG(99, ("Looking up name of master browser %s\n",
addr));
* the original wildcard query as the first choice and fall back to
* MSBROWSE if the wildcard query fails.
*/
- if (!name_status_find("*", 0, 0x1d, &mb_ip->ss, name) &&
- !name_status_find(MSBROWSE, 1, 0x1d, &mb_ip->ss, name)) {
+ if (!name_status_find("*", 0, 0x1d, mb_ip, name) &&
+ !name_status_find(MSBROWSE, 1, 0x1d, mb_ip, name)) {
DEBUG(99, ("Could not retrieve name status for %s\n",
addr));
const struct user_auth_info *user_info,
char **pp_workgroup_out)
{
- struct ip_service *ip_list;
+ struct sockaddr_storage *ip_list;
struct cli_state *cli;
int i, count;
+ NTSTATUS status;
*pp_workgroup_out = NULL;
/* Go looking for workgroups by broadcasting on the local network */
- if (!NT_STATUS_IS_OK(name_resolve_bcast(MSBROWSE, 1, &ip_list,
- &count))) {
- DEBUG(99, ("No master browsers responded\n"));
+ status = name_resolve_bcast(MSBROWSE, 1, talloc_tos(),
+ &ip_list, &count);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(99, ("No master browsers responded: %s\n",
+ nt_errstr(status)));
return False;
}
for (i = 0; i < count; i++) {
char addr[INET6_ADDRSTRLEN];
- print_sockaddr(addr, sizeof(addr), &ip_list[i].ss);
+ print_sockaddr(addr, sizeof(addr), &ip_list[i]);
DEBUG(99, ("Found master browser %s\n", addr));
cli = get_ipc_connect_master_ip(ctx, &ip_list[i],