Unix SMB/CIFS implementation.
client connect/disconnect routines
Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Andrew Barteltt 2001-2002
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
Do an old lanman2 style session setup.
****************************************************************************/
-static BOOL cli_session_setup_lanman2(struct cli_state *cli, char *user,
- char *pass, int passlen, const char *workgroup)
+static BOOL cli_session_setup_lanman2(struct cli_state *cli, const char *user,
+ const char *pass, int passlen, const char *workgroup)
{
fstring pword;
char *p;
- if (passlen > sizeof(pword)-1) {
+ if (passlen > sizeof(pword)-1)
return False;
- }
/* if in share level security then don't send a password now */
- if (!(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL)) {
+ 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. */
show_msg(cli->inbuf);
- if (cli_is_error(cli)) {
+ if (cli_is_error(cli))
return False;
- }
/* use the returned vuid from now on */
cli->vuid = SVAL(cli->inbuf,smb_uid);
{
uint32 capabilities = CAP_NT_SMBS;
- if (!cli->force_dos_errors) {
+ if (!cli->force_dos_errors)
capabilities |= CAP_STATUS32;
- }
- if (cli->use_level_II_oplocks) {
+ if (cli->use_level_II_oplocks)
capabilities |= CAP_LEVEL_II_OPLOCKS;
- }
- if (cli->capabilities & CAP_UNICODE) {
+ if (cli->capabilities & CAP_UNICODE)
capabilities |= CAP_UNICODE;
- }
+
+ if (cli->capabilities & CAP_LARGE_FILES)
+ capabilities |= CAP_LARGE_FILES;
return capabilities;
}
char *p;
uint32 capabilities = cli_session_setup_capabilities(cli);
- /* Guest cannot use SMB signing. */
- cli->sign_info.use_smb_signing = False;
-
set_message(cli->outbuf,13,0,True);
SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
cli_setup_packet(cli);
show_msg(cli->inbuf);
- if (cli_is_error(cli)) {
+ if (cli_is_error(cli))
return False;
- }
cli->vuid = SVAL(cli->inbuf,smb_uid);
Do a NT1 plaintext session setup.
****************************************************************************/
-static BOOL cli_session_setup_plaintext(struct cli_state *cli, char *user,
- char *pass, char *workgroup)
+static BOOL cli_session_setup_plaintext(struct cli_state *cli, const char *user,
+ const char *pass, const char *workgroup)
{
uint32 capabilities = cli_session_setup_capabilities(cli);
- fstring pword;
- int passlen;
char *p;
- passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE|STR_ASCII);
-
set_message(cli->outbuf,13,0,True);
SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
cli_setup_packet(cli);
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,passlen);
SSVAL(cli->outbuf,smb_vwv8,0);
SIVAL(cli->outbuf,smb_vwv11,capabilities);
p = smb_buf(cli->outbuf);
- memcpy(p, pword, passlen);
- p += passlen;
+ p += clistr_push(cli, p, pass, -1, STR_TERMINATE); /* password */
+ SSVAL(cli->outbuf,smb_vwv7,PTR_DIFF(p, smb_buf(cli->outbuf)));
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);
show_msg(cli->inbuf);
- if (cli_is_error(cli)) {
+ if (cli_is_error(cli))
return False;
- }
cli->vuid = SVAL(cli->inbuf,smb_uid);
p = smb_buf(cli->inbuf);
return True;
}
+static void set_signing_on_cli (struct cli_state *cli, const char* pass, uint8 response[24])
+{
+ uint8 zero_sig[8];
+ ZERO_STRUCT(zero_sig);
-/**
+ DEBUG(5, ("Server returned security sig:\n"));
+ dump_data(5, &cli->inbuf[smb_ss_field], 8);
+
+ if (cli->sign_info.use_smb_signing) {
+ DEBUG(5, ("smb signing already active on connection\n"));
+ } else if (memcmp(&cli->inbuf[smb_ss_field], zero_sig, 8) != 0) {
+
+ DEBUG(3, ("smb signing enabled!\n"));
+ cli->sign_info.use_smb_signing = True;
+ cli_calculate_mac_key(cli, pass, response);
+ } else {
+ DEBUG(5, ("smb signing NOT enabled!\n"));
+ }
+}
+
+static void set_temp_signing_on_cli(struct cli_state *cli)
+{
+ if (cli->sign_info.negotiated_smb_signing)
+ cli->sign_info.temp_smb_signing = True;
+}
+
+
+/****************************************************************************
do a NT1 NTLM/LM encrypted session setup
@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.
-*/
+****************************************************************************/
-static BOOL cli_session_setup_nt1(struct cli_state *cli, char *user,
- char *pass, int passlen,
- char *ntpass, int ntpasslen,
- char *workgroup)
+static BOOL cli_session_setup_nt1(struct cli_state *cli, const char *user,
+ const char *pass, int passlen,
+ const char *ntpass, int ntpasslen,
+ const char *workgroup)
{
uint32 capabilities = cli_session_setup_capabilities(cli);
- fstring pword, ntpword;
+ uchar pword[24];
+ uchar ntpword[24];
char *p;
+ BOOL have_plaintext = False;
- if (passlen > sizeof(pword)-1 || ntpasslen > sizeof(ntpword)-1) {
+ if (passlen > sizeof(pword) || ntpasslen > sizeof(ntpword))
return False;
- }
if (passlen != 24) {
/* non encrypted password supplied. Ignore ntpass. */
passlen = 24;
ntpasslen = 24;
- SMBencrypt((uchar *)pass,cli->secblob.data,(uchar *)pword);
- SMBNTencrypt((uchar *)pass,cli->secblob.data,(uchar *)ntpword);
+ SMBencrypt(pass,cli->secblob.data,pword);
+ SMBNTencrypt(pass,cli->secblob.data,ntpword);
+
+ have_plaintext = True;
+ set_temp_signing_on_cli(cli);
} else {
- memcpy(pword, pass, passlen);
- memcpy(ntpword, ntpass, ntpasslen);
+ /* pre-encrypted password supplied. Only used for
+ security=server, can't do
+ signing becouse we don't have oringial key */
+ memcpy(pword, pass, 24);
+ if (ntpasslen == 24)
+ memcpy(ntpword, ntpass, 24);
+ else
+ ZERO_STRUCT(ntpword);
}
/* send a session setup command */
p = smb_buf(cli->outbuf);
memcpy(p,pword,passlen); p += passlen;
memcpy(p,ntpword,ntpasslen); p += ntpasslen;
- 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, user, -1, STR_TERMINATE);
+ p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE);
p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
cli_setup_bcc(cli, p);
- cli_send_smb(cli);
+ if (!cli_send_smb(cli))
+ return False;
+
if (!cli_receive_smb(cli))
return False;
show_msg(cli->inbuf);
- if (cli_is_error(cli)) {
+ if (cli_is_error(cli))
return False;
- }
-
+
/* use the returned vuid from now on */
cli->vuid = SVAL(cli->inbuf,smb_uid);
fstrcpy(cli->user_name, user);
+ if (have_plaintext) {
+ /* Have plaintext orginal */
+ set_signing_on_cli(cli, pass, ntpword);
+ }
+
return True;
}
set_message(cli->outbuf,12,0,True);
SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
+
+ set_temp_signing_on_cli(cli);
+
cli_setup_packet(cli);
SCVAL(cli->outbuf,smb_vwv0,0xFF);
p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
cli_setup_bcc(cli, p);
-
cli_send_smb(cli);
+
if (!cli_receive_smb(cli))
return blob2;
return blob2;
}
-
#ifdef HAVE_KRB5
/****************************************************************************
Do a spnego/kerberos encrypted session setup.
****************************************************************************/
-static BOOL cli_session_setup_kerberos(struct cli_state *cli, char *principal, char *workgroup)
+static BOOL cli_session_setup_kerberos(struct cli_state *cli, const char *principal, const char *workgroup)
{
DATA_BLOB blob2, negTokenTarg;
DEBUG(2,("Doing kerberos session setup\n"));
/* generate the encapsulated kerberos5 ticket */
- negTokenTarg = spnego_gen_negTokenTarg(cli, principal);
+ negTokenTarg = spnego_gen_negTokenTarg(principal, 0);
if (!negTokenTarg.data) return False;
Do a spnego/NTLMSSP encrypted session setup.
****************************************************************************/
-static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, char *user,
- char *pass, char *workgroup)
+static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, const char *user,
+ const char *pass, const char *workgroup)
{
- const char *mechs[] = {OID_NTLMSSP, NULL};
- DATA_BLOB msg1;
- DATA_BLOB blob, chal1, chal2, auth;
+ DATA_BLOB msg1, struct_blob;
+ DATA_BLOB blob, chal1, chal2, auth, challenge_blob;
uint8 challenge[8];
uint8 nthash[24], lmhash[24], sess_key[16];
- uint32 neg_flags;
+ uint32 neg_flags, chal_flags, ntlmssp_command, unkn1, unkn2;
+ pstring server_domain; /* FIX THIS, SHOULD be UCS2-LE */
neg_flags = NTLMSSP_NEGOTIATE_UNICODE |
- NTLMSSP_NEGOTIATE_LM_KEY |
- NTLMSSP_NEGOTIATE_NTLM;
+ NTLMSSP_NEGOTIATE_128 |
+ NTLMSSP_NEGOTIATE_NTLM |
+ NTLMSSP_REQUEST_TARGET;
memset(sess_key, 0, 16);
+ DEBUG(10, ("sending NTLMSSP_NEGOTIATE\n"));
+
/* generate the ntlmssp negotiate packet */
- msrpc_gen(&blob, "CddB",
+ msrpc_gen(&blob, "CddAA",
"NTLMSSP",
NTLMSSP_NEGOTIATE,
neg_flags,
- sess_key, 16);
-
+ workgroup,
+ cli->calling.name);
+ DEBUG(10, ("neg_flags: %0X, workgroup: %s, calling name %s\n",
+ neg_flags, workgroup, cli->calling.name));
/* and wrap it in a SPNEGO wrapper */
- msg1 = gen_negTokenTarg(mechs, blob);
+ msg1 = gen_negTokenInit(OID_NTLMSSP, blob);
data_blob_free(&blob);
/* now send that blob on its way */
data_blob_free(&msg1);
- if (!NT_STATUS_EQUAL(cli_nt_error(cli), NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ if (!NT_STATUS_EQUAL(cli_nt_error(cli), NT_STATUS_MORE_PROCESSING_REQUIRED))
return False;
- }
#if 0
file_save("chal.dat", blob.data, blob.length);
data_blob_free(&blob);
- /* encrypt the password with the challenge */
- memcpy(challenge, chal1.data + 24, 8);
- SMBencrypt((unsigned char *)pass, challenge,lmhash);
- SMBNTencrypt((unsigned char *)pass, challenge,nthash);
+ /*
+ * Ok, chal1 and chal2 are actually two identical copies of
+ * the NTLMSSP Challenge BLOB, and they contain, encoded in them
+ * the challenge to use.
+ */
+
+ if (!msrpc_parse(&chal1, "CdUdbddB",
+ "NTLMSSP",
+ &ntlmssp_command,
+ &server_domain,
+ &chal_flags,
+ &challenge_blob, 8,
+ &unkn1, &unkn2,
+ &struct_blob)) {
+ DEBUG(0, ("Failed to parse the NTLMSSP Challenge\n"));
+ return False;
+ }
+
+ if (ntlmssp_command != NTLMSSP_CHALLENGE) {
+ DEBUG(0, ("NTLMSSP Response != NTLMSSP_CHALLENGE. Got %0X\n",
+ ntlmssp_command));
+ return False;
+ }
+
+ DEBUG(10, ("Challenge:\n"));
+ dump_data(10, challenge_blob.data, 8);
+
+ /* encrypt the password with the challenge which is in the blob */
+ memcpy(challenge, challenge_blob.data, 8);
+ SMBencrypt(pass, challenge,lmhash);
+ SMBNTencrypt(pass, challenge,nthash);
+ data_blob_free(&challenge_blob);
#if 0
file_save("nthash.dat", nthash, 24);
workgroup,
user,
cli->calling.name,
- sess_key, 16,
+ sess_key, 0,
neg_flags);
/* wrap it in SPNEGO */
data_blob_free(&auth);
data_blob_free(&blob);
- return !cli_is_error(cli);
+ if (cli_is_error(cli))
+ return False;
+
+ set_signing_on_cli(cli, pass, nthash);
+
+ return True;
}
/****************************************************************************
Do a spnego encrypted session setup.
****************************************************************************/
-static BOOL cli_session_setup_spnego(struct cli_state *cli, char *user,
- char *pass, char *workgroup)
+static BOOL cli_session_setup_spnego(struct cli_state *cli, const char *user,
+ const char *pass, const char *workgroup)
{
char *principal;
char *OIDs[ASN1_MAX_OIDS];
- uint8 guid[16];
int i;
BOOL got_kerberos_mechanism = False;
+ DATA_BLOB blob;
DEBUG(2,("Doing spnego session setup (blob length=%d)\n", cli->secblob.length));
/* the server might not even do spnego */
- if (cli->secblob.length == 16) {
+ if (cli->secblob.length <= 16) {
DEBUG(3,("server didn't supply a full spnego negprot\n"));
goto ntlmssp;
}
file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
#endif
+ /* there is 16 bytes of GUID before the real spnego packet starts */
+ blob = data_blob(cli->secblob.data+16, cli->secblob.length-16);
+
/* the server sent us the first part of the SPNEGO exchange in the negprot
reply */
- if (!spnego_parse_negTokenInit(cli->secblob, guid, OIDs, &principal)) {
+ if (!spnego_parse_negTokenInit(blob, OIDs, &principal)) {
+ data_blob_free(&blob);
return False;
}
+ data_blob_free(&blob);
/* make sure the server understands kerberos */
for (i=0;OIDs[i];i++) {
****************************************************************************/
BOOL cli_session_setup(struct cli_state *cli,
- char *user,
- char *pass, int passlen,
- char *ntpass, int ntpasslen,
- char *workgroup)
+ const char *user,
+ const char *pass, int passlen,
+ const char *ntpass, int ntpasslen,
+ const char *workgroup)
{
char *p;
fstring user2;
flow a bit easier to understand (tridge) */
/* if its an older server then we have to use the older request format */
- if (cli->protocol < PROTOCOL_NT1) {
+
+ if (cli->protocol < PROTOCOL_NT1)
return cli_session_setup_lanman2(cli, user, pass, passlen, workgroup);
- }
/* if no user is supplied then we have to do an anonymous connection.
passwords are ignored */
- if (!user || !*user) {
+
+ if (!user || !*user)
return cli_session_setup_guest(cli);
- }
/* if the server is share level then send a plaintext null
password at this point. The password is sent in the tree
connect */
- if ((cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) == 0) {
+
+ if ((cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) == 0)
return cli_session_setup_plaintext(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 ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0)
return cli_session_setup_plaintext(cli, user, pass, workgroup);
- }
+ /* Indidicate signing */
+
/* if the server supports extended security then use SPNEGO */
- if (cli->capabilities & CAP_EXTENDED_SECURITY) {
+
+ if (cli->capabilities & CAP_EXTENDED_SECURITY)
return cli_session_setup_spnego(cli, user, pass, workgroup);
- }
/* otherwise do a NT1 style session setup */
+
return cli_session_setup_nt1(cli, user,
pass, passlen, ntpass, ntpasslen,
workgroup);
BOOL cli_ulogoff(struct cli_state *cli)
{
- memset(cli->outbuf,'\0',smb_size);
- set_message(cli->outbuf,2,0,True);
- SCVAL(cli->outbuf,smb_com,SMBulogoffX);
- cli_setup_packet(cli);
+ memset(cli->outbuf,'\0',smb_size);
+ 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 */
- cli_send_smb(cli);
- if (!cli_receive_smb(cli))
- return False;
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli))
+ return False;
- return !cli_is_error(cli);
+ return !cli_is_error(cli);
}
/****************************************************************************
BOOL cli_send_tconX(struct cli_state *cli,
const char *share, const char *dev, const char *pass, int passlen)
{
- fstring fullshare, pword, dos_pword;
+ fstring fullshare, pword;
char *p;
memset(cli->outbuf,'\0',smb_size);
memset(cli->inbuf,'\0',smb_size);
* Non-encrypted passwords - convert to DOS codepage before encryption.
*/
passlen = 24;
- clistr_push(cli, dos_pword, pass, -1, STR_TERMINATE);
- SMBencrypt((uchar *)dos_pword,cli->secblob.data,(uchar *)pword);
+ SMBencrypt(pass,cli->secblob.data,(uchar *)pword);
} else {
if((cli->sec_mode & (NEGOTIATE_SECURITY_USER_LEVEL|NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)) == 0) {
/*
if (!cli_receive_smb(cli))
return False;
- if (cli_is_error(cli)) {
+ if (cli_is_error(cli))
return False;
- }
clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE|STR_ASCII);
- if (strcasecmp(share,"IPC$")==0) {
+ if (strcasecmp(share,"IPC$")==0)
fstrcpy(cli->dev, "IPC");
- }
if (cli->protocol >= PROTOCOL_NT1 &&
smb_buflen(cli->inbuf) == 3) {
char *p;
int numprots;
- if (cli->protocol < PROTOCOL_NT1) {
+ if (cli->protocol < PROTOCOL_NT1)
cli->use_spnego = False;
- }
memset(cli->outbuf,'\0',smb_size);
int numprots;
int plength;
- if (cli->protocol < PROTOCOL_NT1) {
- cli->use_spnego = False;
+ if (cli->sign_info.use_smb_signing) {
+ DEBUG(0, ("Cannot send negprot again, particularly after setting up SMB Signing\n"));
+ return False;
}
+ if (cli->protocol < PROTOCOL_NT1)
+ cli->use_spnego = False;
+
memset(cli->outbuf,'\0',smb_size);
/* setup the protocol strings */
smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
}
- /* A way to attempt to force SMB signing */
- if (getenv("CLI_FORCE_SMB_SIGNING"))
- cli->sign_info.use_smb_signing = True;
-
- if (cli->sign_info.use_smb_signing && !(cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED))
- cli->sign_info.use_smb_signing = False;
+ if ((cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED))
+ cli->sign_info.negotiated_smb_signing = True;
} else if (cli->protocol >= PROTOCOL_LANMAN1) {
cli->use_spnego = False;
cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
- cli->sign_info.use_smb_signing = False;
} else {
/* the old core protocol */
cli->use_spnego = False;
cli->sec_mode = 0;
cli->serverzone = TimeDiff(time(NULL));
- cli->sign_info.use_smb_signing = False;
}
cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
/* a way to force ascii SMB */
- if (getenv("CLI_FORCE_ASCII")) {
+ if (getenv("CLI_FORCE_ASCII"))
cli->capabilities &= ~CAP_UNICODE;
- }
return True;
}
int len = 4;
extern pstring user_socket_options;
- /* 445 doesn't have session request */
- if (cli->port == 445) return True;
-
- /* send a session request (RFC 1002) */
memcpy(&(cli->calling), calling, sizeof(*calling));
memcpy(&(cli->called ), called , sizeof(*called ));
name_mangle(cli->calling.name, p, cli->calling.name_type);
len += name_len(p);
- /* setup the packet length */
+ /* 445 doesn't have session request */
+ if (cli->port == 445)
+ return True;
+
+ if (cli->sign_info.use_smb_signing) {
+ DEBUG(0, ("Cannot send session resquest again, particularly after setting up SMB Signing\n"));
+ return False;
+ }
+
+ /* 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->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
port, cli->timeout);
}
- if (cli->fd != -1) cli->port = port;
+ if (cli->fd != -1)
+ cli->port = port;
}
if (cli->fd == -1) {
DEBUG(1,("Error connecting to %s (%s)\n",
- inet_ntoa(*ip),strerror(errno)));
+ ip?inet_ntoa(*ip):host,strerror(errno)));
return False;
}
Initialise client credentials for authenticated pipe access.
****************************************************************************/
-static void init_creds(struct ntuser_creds *creds, char* username,
- char* domain, char* password)
+static void init_creds(struct ntuser_creds *creds, const char* username,
+ const char* domain, const char* password)
{
ZERO_STRUCTP(creds);
}
}
-/****************************************************************************
- Establishes a connection right up to doing tconX, password specified.
-****************************************************************************/
+/**
+ establishes a connection right up to doing tconX, password specified.
+ @param output_cli A fully initialised cli structure, non-null only on success
+ @param dest_host The netbios name of the remote host
+ @param dest_ip (optional) The the destination IP, NULL for name based lookup
+ @param port (optional) The destination port (0 for default)
+ @param service (optional) The share to make the connection to. Should be 'unqualified' in any way.
+ @param service_type The 'type' of serivice.
+ @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 *my_name, const char *dest_host,
+ const char *my_name,
+ const char *dest_host,
struct in_addr *dest_ip, int port,
- char *service, char *service_type,
- char *user, char *domain,
- char *password)
+ const char *service, const char *service_type,
+ const char *user, const char *domain,
+ const char *password, int flags,
+ BOOL *retry)
{
struct ntuser_creds creds;
NTSTATUS nt_status;
struct nmb_name called;
struct cli_state *cli;
struct in_addr ip;
-
- if (!output_cli)
- DEBUG(0, ("output_cli is NULL!?!"));
- *output_cli = NULL;
-
- make_nmb_name(&calling, my_name, 0x0);
- make_nmb_name(&called , dest_host, 0x20);
-
-again:
+ if (retry)
+ *retry = False;
+ if (!my_name)
+ my_name = global_myname();
+
if (!(cli = cli_initialise(NULL)))
return NT_STATUS_NO_MEMORY;
+ make_nmb_name(&calling, my_name, 0x0);
+ make_nmb_name(&called , dest_host, 0x20);
+
if (cli_set_port(cli, port) != port) {
cli_shutdown(cli);
return NT_STATUS_UNSUCCESSFUL;
}
- ip = *dest_ip;
-
+ cli_set_timeout(cli, 10000); /* 10 seconds. */
+
+ if (dest_ip)
+ ip = *dest_ip;
+ else
+ ZERO_STRUCT(ip);
+
+again:
+
DEBUG(3,("Connecting to host=%s share=%s\n", dest_host, service));
if (!cli_connect(cli, dest_host, &ip)) {
DEBUG(1,("cli_full_connection: failed to connect to %s (%s)\n",
- nmb_namestr(&called), inet_ntoa(*dest_ip)));
+ nmb_namestr(&called), inet_ntoa(ip)));
cli_shutdown(cli);
return NT_STATUS_UNSUCCESSFUL;
}
+ 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)));
- cli_shutdown(cli);
- if ((p=strchr(called.name, '.'))) {
+ if ((p=strchr(called.name, '.')) && !is_ipaddress(called.name)) {
*p = 0;
goto again;
}
return NT_STATUS_UNSUCCESSFUL;
}
+ if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO)
+ cli->use_spnego = False;
+ else if (flags & CLI_FULL_CONNECTION_USE_KERBEROS)
+ cli->use_kerberos = True;
+
if (!cli_negprot(cli)) {
DEBUG(1,("failed negprot\n"));
nt_status = NT_STATUS_UNSUCCESSFUL;
if (!cli_session_setup(cli, user, password, strlen(password)+1,
password, strlen(password)+1,
domain)) {
- DEBUG(1,("failed session setup\n"));
- nt_status = cli_nt_error(cli);
- cli_shutdown(cli);
- if (NT_STATUS_IS_OK(nt_status))
- nt_status = NT_STATUS_UNSUCCESSFUL;
- return nt_status;
+ if ((flags & CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK)
+ && cli_session_setup(cli, "", "", 0, "", 0, domain)) {
+ } else {
+ nt_status = cli_nt_error(cli);
+ DEBUG(1,("failed session setup with %s\n", nt_errstr(nt_status)));
+ cli_shutdown(cli);
+ if (NT_STATUS_IS_OK(nt_status))
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ return nt_status;
+ }
}
if (service) {
if (!cli_send_tconX(cli, service, service_type,
- (char*)password, strlen(password)+1)) {
- DEBUG(1,("failed tcon_X\n"));
+ password, strlen(password)+1)) {
nt_status = cli_nt_error(cli);
+ DEBUG(1,("failed tcon_X with %s\n", nt_errstr(nt_status)));
cli_shutdown(cli);
if (NT_STATUS_IS_OK(nt_status)) {
nt_status = NT_STATUS_UNSUCCESSFUL;
Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
****************************************************************************/
-BOOL attempt_netbios_session_request(struct cli_state *cli, char *srchost, char *desthost,
+BOOL attempt_netbios_session_request(struct cli_state *cli, const char *srchost, const char *desthost,
struct in_addr *pdest_ip)
{
struct nmb_name calling, called;
DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
with error %s.\n", desthost, cli_errstr(cli) ));
- cli_shutdown(cli);
return False;
}
- cli_shutdown(cli);
+ /*
+ * We need to close the connection here but can't call cli_shutdown as
+ * will free an allocated cli struct. cli_close_connection was invented
+ * for this purpose. JRA. Based on work by "Kim R. Pedersen" <krp@filanet.dk>.
+ */
+
+ cli_close_connection(cli);
if (!cli_initialise(cli) ||
!cli_connect(cli, desthost, pdest_ip) ||
!cli_session_request(cli, &calling, &smbservername)) {
DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) ));
- cli_shutdown(cli);
return False;
}
}