summaryrefslogtreecommitdiff
path: root/source3/libsmb
diff options
context:
space:
mode:
Diffstat (limited to 'source3/libsmb')
-rw-r--r--source3/libsmb/cliconnect.c113
-rw-r--r--source3/libsmb/clientgen.c45
-rw-r--r--source3/libsmb/clifile.c4
-rw-r--r--source3/libsmb/clikrb5.c30
-rw-r--r--source3/libsmb/climessage.c38
-rw-r--r--source3/libsmb/clirap.c4
-rw-r--r--source3/libsmb/clirap2.c4
-rw-r--r--source3/libsmb/clispnego.c2
-rw-r--r--source3/libsmb/namecache.c111
-rw-r--r--source3/libsmb/namequery.c756
-rw-r--r--source3/libsmb/namequery_dc.c128
-rw-r--r--source3/libsmb/nmblib.c4
-rw-r--r--source3/libsmb/ntlmssp.c120
-rw-r--r--source3/libsmb/ntlmssp_parse.c75
-rw-r--r--source3/libsmb/ntlmssp_sign.c206
-rw-r--r--source3/libsmb/pwd_cache.c14
-rw-r--r--source3/libsmb/smb_signing.c270
-rw-r--r--source3/libsmb/smbencrypt.c157
-rw-r--r--source3/libsmb/trustdom_cache.c129
-rw-r--r--source3/libsmb/trusts_util.c95
20 files changed, 1508 insertions, 797 deletions
diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c
index 32397173da..fa9af19bf5 100644
--- a/source3/libsmb/cliconnect.c
+++ b/source3/libsmb/cliconnect.c
@@ -270,28 +270,41 @@ static BOOL cli_session_setup_nt1(struct cli_state *cli, const char *user,
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 (!SMBNTLMv2encrypt(user, workgroup, pass, server_chal,
+ /* 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(cli->called.name, workgroup);
+
+ if (!SMBNTLMv2encrypt(user, workgroup, pass, &server_chal,
+ &names_blob,
&lm_response, &nt_response, &session_key)) {
+ data_blob_free(&names_blob);
data_blob_free(&server_chal);
return False;
}
+ data_blob_free(&names_blob);
data_blob_free(&server_chal);
} else {
uchar nt_hash[16];
E_md4hash(pass, nt_hash);
+ nt_response = data_blob(NULL, 24);
+ SMBNTencrypt(pass,cli->secblob.data,nt_response.data);
+
/* non encrypted password supplied. Ignore ntpass. */
if (lp_client_lanman_auth()) {
lm_response = data_blob(NULL, 24);
- SMBencrypt(pass,cli->secblob.data,lm_response.data);
+ SMBencrypt(pass,cli->secblob.data, lm_response.data);
+ } else {
+ /* LM disabled, place NT# in LM feild instead */
+ lm_response = data_blob(nt_response.data, nt_response.length);
}
- nt_response = data_blob(NULL, 24);
- SMBNTencrypt(pass,cli->secblob.data,nt_response.data);
session_key = data_blob(NULL, 16);
SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data);
}
@@ -440,6 +453,8 @@ static DATA_BLOB cli_session_setup_blob_receive(struct cli_state *cli)
return blob2;
}
+#ifdef HAVE_KRB5
+
/****************************************************************************
Send a extended security session setup blob, returning a reply blob.
****************************************************************************/
@@ -454,7 +469,6 @@ static DATA_BLOB cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob)
return cli_session_setup_blob_receive(cli);
}
-#ifdef HAVE_KRB5
/****************************************************************************
Use in-memory credentials cache
****************************************************************************/
@@ -490,7 +504,8 @@ static BOOL cli_session_setup_kerberos(struct cli_state *cli, const char *princi
return !cli_is_error(cli);
}
-#endif
+#endif /* HAVE_KRB5 */
+
/****************************************************************************
Do a spnego/NTLMSSP encrypted session setup.
@@ -525,11 +540,18 @@ static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, const char *user,
ntlmssp_state->use_ntlmv2 = lp_client_ntlmv2_auth();
+ if (cli->sign_info.negotiated_smb_signing
+ || cli->sign_info.mandatory_signing) {
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
+ }
+
do {
nt_status = ntlmssp_client_update(ntlmssp_state,
blob_in, &blob_out);
data_blob_free(&blob_in);
if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ DATA_BLOB null = data_blob(NULL, 0);
if (turn == 1) {
/* and wrap it in a SPNEGO wrapper */
msg1 = gen_negTokenInit(OID_NTLMSSP, blob_out);
@@ -538,14 +560,16 @@ static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, const char *user,
msg1 = spnego_gen_auth(blob_out);
}
+ cli_simple_set_signing(cli,
+ ntlmssp_state->session_key.data,
+ null);
+
/* now send that blob on its way */
if (!cli_session_setup_blob_send(cli, msg1)) {
return False;
}
data_blob_free(&msg1);
- cli_ntlmssp_set_signing(cli, ntlmssp_state);
-
blob = cli_session_setup_blob_receive(cli);
nt_status = cli_nt_error(cli);
@@ -566,7 +590,6 @@ static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, const char *user,
}
data_blob_free(&tmp_blob);
} else {
- /* the server might give us back two challenges */
if (!spnego_parse_auth_response(blob, nt_status,
&blob_in)) {
DEBUG(3,("Failed to parse auth response\n"));
@@ -704,8 +727,22 @@ BOOL cli_session_setup(struct cli_state *cli,
/* if its an older server then we have to use the older request format */
- if (cli->protocol < PROTOCOL_NT1)
+ 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"));
+ return False;
+ }
+
+ if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0 &&
+ !lp_client_plaintext_auth() && (*pass)) {
+ DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'"
+ " is disabled\n"));
+ return False;
+ }
+
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 */
@@ -717,17 +754,21 @@ BOOL cli_session_setup(struct cli_state *cli,
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) {
+ if (!lp_client_plaintext_auth() && (*pass)) {
+ DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'"
+ " is disabled\n"));
+ return False;
+ }
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)
@@ -780,6 +821,12 @@ BOOL cli_send_tconX(struct cli_state *cli,
}
if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && *pass && passlen != 24) {
+ if (!lp_client_lanman_auth()) {
+ DEBUG(1, ("Server requested LANMAN password but 'client use lanman auth'"
+ " is disabled\n"));
+ return False;
+ }
+
/*
* Non-encrypted passwords - convert to DOS codepage before encryption.
*/
@@ -787,10 +834,17 @@ BOOL cli_send_tconX(struct cli_state *cli,
SMBencrypt(pass,cli->secblob.data,(uchar *)pword);
} else {
if((cli->sec_mode & (NEGOTIATE_SECURITY_USER_LEVEL|NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)) == 0) {
+ if (!lp_client_plaintext_auth() && (*pass)) {
+ DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'"
+ " is disabled\n"));
+ return False;
+ }
+
/*
* Non-encrypted passwords - convert to DOS codepage before using.
*/
passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
+
} else {
memcpy(pword, pass, passlen);
}
@@ -823,9 +877,6 @@ BOOL cli_send_tconX(struct cli_state *cli,
clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE|STR_ASCII);
- if (strcasecmp(share,"IPC$")==0)
- fstrcpy(cli->dev, "IPC");
-
if (cli->protocol >= PROTOCOL_NT1 &&
smb_buflen(cli->inbuf) == 3) {
/* almost certainly win95 - enable bug fixes */
@@ -962,12 +1013,24 @@ BOOL cli_negprot(struct cli_state *cli)
smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
}
- if ((cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED))
+ if ((cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED)) {
+ /* Fail if signing is mandatory and we don't want to support it. */
+ if (!lp_client_signing()) {
+ DEBUG(1,("cli_negprot: SMB signing is mandatory and we have disabled it.\n"));
+ return False;
+ }
cli->sign_info.negotiated_smb_signing = True;
+ }
if ((cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) && cli->sign_info.allow_smb_signing)
cli->sign_info.negotiated_smb_signing = True;
+ /* Fail if signing is mandatory and the server doesn't support it. */
+ if (cli->sign_info.mandatory_signing && !(cli->sign_info.negotiated_smb_signing)) {
+ DEBUG(1,("cli_negprot: SMB signing is mandatory and the server doesn't support it.\n"));
+ return False;
+ }
+
} else if (cli->protocol >= PROTOCOL_LANMAN1) {
cli->use_spnego = False;
cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
@@ -1369,6 +1432,12 @@ NTSTATUS cli_raw_tcon(struct cli_state *cli,
{
char *p;
+ if (!lp_client_plaintext_auth() && (*pass)) {
+ DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'"
+ " is disabled\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
memset(cli->outbuf,'\0',smb_size);
memset(cli->inbuf,'\0',smb_size);
@@ -1433,7 +1502,7 @@ struct cli_state *get_ipc_connect(char *server, struct in_addr *server_ip,
struct cli_state *get_ipc_connect_master_ip_bcast(pstring workgroup, struct user_auth_info *user_info)
{
- struct in_addr *ip_list;
+ struct ip_service *ip_list;
struct cli_state *cli;
int i, count;
struct in_addr server_ip;
@@ -1447,7 +1516,7 @@ struct cli_state *get_ipc_connect_master_ip_bcast(pstring workgroup, struct user
for (i = 0; i < count; i++) {
static fstring name;
- if (!name_status_find("*", 0, 0x1d, ip_list[i], name))
+ if (!name_status_find("*", 0, 0x1d, ip_list[i].ip, name))
continue;
if (!find_master_ip(name, &server_ip))
@@ -1456,7 +1525,7 @@ struct cli_state *get_ipc_connect_master_ip_bcast(pstring workgroup, struct user
pstrcpy(workgroup, name);
DEBUG(4, ("found master browser %s, %s\n",
- name, inet_ntoa(ip_list[i])));
+ name, inet_ntoa(ip_list[i].ip)));
cli = get_ipc_connect(inet_ntoa(server_ip), &server_ip, user_info);
diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c
index 8d4e8a266c..58c5ad8cd3 100644
--- a/source3/libsmb/clientgen.c
+++ b/source3/libsmb/clientgen.c
@@ -203,12 +203,9 @@ void cli_init_creds(struct cli_state *cli, const struct ntuser_creds *usr)
fstrcpy(cli->domain , usr->domain);
fstrcpy(cli->user_name, usr->user_name);
memcpy(&cli->pwd, &usr->pwd, sizeof(usr->pwd));
- cli->ntlmssp_flags = usr->ntlmssp_flags;
- cli->ntlmssp_cli_flgs = usr != NULL ? usr->ntlmssp_flags : 0;
- DEBUG(10,("cli_init_creds: user %s domain %s flgs: %x\nntlmssp_cli_flgs:%x\n",
- cli->user_name, cli->domain,
- cli->ntlmssp_flags,cli->ntlmssp_cli_flgs));
+ DEBUG(10,("cli_init_creds: user %s domain %s\n",
+ cli->user_name, cli->domain));
}
/****************************************************************************
@@ -264,6 +261,9 @@ struct cli_state *cli_initialise(struct cli_state *cli)
if (lp_client_signing())
cli->sign_info.allow_smb_signing = True;
+
+ if (lp_client_signing() == Required)
+ cli->sign_info.mandatory_signing = True;
if (!cli->outbuf || !cli->inbuf)
goto error;
@@ -287,6 +287,8 @@ struct cli_state *cli_initialise(struct cli_state *cli)
cli->initialised = 1;
cli->allocated = alloced_cli;
+ cli->pipe_idx = -1;
+
return cli;
/* Clean up after malloc() error */
@@ -303,17 +305,50 @@ struct cli_state *cli_initialise(struct cli_state *cli)
}
/****************************************************************************
+close the session
+****************************************************************************/
+
+void cli_nt_session_close(struct cli_state *cli)
+{
+ if (cli->ntlmssp_pipe_state) {
+ ntlmssp_client_end(&cli->ntlmssp_pipe_state);
+ }
+
+ cli_close(cli, cli->nt_pipe_fnum);
+ cli->nt_pipe_fnum = 0;
+ cli->pipe_idx = -1;
+}
+
+/****************************************************************************
+close the NETLOGON session holding the session key for NETSEC
+****************************************************************************/
+
+void cli_nt_netlogon_netsec_session_close(struct cli_state *cli)
+{
+ if (cli->saved_netlogon_pipe_fnum != 0) {
+ cli_close(cli, cli->saved_netlogon_pipe_fnum);
+ cli->saved_netlogon_pipe_fnum = 0;
+ }
+}
+
+/****************************************************************************
Close a client connection and free the memory without destroying cli itself.
****************************************************************************/
void cli_close_connection(struct cli_state *cli)
{
+ cli_nt_session_close(cli);
+ cli_nt_netlogon_netsec_session_close(cli);
+
SAFE_FREE(cli->outbuf);
SAFE_FREE(cli->inbuf);
cli_free_signing_context(cli);
data_blob_free(&cli->secblob);
+ if (cli->ntlmssp_pipe_state)
+ ntlmssp_client_end(&cli->ntlmssp_pipe_state);
+
if (cli->mem_ctx) {
talloc_destroy(cli->mem_ctx);
cli->mem_ctx = NULL;
diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c
index b771e135f4..f021076a46 100644
--- a/source3/libsmb/clifile.c
+++ b/source3/libsmb/clifile.c
@@ -600,8 +600,8 @@ NTSTATUS cli_locktype(struct cli_state *cli, int fnum,
/****************************************************************************
Lock a file.
+ note that timeout is in units of 2 milliseconds
****************************************************************************/
-
BOOL cli_lock(struct cli_state *cli, int fnum,
uint32 offset, uint32 len, int timeout, enum brl_type lock_type)
{
@@ -636,7 +636,7 @@ BOOL cli_lock(struct cli_state *cli, int fnum,
cli_send_smb(cli);
if (timeout != 0) {
- cli->timeout = (timeout == -1) ? 0x7FFFFFFF : (timeout + 10*1000);
+ cli->timeout = (timeout == -1) ? 0x7FFFFFFF : (timeout*2 + 5*1000);
}
if (!cli_receive_smb(cli)) {
diff --git a/source3/libsmb/clikrb5.c b/source3/libsmb/clikrb5.c
index 5edc56daa9..fd5dd91325 100644
--- a/source3/libsmb/clikrb5.c
+++ b/source3/libsmb/clikrb5.c
@@ -235,12 +235,12 @@ krb5_error_code get_kerberos_allowed_etypes(krb5_context context,
/*
we can't use krb5_mk_req because w2k wants the service to be in a particular format
*/
-static krb5_error_code krb5_mk_req2(krb5_context context,
- krb5_auth_context *auth_context,
- const krb5_flags ap_req_options,
- const char *principal,
- krb5_ccache ccache,
- krb5_data *outbuf)
+static krb5_error_code ads_krb5_mk_req(krb5_context context,
+ krb5_auth_context *auth_context,
+ const krb5_flags ap_req_options,
+ const char *principal,
+ krb5_ccache ccache,
+ krb5_data *outbuf)
{
krb5_error_code retval;
krb5_principal server;
@@ -255,7 +255,7 @@ static krb5_error_code krb5_mk_req2(krb5_context context,
}
/* obtain ticket & session key */
- memset((char *)&creds, 0, sizeof(creds));
+ ZERO_STRUCT(creds);
if ((retval = krb5_copy_principal(context, server, &creds.server))) {
DEBUG(1,("krb5_copy_principal failed (%s)\n",
error_message(retval)));
@@ -305,7 +305,7 @@ cleanup_princ:
/*
get a kerberos5 ticket for the given service
*/
-DATA_BLOB krb5_get_ticket(const char *principal, time_t time_offset)
+DATA_BLOB cli_krb5_get_ticket(const char *principal, time_t time_offset)
{
krb5_error_code retval;
krb5_data packet;
@@ -344,11 +344,11 @@ DATA_BLOB krb5_get_ticket(const char *principal, time_t time_offset)
goto failed;
}
- if ((retval = krb5_mk_req2(context,
- &auth_context,
- 0,
- principal,
- ccdef, &packet))) {
+ if ((retval = ads_krb5_mk_req(context,
+ &auth_context,
+ 0,
+ principal,
+ ccdef, &packet))) {
goto failed;
}
@@ -365,7 +365,7 @@ failed:
return data_blob(NULL, 0);
}
- BOOL krb5_get_smb_session_key(krb5_context context, krb5_auth_context auth_context, uint8 session_key[16])
+ BOOL get_krb5_smb_session_key(krb5_context context, krb5_auth_context auth_context, uint8 session_key[16])
{
#ifdef ENCTYPE_ARCFOUR_HMAC
krb5_keyblock *skey;
@@ -390,7 +390,7 @@ failed:
}
#else /* HAVE_KRB5 */
/* this saves a few linking headaches */
-DATA_BLOB krb5_get_ticket(const char *principal, time_t time_offset)
+DATA_BLOB cli_krb5_get_ticket(const char *principal, time_t time_offset)
{
DEBUG(0,("NO KERBEROS SUPPORT\n"));
return data_blob(NULL, 0);
diff --git a/source3/libsmb/climessage.c b/source3/libsmb/climessage.c
index 2b1be75089..8ce8416487 100644
--- a/source3/libsmb/climessage.c
+++ b/source3/libsmb/climessage.c
@@ -26,12 +26,11 @@
/****************************************************************************
start a message sequence
****************************************************************************/
-BOOL cli_message_start(struct cli_state *cli, char *host, char *username,
- int *grp)
+int cli_message_start_build(struct cli_state *cli, char *host, char *username)
{
char *p;
- /* send a SMBsendstrt command */
+ /* construct a SMBsendstrt command */
memset(cli->outbuf,'\0',smb_size);
set_message(cli->outbuf,0,0,True);
SCVAL(cli->outbuf,smb_com,SMBsendstrt);
@@ -45,6 +44,14 @@ BOOL cli_message_start(struct cli_state *cli, char *host, char *username,
p += clistr_push(cli, p, host, -1, STR_ASCII|STR_TERMINATE);
cli_setup_bcc(cli, p);
+
+ return(PTR_DIFF(p, cli->outbuf));
+}
+
+BOOL cli_message_start(struct cli_state *cli, char *host, char *username,
+ int *grp)
+{
+ cli_message_start_build(cli, host, username);
cli_send_smb(cli);
@@ -63,7 +70,7 @@ BOOL cli_message_start(struct cli_state *cli, char *host, char *username,
/****************************************************************************
send a message
****************************************************************************/
-BOOL cli_message_text(struct cli_state *cli, char *msg, int len, int grp)
+int cli_message_text_build(struct cli_state *cli, char *msg, int len, int grp)
{
char *msgdos;
int lendos;
@@ -93,6 +100,14 @@ BOOL cli_message_text(struct cli_state *cli, char *msg, int len, int grp)
}
cli_setup_bcc(cli, p);
+
+ return(PTR_DIFF(p, cli->outbuf));
+}
+
+BOOL cli_message_text(struct cli_state *cli, char *msg, int len, int grp)
+{
+ cli_message_text_build(cli, msg, len, grp);
+
cli_send_smb(cli);
if (!cli_receive_smb(cli)) {
@@ -107,8 +122,10 @@ BOOL cli_message_text(struct cli_state *cli, char *msg, int len, int grp)
/****************************************************************************
end a message
****************************************************************************/
-BOOL cli_message_end(struct cli_state *cli, int grp)
+int cli_message_end_build(struct cli_state *cli, int grp)
{
+ char *p;
+
memset(cli->outbuf,'\0',smb_size);
set_message(cli->outbuf,1,0,True);
SCVAL(cli->outbuf,smb_com,SMBsendend);
@@ -117,7 +134,16 @@ BOOL cli_message_end(struct cli_state *cli, int grp)
SSVAL(cli->outbuf,smb_vwv0,grp);
cli_setup_packet(cli);
-
+
+ p = smb_buf(cli->outbuf);
+
+ return(PTR_DIFF(p, cli->outbuf));
+}
+
+BOOL cli_message_end(struct cli_state *cli, int grp)
+{
+ cli_message_end_build(cli, grp);
+
cli_send_smb(cli);
if (!cli_receive_smb(cli)) {
diff --git a/source3/libsmb/clirap.c b/source3/libsmb/clirap.c
index 9d4411797d..a307ac6ccf 100644
--- a/source3/libsmb/clirap.c
+++ b/source3/libsmb/clirap.c
@@ -92,13 +92,13 @@ BOOL cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation)
SSVAL(p,0,1);
p += 2;
pstrcpy_base(p,user,param);
- strupper(p);
+ strupper_m(p);
p += 21;
p++;
p += 15;
p++;
pstrcpy_base(p, workstation, param);
- strupper(p);
+ strupper_m(p);
p += 16;
SSVAL(p, 0, CLI_BUFFER_SIZE);
p += 2;
diff --git a/source3/libsmb/clirap2.c b/source3/libsmb/clirap2.c
index 948e88061a..669b33860d 100644
--- a/source3/libsmb/clirap2.c
+++ b/source3/libsmb/clirap2.c
@@ -1396,11 +1396,11 @@ BOOL cli_NetWkstaUserLogoff(struct cli_state *cli,char *user, char *workstation)
PUTDWORD(p, 0); /* Null pointer */
PUTDWORD(p, 0); /* Null pointer */
fstrcpy(upperbuf, user);
- strupper(upperbuf);
+ strupper_m(upperbuf);
PUTSTRINGF(p, upperbuf, RAP_USERNAME_LEN);
p++; /* strange format, but ok */
fstrcpy(upperbuf, workstation);
- strupper(upperbuf);
+ strupper_m(upperbuf);
PUTSTRINGF(p, upperbuf, RAP_MACHNAME_LEN);
PUTWORD(p, CLI_BUFFER_SIZE);
PUTWORD(p, CLI_BUFFER_SIZE);
diff --git a/source3/libsmb/clispnego.c b/source3/libsmb/clispnego.c
index 53f7eb6e7d..bb48f57915 100644
--- a/source3/libsmb/clispnego.c
+++ b/source3/libsmb/clispnego.c
@@ -329,7 +329,7 @@ DATA_BLOB spnego_gen_negTokenTarg(const char *principal, int time_offset)
const char *krb_mechs[] = {OID_KERBEROS5_OLD, OID_NTLMSSP, NULL};
/* get a kerberos ticket for the service */
- tkt = krb5_get_ticket(principal, time_offset);
+ tkt = cli_krb5_get_ticket(principal, time_offset);
/* wrap that up in a nice GSS-API wrapping */
tkt_wrapped = spnego_gen_krb5_wrap(tkt, TOK_ID_KRB_AP_REQ);
diff --git a/source3/libsmb/namecache.c b/source3/libsmb/namecache.c
index d3541b7719..e3e7ac4e3c 100644
--- a/source3/libsmb/namecache.c
+++ b/source3/libsmb/namecache.c
@@ -113,7 +113,7 @@ static char* namecache_key(const char *name, int name_type)
**/
BOOL namecache_store(const char *name, int name_type,
- int num_names, struct in_addr *ip_list)
+ int num_names, struct ip_service *ip_list)
{
time_t expiry;
char *key, *value_string;
@@ -126,27 +126,19 @@ BOOL namecache_store(const char *name, int name_type,
*/
if (!gencache_init()) return False;
- DEBUG(5, ("namecache_store: storing %d address%s for %s#%02x: ",
- num_names, num_names == 1 ? "": "es", name, name_type));
-
- for (i = 0; i < num_names; i++)
- DEBUGADD(5, ("%s%s", inet_ntoa(ip_list[i]),
- i == (num_names - 1) ? "" : ", "));
-
- DEBUGADD(5, ("\n"));
+ if ( DEBUGLEVEL >= 5 ) {
+ DEBUG(5, ("namecache_store: storing %d address%s for %s#%02x: ",
+ num_names, num_names == 1 ? "": "es", name, name_type));
+ for (i = 0; i < num_names; i++)
+ DEBUGADD(5, ("%s:%d%s", inet_ntoa(ip_list[i].ip),
+ ip_list[i].port, (i == (num_names - 1) ? "" : ",")));
+
+ DEBUGADD(5, ("\n"));
+ }
+
key = namecache_key(name, name_type);
-
- /*
- * Cache pdc location or dc lists for only a little while
- * otherwise if we lock on to a bad DC we can potentially be
- * out of action for the entire cache timeout time!
- */
-
- if (name_type == 0x1b || name_type == 0x1c)
- expiry = time(NULL) + 10;
- else
- expiry = time(NULL) + lp_name_cache_timeout();
+ expiry = time(NULL) + lp_name_cache_timeout();
/*
* Generate string representation of ip addresses list
@@ -180,7 +172,7 @@ BOOL namecache_store(const char *name, int name_type,
* false if name isn't found in the cache or has expired
**/
-BOOL namecache_fetch(const char *name, int name_type, struct in_addr **ip_list,
+BOOL namecache_fetch(const char *name, int name_type, struct ip_service **ip_list,
int *num_names)
{
char *key, *value;
@@ -201,7 +193,9 @@ BOOL namecache_fetch(const char *name, int name_type, struct in_addr **ip_list,
if (!gencache_get(key, &value, &timeout)) {
DEBUG(5, ("no entry for %s#%02X found.\n", name, name_type));
+ gencache_del(key);
SAFE_FREE(key);
+ SAFE_FREE(value);
return False;
} else {
DEBUG(5, ("name %s#%02X found.\n", name, name_type));
@@ -213,7 +207,8 @@ BOOL namecache_fetch(const char *name, int name_type, struct in_addr **ip_list,
*num_names = ipstr_list_parse(value, ip_list);
SAFE_FREE(key);
- SAFE_FREE(value);
+ SAFE_FREE(value);
+
return *num_names > 0; /* true only if some ip has been fetched */
}
@@ -252,3 +247,75 @@ void namecache_flush(void)
DEBUG(5, ("Namecache flushed\n"));
}
+/* Construct a name status record key. */
+
+static char *namecache_status_record_key(const char *name, int name_type1,
+ int name_type2, struct in_addr keyip)
+{
+ char *keystr;
+
+ asprintf(&keystr, "NBT/%s#%02X.%02X.%s",
+ strupper_static(name), name_type1, name_type2, inet_ntoa(keyip));
+ return keystr;
+}
+
+/* Store a name status record. */
+
+BOOL namecache_status_store(const char *keyname, int keyname_type,
+ int name_type, struct in_addr keyip,
+ const char *srvname)
+{
+ char *key;
+ time_t expiry;
+ BOOL ret;
+
+ if (!gencache_init())
+ return False;
+
+ key = namecache_status_record_key(keyname, keyname_type, name_type, keyip);
+ if (!key)
+ return False;
+
+ expiry = time(NULL) + lp_name_cache_timeout();
+ ret = gencache_set(key, srvname, expiry);
+
+ if (ret)
+ DEBUG(5, ("namecache_status_store: entry %s -> %s\n", key, srvname ));
+ else
+ DEBUG(5, ("namecache_status_store: entry %s store failed.\n", key ));
+
+ SAFE_FREE(key);
+ return ret;
+}
+
+/* Fetch a name status record. */
+
+BOOL namecache_status_fetch(const char *keyname, int keyname_type,
+ int name_type, struct in_addr keyip, char *srvname_out)
+{
+ char *key = NULL;
+ char *value = NULL;
+ time_t timeout;
+
+ if (!gencache_init())
+ return False;
+
+ key = namecache_status_record_key(keyname, keyname_type, name_type, keyip);
+ if (!key)
+ return False;
+
+ if (!gencache_get(key, &value, &timeout)) {
+ DEBUG(5, ("namecache_status_fetch: no entry for %s found.\n", key));
+ gencache_del(key);
+ SAFE_FREE(key);
+ SAFE_FREE(value);
+ return False;
+ } else {
+ DEBUG(5, ("namecache_status_fetch: key %s -> %s\n", key, value ));
+ }
+
+ strlcpy(srvname_out, value, 16);
+ SAFE_FREE(key);
+ SAFE_FREE(value);
+ return True;
+}
diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c
index 18ce5e4bd9..9875f77c72 100644
--- a/source3/libsmb/namequery.c
+++ b/source3/libsmb/namequery.c
@@ -25,8 +25,9 @@
BOOL global_in_nmbd = False;
/****************************************************************************
-generate a random trn_id
+ Generate a random trn_id.
****************************************************************************/
+
static int generate_trn_id(void)
{
static int trn_id;
@@ -40,10 +41,10 @@ static int generate_trn_id(void)
return trn_id % (unsigned)0x7FFF;
}
-
/****************************************************************************
- parse a node status response into an array of structures
+ Parse a node status response into an array of structures.
****************************************************************************/
+
static struct node_status *parse_node_status(char *p, int *num_names)
{
struct node_status *ret;
@@ -51,7 +52,8 @@ static struct node_status *parse_node_status(char *p, int *num_names)
*num_names = CVAL(p,0);
- if (*num_names == 0) return NULL;
+ if (*num_names == 0)
+ return NULL;
ret = (struct node_status *)malloc(sizeof(struct node_status)* (*num_names));
if (!ret) return NULL;
@@ -71,9 +73,10 @@ static struct node_status *parse_node_status(char *p, int *num_names)
/****************************************************************************
-do a NBT node status query on an open socket and return an array of
-structures holding the returned names or NULL if the query failed
+ Do a NBT node status query on an open socket and return an array of
+ structures holding the returned names or NULL if the query failed.
**************************************************************************/
+
struct node_status *node_status_query(int fd,struct nmb_name *name,
struct in_addr to_ip, int *num_names)
{
@@ -155,11 +158,9 @@ struct node_status *node_status_query(int fd,struct nmb_name *name,
return NULL;
}
-
/****************************************************************************
-find the first type XX name in a node status reply - used for finding
-a servers name given its IP
-return the matched name in *name
+ Find the first type XX name in a node status reply - used for finding
+ a servers name given its IP. Return the matched name in *name.
**************************************************************************/
BOOL name_status_find(const char *q_name, int q_type, int type, struct in_addr to_ip, char *name)
@@ -178,6 +179,11 @@ BOOL name_status_find(const char *q_name, int q_type, int type, struct in_addr t
DEBUG(10, ("name_status_find: looking up %s#%02x at %s\n", q_name,
q_type, inet_ntoa(to_ip)));
+ /* Check the cache first. */
+
+ if (namecache_status_fetch(q_name, q_type, type, to_ip, name))
+ return True;
+
sock = open_socket_in(SOCK_DGRAM, 0, 3, interpret_addr(lp_socket_address()), True);
if (sock == -1)
goto done;
@@ -197,6 +203,14 @@ BOOL name_status_find(const char *q_name, int q_type, int type, struct in_addr t
goto done;
pull_ascii(name, status[i].name, 16, 15, STR_TERMINATE);
+
+ /* Store the result in the cache. */
+ /* but don't store an entry for 0x1c names here. Here we have
+ a single host and DOMAIN<0x1c> names should be a list of hosts */
+
+ if ( q_type != 0x1c )
+ namecache_status_store(q_name, q_type, type, to_ip, name);
+
result = True;
done:
@@ -205,17 +219,17 @@ BOOL name_status_find(const char *q_name, int q_type, int type, struct in_addr t
DEBUG(10, ("name_status_find: name %sfound", result ? "" : "not "));
if (result)
- DEBUGADD(10, (", ip address is %s", inet_ntoa(to_ip)));
+ DEBUGADD(10, (", name %s ip address is %s", name, inet_ntoa(to_ip)));
DEBUG(10, ("\n"));
return result;
}
-
/*
comparison function used by sort_ip_list
*/
+
int ip_compare(struct in_addr *ip1, struct in_addr *ip2)
{
int max_bits1=0, max_bits2=0;
@@ -243,11 +257,32 @@ int ip_compare(struct in_addr *ip1, struct in_addr *ip2)
return max_bits2 - max_bits1;
}
+/*******************************************************************
+ compare 2 ldap IPs by nearness to our interfaces - used in qsort
+*******************************************************************/
+
+static int ip_service_compare(struct ip_service *ip1, struct ip_service *ip2)
+{
+ int result;
+
+ if ( (result = ip_compare(&ip1->ip, &ip2->ip)) != 0 )
+ return result;
+
+ if ( ip1->port > ip2->port )
+ return 1;
+
+ if ( ip1->port < ip2->port )
+ return -1;
+
+ return 0;
+}
+
/*
sort an IP list so that names that are close to one of our interfaces
are at the top. This prevents the problem where a WINS server returns an IP that
is not reachable from our subnet as the first match
*/
+
static void sort_ip_list(struct in_addr *iplist, int count)
{
if (count <= 1) {
@@ -257,6 +292,50 @@ static void sort_ip_list(struct in_addr *iplist, int count)
qsort(iplist, count, sizeof(struct in_addr), QSORT_CAST ip_compare);
}
+void sort_ip_list2(struct ip_service *iplist, int count)
+{
+ if (count <= 1) {
+ return;
+ }
+
+ qsort(iplist, count, sizeof(struct ip_service), QSORT_CAST ip_service_compare);
+}
+
+/**********************************************************************
+ Remove any duplicate address/port pairs in the list
+ *********************************************************************/
+
+static int remove_duplicate_addrs2( struct ip_service *iplist, int count )
+{
+ int i, j;
+
+ DEBUG(10,("remove_duplicate_addrs2: looking for duplicate address/port pairs\n"));
+
+ /* one loop to remove duplicates */
+ for ( i=0; i<count; i++ ) {
+ if ( is_zero_ip(iplist[i].ip) )
+ continue;
+
+ for ( j=i+1; j<count; j++ ) {
+ if ( ip_service_equal(iplist[i], iplist[j]) )
+ zero_ip(&iplist[j].ip);
+ }
+ }
+
+ /* one loop to clean up any holes we left */
+ /* first ip should never be a zero_ip() */
+ for (i = 0; i<count; ) {
+ if ( is_zero_ip(iplist[i].ip) ) {
+ if (i != count-1 )
+ memmove(&iplist[i], &iplist[i+1], (count - i - 1)*sizeof(iplist[i]));
+ count--;
+ continue;
+ }
+ i++;
+ }
+
+ return count;
+}
/****************************************************************************
Do a netbios name query to find someones IP.
@@ -264,6 +343,7 @@ static void sort_ip_list(struct in_addr *iplist, int count)
*count will be set to the number of addresses returned.
*timed_out is set if we failed by timing out
****************************************************************************/
+
struct in_addr *name_query(int fd,const char *name,int name_type,
BOOL bcast,BOOL recurse,
struct in_addr to_ip, int *count, int *flags,
@@ -436,7 +516,9 @@ struct in_addr *name_query(int fd,const char *name,int name_type,
}
}
- if (timed_out) {
+ /* only set timed_out if we didn't fund what we where looking for*/
+
+ if ( !found && timed_out ) {
*timed_out = True;
}
@@ -556,23 +638,49 @@ void endlmhosts(XFILE *fp)
x_fclose(fp);
}
+/********************************************************
+ convert an array if struct in_addrs to struct ip_service
+ return False on failure. Port is set to PORT_NONE;
+*********************************************************/
+
+static BOOL convert_ip2service( struct ip_service **return_iplist, struct in_addr *ip_list, int count )
+{
+ int i;
+
+ if ( count==0 || !ip_list )
+ return False;
+
+ /* copy the ip address; port will be PORT_NONE */
+ if ( (*return_iplist = (struct ip_service*)malloc(count*sizeof(struct ip_service))) == NULL ) {
+ DEBUG(0,("convert_ip2service: malloc failed for %d enetries!\n", count ));
+ return False;
+ }
+
+ for ( i=0; i<count; i++ ) {
+ (*return_iplist)[i].ip = ip_list[i];
+ (*return_iplist)[i].port = PORT_NONE;
+ }
+ return True;
+}
/********************************************************
Resolve via "bcast" method.
*********************************************************/
BOOL name_resolve_bcast(const char *name, int name_type,
- struct in_addr **return_ip_list, int *return_count)
+ struct ip_service **return_iplist, int *return_count)
{
int sock, i;
int num_interfaces = iface_count();
+ struct in_addr *ip_list;
+ BOOL ret;
if (lp_disable_netbios()) {
DEBUG(5,("name_resolve_bcast(%s#%02x): netbios is disabled\n", name, name_type));
return False;
}
- *return_ip_list = NULL;
+ *return_iplist = NULL;
*return_count = 0;
/*
@@ -596,27 +704,38 @@ BOOL name_resolve_bcast(const char *name, int name_type,
int flags;
/* Done this way to fix compiler error on IRIX 5.x */
sendto_ip = *iface_n_bcast(i);
- *return_ip_list = name_query(sock, name, name_type, True,
+ ip_list = name_query(sock, name, name_type, True,
True, sendto_ip, return_count, &flags, NULL);
- if(*return_ip_list != NULL) {
- close(sock);
- return True;
- }
+ if( ip_list )
+ goto success;
}
-
+
+ /* failed - no response */
+
close(sock);
return False;
+
+success:
+ ret = True;
+ if ( !convert_ip2service(return_iplist, ip_list, *return_count) )
+ ret = False;
+
+ SAFE_FREE( ip_list );
+ close(sock);
+ return ret;
}
/********************************************************
Resolve via "wins" method.
*********************************************************/
+
BOOL resolve_wins(const char *name, int name_type,
- struct in_addr **return_iplist, int *return_count)
+ struct ip_service **return_iplist, int *return_count)
{
int sock, t, i;
char **wins_tags;
- struct in_addr src_ip;
+ struct in_addr src_ip, *ip_list = NULL;
+ BOOL ret;
if (lp_disable_netbios()) {
DEBUG(5,("resolve_wins(%s#%02x): netbios is disabled\n", name, name_type));
@@ -672,12 +791,15 @@ BOOL resolve_wins(const char *name, int name_type,
continue;
}
- *return_iplist = name_query(sock,name,name_type, False,
+ ip_list = name_query(sock,name,name_type, False,
True, wins_ip, return_count, &flags,
&timed_out);
- if (*return_iplist != NULL) {
+
+ /* exit loop if we got a list of addresses */
+
+ if ( ip_list )
goto success;
- }
+
close(sock);
if (timed_out) {
@@ -695,9 +817,15 @@ BOOL resolve_wins(const char *name, int name_type,
return False;
success:
+ ret = True;
+ if ( !convert_ip2service( return_iplist, ip_list, *return_count ) )
+ ret = False;
+
+ SAFE_FREE( ip_list );
wins_srv_tags_free(wins_tags);
close(sock);
- return True;
+
+ return ret;
}
/********************************************************
@@ -705,7 +833,7 @@ success:
*********************************************************/
static BOOL resolve_lmhosts(const char *name, int name_type,
- struct in_addr **return_iplist, int *return_count)
+ struct ip_service **return_iplist, int *return_count)
{
/*
* "lmhosts" means parse the local lmhosts file.
@@ -728,12 +856,12 @@ static BOOL resolve_lmhosts(const char *name, int name_type,
((name_type2 == -1) || (name_type == name_type2))
) {
endlmhosts(fp);
- *return_iplist = (struct in_addr *)malloc(sizeof(struct in_addr));
- if(*return_iplist == NULL) {
+ if ( (*return_iplist = (struct ip_service *)malloc(sizeof(struct ip_service))) == NULL ) {
DEBUG(3,("resolve_lmhosts: malloc fail !\n"));
return False;
}
- **return_iplist = return_ip;
+ (*return_iplist)[0].ip = return_ip;
+ (*return_iplist)[0].port = PORT_NONE;
*return_count = 1;
return True;
}
@@ -748,13 +876,67 @@ static BOOL resolve_lmhosts(const char *name, int name_type,
Resolve via "hosts" method.
*********************************************************/
-static BOOL resolve_hosts(const char *name,
- struct in_addr **return_iplist, int *return_count)
+static BOOL resolve_hosts(const char *name, int name_type,
+ struct ip_service **return_iplist, int *return_count)
{
/*
* "host" means do a localhost, or dns lookup.
*/
struct hostent *hp;
+
+#ifdef HAVE_ADS
+ if ( name_type == 0x1c ) {
+ int count, i = 0;
+ char *list = NULL;
+ const char *ptr;
+ pstring tok;
+
+ /* try to lookup the _ldap._tcp.<domain> if we are using ADS */
+ if ( lp_security() != SEC_ADS )
+ return False;
+
+ DEBUG(5,("resolve_hosts: Attempting to resolve DC's for %s using DNS\n",
+ name));
+
+ if (ldap_domain2hostlist(name, &list) != LDAP_SUCCESS)
+ return False;
+
+ count = count_chars(list, ' ') + 1;
+ if ( (*return_iplist = malloc(count * sizeof(struct ip_service))) == NULL ) {
+ DEBUG(0,("resolve_hosts: malloc failed for %d entries\n", count ));
+ return False;
+ }
+
+ ptr = list;
+ while (next_token(&ptr, tok, " ", sizeof(tok))) {
+ unsigned port = LDAP_PORT;
+ char *p = strchr(tok, ':');
+ if (p) {
+ *p = 0;
+ port = atoi(p+1);
+ }
+ (*return_iplist)[i].ip = *interpret_addr2(tok);
+ (*return_iplist)[i].port = port;
+
+ /* make sure it is a valid IP. I considered checking the negative
+ connection cache, but this is the wrong place for it. Maybe only
+ as a hac. After think about it, if all of the IP addresses retuend
+ from DNS are dead, what hope does a netbios name lookup have?
+ The standard reason for falling back to netbios lookups is that
+ our DNS server doesn't know anything about the DC's -- jerry */
+
+ if ( is_zero_ip((*return_iplist)[i].ip) )
+ continue;
+
+ i++;
+ }
+ SAFE_FREE(list);
+
+ *return_count = i;
+
+ return True;
+ }
+#endif /* HAVE_ADS */
*return_iplist = NULL;
*return_count = 0;
@@ -764,27 +946,33 @@ static BOOL resolve_hosts(const char *name,
if (((hp = sys_gethostbyname(name)) != NULL) && (hp->h_addr != NULL)) {
struct in_addr return_ip;
putip((char *)&return_ip,(char *)hp->h_addr);
- *return_iplist = (struct in_addr *)malloc(sizeof(struct in_addr));
+ *return_iplist = (struct ip_service *)malloc(sizeof(struct ip_service));
if(*return_iplist == NULL) {
DEBUG(3,("resolve_hosts: malloc fail !\n"));
return False;
}
- **return_iplist = return_ip;
+ (*return_iplist)->ip = return_ip;
+ (*return_iplist)->port = PORT_NONE;
*return_count = 1;
return True;
}
return False;
}
-/********************************************************
+/*******************************************************************
Internal interface to resolve a name into an IP address.
Use this function if the string is either an IP address, DNS
or host name or NetBIOS name. This uses the name switch in the
smb.conf to determine the order of name resolution.
-*********************************************************/
+
+ Added support for ip addr/port to support ADS ldap servers.
+ the only place we currently care about the port is in the
+ resolve_hosts() when looking up DC's via SRV RR entries in DNS
+**********************************************************************/
static BOOL internal_resolve_name(const char *name, int name_type,
- struct in_addr **return_iplist, int *return_count)
+ struct ip_service **return_iplist,
+ int *return_count, const char *resolve_order)
{
pstring name_resolve_list;
fstring tok;
@@ -793,7 +981,6 @@ static BOOL internal_resolve_name(const char *name, int name_type,
BOOL allzeros = (strcmp(name,"0.0.0.0") == 0);
BOOL is_address = is_ipaddress(name);
BOOL result = False;
- struct in_addr *nodupes_iplist;
int i;
*return_iplist = NULL;
@@ -802,42 +989,56 @@ static BOOL internal_resolve_name(const char *name, int name_type,
DEBUG(10, ("internal_resolve_name: looking up %s#%x\n", name, name_type));
if (allzeros || allones || is_address) {
- *return_iplist = (struct in_addr *)malloc(sizeof(struct in_addr));
- if(*return_iplist == NULL) {
- DEBUG(3,("internal_resolve_name: malloc fail !\n"));
+
+ if ( (*return_iplist = (struct ip_service *)malloc(sizeof(struct ip_service))) == NULL ) {
+ DEBUG(0,("internal_resolve_name: malloc fail !\n"));
return False;
}
+
if(is_address) {
+ /* ignore the port here */
+ (*return_iplist)->port = PORT_NONE;
+
/* if it's in the form of an IP address then get the lib to interpret it */
- if (((*return_iplist)->s_addr = inet_addr(name)) == 0xFFFFFFFF ){
+ if (((*return_iplist)->ip.s_addr = inet_addr(name)) == 0xFFFFFFFF ){
DEBUG(1,("internal_resolve_name: inet_addr failed on %s\n", name));
return False;
}
} else {
- (*return_iplist)->s_addr = allones ? 0xFFFFFFFF : 0;
+ (*return_iplist)->ip.s_addr = allones ? 0xFFFFFFFF : 0;
*return_count = 1;
}
return True;
}
- /* Check netbios name cache */
+ /* Check name cache */
if (namecache_fetch(name, name_type, return_iplist, return_count)) {
-
- /* This could be a negative response */
-
- return (*return_count > 0);
+ /* This could be a negative response */
+ return (*return_count > 0);
}
- pstrcpy(name_resolve_list, lp_name_resolve_order());
- ptr = name_resolve_list;
- if (!ptr || !*ptr)
+ /* set the name resolution order */
+
+ if ( !resolve_order )
+ pstrcpy(name_resolve_list, lp_name_resolve_order());
+ else
+ pstrcpy(name_resolve_list, resolve_order);
+
+ if ( !name_resolve_list[0] )
ptr = "host";
+ else
+ ptr = name_resolve_list;
+ /* iterate through the name resolution backends */
+
while (next_token(&ptr, tok, LIST_SEP, sizeof(tok))) {
if((strequal(tok, "host") || strequal(tok, "hosts"))) {
- if (name_type == 0x20) {
- if (resolve_hosts(name, return_iplist, return_count)) {
+ /* deal with 0x20 & 0x1c names here. The latter will result
+ in a SRV record lookup for _ldap._tcp.<domain> if we are using
+ 'security = ads' */
+ if ( name_type==0x20 || name_type == 0x1c ) {
+ if (resolve_hosts(name, name_type, return_iplist, return_count)) {
result = True;
goto done;
}
@@ -878,58 +1079,31 @@ static BOOL internal_resolve_name(const char *name, int name_type,
controllers including the PDC in iplist[1..n]. Iterating over
the iplist when the PDC is down will cause two sets of timeouts. */
- if (*return_count && (nodupes_iplist = (struct in_addr *)
- malloc(sizeof(struct in_addr) * (*return_count)))) {
- int nodupes_count = 0;
-
- /* Iterate over return_iplist looking for duplicates */
-
- for (i = 0; i < *return_count; i++) {
- BOOL is_dupe = False;
- int j;
-
- for (j = i + 1; j < *return_count; j++) {
- if (ip_equal((*return_iplist)[i],
- (*return_iplist)[j])) {
- is_dupe = True;
- break;
- }
- }
-
- if (!is_dupe) {
-
- /* This one not a duplicate */
-
- nodupes_iplist[nodupes_count] = (*return_iplist)[i];
- nodupes_count++;
- }
- }
-
- /* Switcheroo with original list */
-
- free(*return_iplist);
-
- *return_iplist = nodupes_iplist;
- *return_count = nodupes_count;
+ if ( *return_count ) {
+ *return_count = remove_duplicate_addrs2( *return_iplist, *return_count );
}
/* Save in name cache */
- for (i = 0; i < *return_count && DEBUGLEVEL == 100; i++)
- DEBUG(100, ("Storing name %s of type %d (ip: %s)\n", name,
- name_type, inet_ntoa((*return_iplist)[i])));
-
+ if ( DEBUGLEVEL >= 100 ) {
+ for (i = 0; i < *return_count && DEBUGLEVEL == 100; i++)
+ DEBUG(100, ("Storing name %s of type %d (%s:%d)\n", name,
+ name_type, inet_ntoa((*return_iplist)[i].ip), (*return_iplist)[i].port));
+ }
+
namecache_store(name, name_type, *return_count, *return_iplist);
/* Display some debugging info */
- DEBUG(10, ("internal_resolve_name: returning %d addresses: ",
- *return_count));
-
- for (i = 0; i < *return_count; i++)
- DEBUGADD(10, ("%s ", inet_ntoa((*return_iplist)[i])));
+ if ( DEBUGLEVEL >= 10 ) {
+ DEBUG(10, ("internal_resolve_name: returning %d addresses: ",
+ *return_count));
- DEBUG(10, ("\n"));
+ for (i = 0; i < *return_count; i++)
+ DEBUGADD(10, ("%s:%d ", inet_ntoa((*return_iplist)[i].ip), (*return_iplist)[i].port));
+ DEBUG(10, ("\n"));
+ }
+
return result;
}
@@ -942,7 +1116,7 @@ static BOOL internal_resolve_name(const char *name, int name_type,
BOOL resolve_name(const char *name, struct in_addr *return_ip, int name_type)
{
- struct in_addr *ip_list = NULL;
+ struct ip_service *ip_list = NULL;
int count = 0;
if (is_ipaddress(name)) {
@@ -950,20 +1124,23 @@ BOOL resolve_name(const char *name, struct in_addr *return_ip, int name_type)
return True;
}
- if (internal_resolve_name(name, name_type, &ip_list, &count)) {
+ if (internal_resolve_name(name, name_type, &ip_list, &count, lp_name_resolve_order())) {
int i;
+
/* only return valid addresses for TCP connections */
for (i=0; i<count; i++) {
- char *ip_str = inet_ntoa(ip_list[i]);
+ char *ip_str = inet_ntoa(ip_list[i].ip);
if (ip_str &&
strcmp(ip_str, "255.255.255.255") != 0 &&
- strcmp(ip_str, "0.0.0.0") != 0) {
- *return_ip = ip_list[i];
+ strcmp(ip_str, "0.0.0.0") != 0)
+ {
+ *return_ip = ip_list[i].ip;
SAFE_FREE(ip_list);
return True;
}
}
}
+
SAFE_FREE(ip_list);
return False;
}
@@ -974,7 +1151,7 @@ BOOL resolve_name(const char *name, struct in_addr *return_ip, int name_type)
BOOL find_master_ip(const char *group, struct in_addr *master_ip)
{
- struct in_addr *ip_list = NULL;
+ struct ip_service *ip_list = NULL;
int count = 0;
if (lp_disable_netbios()) {
@@ -982,13 +1159,13 @@ BOOL find_master_ip(const char *group, struct in_addr *master_ip)
return False;
}
- if (internal_resolve_name(group, 0x1D, &ip_list, &count)) {
- *master_ip = ip_list[0];
+ if (internal_resolve_name(group, 0x1D, &ip_list, &count, lp_name_resolve_order())) {
+ *master_ip = ip_list[0].ip;
SAFE_FREE(ip_list);
return True;
}
- if(internal_resolve_name(group, 0x1B, &ip_list, &count)) {
- *master_ip = ip_list[0];
+ if(internal_resolve_name(group, 0x1B, &ip_list, &count, lp_name_resolve_order())) {
+ *master_ip = ip_list[0].ip;
SAFE_FREE(ip_list);
return True;
}
@@ -998,285 +1175,87 @@ BOOL find_master_ip(const char *group, struct in_addr *master_ip)
}
/********************************************************
- Lookup a DC name given a Domain name and IP address.
-*********************************************************/
-
-BOOL lookup_dc_name(const char *srcname, const char *domain,
- struct in_addr *dc_ip, char *ret_name)
-{
-#if !defined(I_HATE_WINDOWS_REPLY_CODE)
- fstring dc_name;
- BOOL ret;
-
- if (lp_disable_netbios()) {
- DEBUG(5,("lookup_dc_name(%s): netbios is disabled\n", domain));
- return False;
- }
-
- /*
- * Due to the fact win WinNT *sucks* we must do a node status
- * query here... JRA.
- */
-
- *dc_name = '\0';
-
- ret = name_status_find(domain, 0x1c, 0x20, *dc_ip, dc_name);
-
- if(ret && *dc_name) {
- fstrcpy(ret_name, dc_name);
- return True;
- }
-
- return False;
-
-#else /* defined(I_HATE_WINDOWS_REPLY_CODE) */
-
-JRA - This code is broken with BDC rollover - we need to do a full
-NT GETDC call, UNICODE, NT domain SID and uncle tom cobbley and all...
-
- int retries = 3;
- int retry_time = 2000;
- struct timeval tval;
- struct packet_struct p;
- struct dgram_packet *dgram = &p.packet.dgram;
- char *ptr,*p2;
- char tmp[4];
- int len;
- struct sockaddr_in sock_name;
- int sock_len = sizeof(sock_name);
- const char *mailslot = NET_LOGON_MAILSLOT;
- char *mailslot_name;
- char buffer[1024];
- char *bufp;
- int dgm_id = generate_trn_id();
- int sock = open_socket_in(SOCK_DGRAM, 0, 3, interpret_addr(lp_socket_address()), True );
-
- if(sock == -1)
- return False;
-
- /* Find out the transient UDP port we have been allocated. */
- if(getsockname(sock, (struct sockaddr *)&sock_name, &sock_len)<0) {
- DEBUG(0,("lookup_pdc_name: Failed to get local UDP port. Error was %s\n",
- strerror(errno)));
- close(sock);
- return False;
- }
-
- /*
- * Create the request data.
- */
-
- memset(buffer,'\0',sizeof(buffer));
- bufp = buffer;
- SSVAL(bufp,0,QUERYFORPDC);
- bufp += 2;
- fstrcpy(bufp,srcname);
- bufp += (strlen(bufp) + 1);
- slprintf(bufp, sizeof(fstring)-1, "\\MAILSLOT\\NET\\GETDC%d", dgm_id);
- mailslot_name = bufp;
- bufp += (strlen(bufp) + 1);
- bufp = ALIGN2(bufp, buffer);
- bufp += push_ucs2(NULL, bufp, srcname, sizeof(buffer) - (bufp - buffer), STR_TERMINATE);
-
- SIVAL(bufp,0,1);
- SSVAL(bufp,4,0xFFFF);
- SSVAL(bufp,6,0xFFFF);
- bufp += 8;
- len = PTR_DIFF(bufp,buffer);
-
- memset((char *)&p,'\0',sizeof(p));
-
- /* DIRECT GROUP or UNIQUE datagram. */
- dgram->header.msg_type = 0x10;
- dgram->header.flags.node_type = M_NODE;
- dgram->header.flags.first = True;
- dgram->header.flags.more = False;
- dgram->header.dgm_id = dgm_id;
- dgram->header.source_ip = *iface_ip(*pdc_ip);
- dgram->header.source_port = ntohs(sock_name.sin_port);
- dgram->header.dgm_length = 0; /* Let build_dgram() handle this. */
- dgram->header.packet_offset = 0;
-
- make_nmb_name(&dgram->source_name,srcname,0);
- make_nmb_name(&dgram->dest_name,domain,0x1C);
-
- ptr = &dgram->data[0];
-
- /* Setup the smb part. */
- ptr -= 4; /* XXX Ugliness because of handling of tcp SMB length. */
- memcpy(tmp,ptr,4);
- set_message(ptr,17,17 + len,True);
- memcpy(ptr,tmp,4);
-
- CVAL(ptr,smb_com) = SMBtrans;
- SSVAL(ptr,smb_vwv1,len);
- SSVAL(ptr,smb_vwv11,len);
- SSVAL(ptr,smb_vwv12,70 + strlen(mailslot));
- SSVAL(ptr,smb_vwv13,3);
- SSVAL(ptr,smb_vwv14,1);
- SSVAL(ptr,smb_vwv15,1);
- SSVAL(ptr,smb_vwv16,2);
- p2 = smb_buf(ptr);
- pstrcpy(p2,mailslot);
- p2 = skip_string(p2,1);
-
- memcpy(p2,buffer,len);
- p2 += len;
-
- dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length. */
-
- p.ip = *pdc_ip;
- p.port = DGRAM_PORT;
- p.fd = sock;
- p.timestamp = time(NULL);
- p.packet_type = DGRAM_PACKET;
-
- GetTimeOfDay(&tval);
-
- if (!send_packet(&p)) {
- DEBUG(0,("lookup_pdc_name: send_packet failed.\n"));
- close(sock);
- return False;
- }
-
- retries--;
-
- while (1) {
- struct timeval tval2;
- struct packet_struct *p_ret;
-
- GetTimeOfDay(&tval2);
- if (TvalDiff(&tval,&tval2) > retry_time) {
- if (!retries)
- break;
- if (!send_packet(&p)) {
- DEBUG(0,("lookup_pdc_name: send_packet failed.\n"));
- close(sock);
- return False;
- }
- GetTimeOfDay(&tval);
- retries--;
- }
-
- if ((p_ret = receive_dgram_packet(sock,90,mailslot_name))) {
- struct dgram_packet *dgram2 = &p_ret->packet.dgram;
- char *buf;
- char *buf2;
-
- buf = &dgram2->data[0];
- buf -= 4;
-
- if (CVAL(buf,smb_com) != SMBtrans) {
- DEBUG(0,("lookup_pdc_name: datagram type %u != SMBtrans(%u)\n", (unsigned int)
- CVAL(buf,smb_com), (unsigned int)SMBtrans ));
- free_packet(p_ret);
- continue;
- }
-
- len = SVAL(buf,smb_vwv11);
- buf2 = smb_base(buf) + SVAL(buf,smb_vwv12);
-
- if (len <= 0) {
- DEBUG(0,("lookup_pdc_name: datagram len < 0 (%d)\n", len ));
- free_packet(p_ret);
- continue;
- }
-
- DEBUG(4,("lookup_pdc_name: datagram reply from %s to %s IP %s for %s of type %d len=%d\n",
- nmb_namestr(&dgram2->source_name),nmb_namestr(&dgram2->dest_name),
- inet_ntoa(p_ret->ip), smb_buf(buf),SVAL(buf2,0),len));
-
- if(SVAL(buf2,0) != QUERYFORPDC_R) {
- DEBUG(0,("lookup_pdc_name: datagram type (%u) != QUERYFORPDC_R(%u)\n",
- (unsigned int)SVAL(buf,0), (unsigned int)QUERYFORPDC_R ));
- free_packet(p_ret);
- continue;
- }
-
- buf2 += 2;
- /* Note this is safe as it is a bounded strcpy. */
- fstrcpy(ret_name, buf2);
- ret_name[sizeof(fstring)-1] = '\0';
- close(sock);
- free_packet(p_ret);
- return True;
- }
- }
-
- close(sock);
- return False;
-#endif /* defined(I_HATE_WINDOWS_REPLY_CODE) */
-}
-
-/********************************************************
Get the IP address list of the primary domain controller
for a domain.
*********************************************************/
BOOL get_pdc_ip(const char *domain, struct in_addr *ip)
{
- struct in_addr *ip_list;
+ struct ip_service *ip_list;
int count;
- int i = 0;
/* Look up #1B name */
- if (!internal_resolve_name(domain, 0x1b, &ip_list, &count))
+ if (!internal_resolve_name(domain, 0x1b, &ip_list, &count, lp_name_resolve_order()))
return False;
/* if we get more than 1 IP back we have to assume it is a
multi-homed PDC and not a mess up */
-
+
if ( count > 1 ) {
- DEBUG(6,("get_pdc_ip: PDC has %d IP addresses!\n", count));
-
- /* look for a local net */
- for ( i=0; i<count; i++ ) {
- if ( is_local_net( ip_list[i] ) )
- break;
- }
-
- /* if we hit then end then just grab the first
- one from the list */
-
- if ( i == count )
- i = 0;
+ DEBUG(6,("get_pdc_ip: PDC has %d IP addresses!\n", count));
+ sort_ip_list2( ip_list, count );
}
- *ip = ip_list[i];
+ *ip = ip_list[0].ip;
SAFE_FREE(ip_list);
return True;
}
+/*********************************************************************
+ small wrapper function to get the DC list and sort it if neccessary
+*********************************************************************/
+BOOL get_sorted_dc_list( const char *domain, struct ip_service **ip_list, int *count, BOOL dns_only )
+{
+ BOOL ordered;
+
+ DEBUG(8,("get_sorted_dc_list: attempting lookup using [%s]\n",
+ (dns_only ? "hosts" : lp_name_resolve_order())));
+
+ if ( !get_dc_list(domain, ip_list, count, dns_only, &ordered) )
+ return False;
+
+ /* only sort if we don't already have an ordered list */
+ if ( !ordered )
+ sort_ip_list2( *ip_list, *count );
+
+ return True;
+}
+
/********************************************************
Get the IP address list of the domain controllers for
a domain.
*********************************************************/
-BOOL get_dc_list(const char *domain, struct in_addr **ip_list, int *count, int *ordered)
+BOOL get_dc_list(const char *domain, struct ip_service **ip_list,
+ int *count, BOOL dns_only, int *ordered)
{
-
+ /* defined the name resolve order to internal_name_resolve()
+ only used for looking up 0x1c names */
+ const char *resolve_oder = (dns_only ? "hosts" : lp_name_resolve_order());
+
*ordered = False;
/* If it's our domain then use the 'password server' parameter. */
- if (strequal(domain, lp_workgroup())) {
+ if ( strequal(domain, lp_workgroup()) || strequal(domain, lp_realm()) ) {
const char *p;
char *pserver = lp_passwordserver(); /* UNIX charset. */
+ char *port_str;
+ int port;
fstring name;
int num_addresses = 0;
int local_count, i, j;
- struct in_addr *return_iplist = NULL;
- struct in_addr *auto_ip_list = NULL;
+ struct ip_service *return_iplist = NULL;
+ struct ip_service *auto_ip_list = NULL;
BOOL done_auto_lookup = False;
int auto_count = 0;
if (!*pserver)
- return internal_resolve_name(
- domain, 0x1C, ip_list, count);
+ return internal_resolve_name(domain, 0x1C, ip_list, count, resolve_oder);
p = pserver;
@@ -1289,7 +1268,7 @@ BOOL get_dc_list(const char *domain, struct in_addr **ip_list, int *count, int *
while (next_token(&p,name,LIST_SEP,sizeof(name))) {
if (strequal(name, "*")) {
- if ( internal_resolve_name(domain, 0x1C, &auto_ip_list, &auto_count) )
+ if ( internal_resolve_name(domain, 0x1C, &auto_ip_list, &auto_count, resolve_oder) )
num_addresses += auto_count;
done_auto_lookup = True;
DEBUG(8,("Adding %d DC's from auto lookup\n", auto_count));
@@ -1302,11 +1281,18 @@ BOOL get_dc_list(const char *domain, struct in_addr **ip_list, int *count, int *
just return the list of DC's */
if ( (num_addresses == 0) && !done_auto_lookup )
- return internal_resolve_name(domain, 0x1C, ip_list, count);
+ return internal_resolve_name(domain, 0x1C, ip_list, count, resolve_oder);
- return_iplist = (struct in_addr *)malloc(num_addresses * sizeof(struct in_addr));
-
- if (return_iplist == NULL) {
+ /* maybe we just failed? */
+
+ if ( num_addresses == 0 ) {
+ DEBUG(4,("get_dc_list: no servers found\n"));
+ return False;
+ }
+
+ if ( (return_iplist = (struct ip_service *)
+ malloc(num_addresses * sizeof(struct ip_service))) == NULL )
+ {
DEBUG(3,("get_dc_list: malloc fail !\n"));
return False;
}
@@ -1322,59 +1308,59 @@ BOOL get_dc_list(const char *domain, struct in_addr **ip_list, int *count, int *
/* copy any addersses from the auto lookup */
if ( strequal(name, "*") ) {
- for ( j=0; j<auto_count; j++ )
- return_iplist[local_count++] = auto_ip_list[j];
+ for ( j=0; j<auto_count; j++ ) {
+ return_iplist[local_count].ip = auto_ip_list[j].ip;
+ return_iplist[local_count].port = auto_ip_list[j].port;
+ local_count++;
+ }
continue;
}
+
+ /* added support for address:port syntax for ads (not that I think
+ anyone will ever run the LDAP server in an AD domain on something
+ other than port 389 */
+
+ port = (lp_security() == SEC_ADS) ? LDAP_PORT : PORT_NONE;
+ if ( (port_str=strchr(name, ':')) != NULL ) {
+ *port_str = '\0';
+ port_str++;
+ port = atoi( port_str );
+ }
+
/* explicit lookup; resolve_name() will handle names & IP addresses */
-
- if ( resolve_name( name, &name_ip, 0x20) ) {
- return_iplist[local_count++] = name_ip;
+ if ( resolve_name( name, &name_ip, 0x20 ) ) {
+ return_iplist[local_count].ip = name_ip;
+ return_iplist[local_count].port = port;
+ local_count++;
*ordered = True;
}
-
}
SAFE_FREE(auto_ip_list);
- /* need to remove duplicates in the list if we have
- any explicit password servers */
+ /* need to remove duplicates in the list if we have any
+ explicit password servers */
- if ( *ordered ) {
- /* one loop to remove duplicates */
- for ( i=0; i<local_count; i++ ) {
- if ( is_zero_ip(return_iplist[i]) )
- continue;
-
- for ( j=i+1; j<local_count; j++ ) {
- if ( ip_equal( return_iplist[i], return_iplist[j]) )
- zero_ip(&return_iplist[j]);
- }
- }
-
- /* one loop to clean up any holes we left */
- /* first ip should never be a zero_ip() */
- for (i = 0; i<local_count; ) {
- if ( is_zero_ip(return_iplist[i]) ) {
- if (i != local_count-1 )
- memmove(&return_iplist[i], &return_iplist[i+1],
- (local_count - i - 1)*sizeof(return_iplist[i]));
- local_count--;
- continue;
- }
- i++;
- }
- }
+ if ( local_count )
+ local_count = remove_duplicate_addrs2( return_iplist, local_count );
+ if ( DEBUGLEVEL >= 4 ) {
+ DEBUG(4,("get_dc_list: returning %d ip addresses in an %sordered list\n", local_count,
+ *ordered ? "":"un"));
+ DEBUG(4,("get_dc_list: "));
+ for ( i=0; i<local_count; i++ )
+ DEBUGADD(4,("%s:%d ", inet_ntoa(return_iplist[i].ip), return_iplist[i].port ));
+ DEBUGADD(4,("\n"));
+ }
+
*ip_list = return_iplist;
*count = local_count;
-
- DEBUG(8,("get_dc_list: return %d ip addresses\n", *count));
return (*count != 0);
}
- return internal_resolve_name(domain, 0x1C, ip_list, count);
+ DEBUG(10,("get_dc_list: defaulting to internal auto lookup for domain %s\n", domain));
+
+ return internal_resolve_name(domain, 0x1C, ip_list, count, resolve_oder);
}
-
diff --git a/source3/libsmb/namequery_dc.c b/source3/libsmb/namequery_dc.c
index ffc64139e9..c9d45a7acc 100644
--- a/source3/libsmb/namequery_dc.c
+++ b/source3/libsmb/namequery_dc.c
@@ -5,6 +5,7 @@
Copyright (C) Tim Potter 2001
Copyright (C) Andrew Bartlett 2002
+ Copyright (C) Gerald Carter 2003
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
@@ -24,16 +25,60 @@
#include "includes.h"
+/**************************************************************************
+ Find the name and IP address for a server in he realm/domain
+ *************************************************************************/
+
+static BOOL ads_dc_name(const char *domain, struct in_addr *dc_ip, fstring srv_name)
+{
+ ADS_STRUCT *ads;
+ const char *realm = domain;
-/*
- find the DC for a domain using methods appropriate for a RPC domain
-*/
-BOOL rpc_find_dc(const char *domain, fstring srv_name, struct in_addr *ip_out)
+ if (strcasecmp(realm, lp_workgroup()) == 0)
+ realm = lp_realm();
+
+ ads = ads_init(realm, domain, NULL);
+ if (!ads)
+ return False;
+
+ /* we don't need to bind, just connect */
+ ads->auth.flags |= ADS_AUTH_NO_BIND;
+
+ DEBUG(4,("ads_dc_name: domain=%s\n", domain));
+
+#ifdef HAVE_ADS
+ /* a full ads_connect() is actually overkill, as we don't srictly need
+ to do the SASL auth in order to get the info we need, but libads
+ doesn't offer a better way right now */
+ ads_connect(ads);
+#endif
+
+ if (!ads->config.realm)
+ return False;
+
+ fstrcpy(srv_name, ads->config.ldap_server_name);
+ strupper_m(srv_name);
+ *dc_ip = ads->ldap_ip;
+ ads_destroy(&ads);
+
+ DEBUG(4,("ads_dc_name: using server='%s' IP=%s\n",
+ srv_name, inet_ntoa(*dc_ip)));
+
+ return True;
+}
+
+/****************************************************************************
+ Utility function to return the name of a DC. The name is guaranteed to be
+ valid since we have already done a name_status_find on it
+ ***************************************************************************/
+
+static BOOL rpc_dc_name(const char *domain, fstring srv_name, struct in_addr *ip_out)
{
- struct in_addr *ip_list = NULL, dc_ip, exclude_ip;
+ struct ip_service *ip_list = NULL;
+ struct in_addr dc_ip, exclude_ip;
int count, i;
- BOOL list_ordered;
BOOL use_pdc_only;
+ NTSTATUS result;
zero_ip(&exclude_ip);
@@ -41,11 +86,17 @@ BOOL rpc_find_dc(const char *domain, fstring srv_name, struct in_addr *ip_out)
/* Lookup domain controller name */
- if ( use_pdc_only && get_pdc_ip(domain, &dc_ip) ) {
- DEBUG(10,("rpc_find_dc: Atempting to lookup PDC to avoid sam sync delays\n"));
+ if ( use_pdc_only && get_pdc_ip(domain, &dc_ip) )
+ {
+ DEBUG(10,("rpc_dc_name: Atempting to lookup PDC to avoid sam sync delays\n"));
- if (name_status_find(domain, 0x1c, 0x20, dc_ip, srv_name)) {
- goto done;
+ /* check the connection cache and perform the node status
+ lookup only if the IP is not found to be bad */
+
+ if (name_status_find(domain, 0x1b, 0x20, dc_ip, srv_name) ) {
+ result = check_negative_conn_cache( domain, srv_name );
+ if ( NT_STATUS_IS_OK(result) )
+ goto done;
}
/* Didn't get name, remember not to talk to this DC. */
exclude_ip = dc_ip;
@@ -53,7 +104,7 @@ BOOL rpc_find_dc(const char *domain, fstring srv_name, struct in_addr *ip_out)
/* get a list of all domain controllers */
- if (!get_dc_list( domain, &ip_list, &count, &list_ordered) ) {
+ if ( !get_sorted_dc_list(domain, &ip_list, &count, False) ) {
DEBUG(3, ("Could not look up dc's for domain %s\n", domain));
return False;
}
@@ -62,37 +113,37 @@ BOOL rpc_find_dc(const char *domain, fstring srv_name, struct in_addr *ip_out)
if ( use_pdc_only ) {
for (i = 0; i < count; i++) {
- if (ip_equal( exclude_ip, ip_list[i]))
- zero_ip(&ip_list[i]);
+ if (ip_equal( exclude_ip, ip_list[i].ip))
+ zero_ip(&ip_list[i].ip);
}
}
- /* Pick a nice close server, but only if the list was not ordered */
- if (!list_ordered && (count > 1) ) {
- qsort(ip_list, count, sizeof(struct in_addr), QSORT_CAST ip_compare);
- }
-
for (i = 0; i < count; i++) {
- if (is_zero_ip(ip_list[i]))
+ if (is_zero_ip(ip_list[i].ip))
continue;
- if (name_status_find(domain, 0x1c, 0x20, ip_list[i], srv_name)) {
- dc_ip = ip_list[i];
- goto done;
+ if (name_status_find(domain, 0x1c, 0x20, ip_list[i].ip, srv_name)) {
+ result = check_negative_conn_cache( domain, srv_name );
+ if ( NT_STATUS_IS_OK(result) ) {
+ dc_ip = ip_list[i].ip;
+ goto done;
+ }
}
}
-
+
SAFE_FREE(ip_list);
- return False;
-done:
+ /* No-one to talk to )-: */
+ return False; /* Boo-hoo */
+
+ done:
/* We have the netbios name and IP address of a domain controller.
Ideally we should sent a SAMLOGON request to determine whether
the DC is alive and kicking. If we can catch a dead DC before
performing a cli_connect() we can avoid a 30-second timeout. */
- DEBUG(3, ("rpc_find_dc: Returning DC %s (%s) for domain %s\n", srv_name,
+ DEBUG(3, ("rpc_dc_name: Returning DC %s (%s) for domain %s\n", srv_name,
inet_ntoa(dc_ip), domain));
*ip_out = dc_ip;
@@ -102,3 +153,28 @@ done:
return True;
}
+/**********************************************************************
+ wrapper around ads and rpc methods of finds DC's
+**********************************************************************/
+
+BOOL get_dc_name(const char *domain, fstring srv_name, struct in_addr *ip_out)
+{
+ struct in_addr dc_ip;
+ BOOL ret;
+
+ zero_ip(&dc_ip);
+
+ ret = False;
+ if (lp_security() == SEC_ADS)
+ ret = ads_dc_name(domain, &dc_ip, srv_name);
+
+ if (!ret) {
+ /* fall back on rpc methods if the ADS methods fail */
+ ret = rpc_dc_name(domain, srv_name, &dc_ip);
+ }
+
+ *ip_out = dc_ip;
+
+ return ret;
+}
+
diff --git a/source3/libsmb/nmblib.c b/source3/libsmb/nmblib.c
index 30ce5b6b10..157a2bb43c 100644
--- a/source3/libsmb/nmblib.c
+++ b/source3/libsmb/nmblib.c
@@ -295,7 +295,7 @@ static int put_nmb_name(char *buf,int offset,struct nmb_name *name)
if (name->scope[0]) {
/* XXXX this scope handling needs testing */
ret += strlen(name->scope) + 1;
- pstrcpy(&buf[offset+1],name->scope);
+ safe_strcpy(&buf[offset+1],name->scope,sizeof(name->scope));
p = &buf[offset+1];
while ((p = strchr_m(p,'.'))) {
@@ -823,7 +823,7 @@ void make_nmb_name( struct nmb_name *n, const char *name, int type)
push_ascii(n->name, name, 16, STR_TERMINATE|STR_UPPER);
n->name_type = (unsigned int)type & 0xFF;
StrnCpy( n->scope, global_scope(), 63 );
- strupper( n->scope );
+ strupper_m( n->scope );
}
/*******************************************************************
diff --git a/source3/libsmb/ntlmssp.c b/source3/libsmb/ntlmssp.c
index d54655d17f..66dc6e08eb 100644
--- a/source3/libsmb/ntlmssp.c
+++ b/source3/libsmb/ntlmssp.c
@@ -175,11 +175,11 @@ static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state,
/* This should be a 'netbios domain -> DNS domain' mapping */
dnsdomname[0] = '\0';
get_mydomname(dnsdomname);
- strlower(dnsdomname);
+ strlower_m(dnsdomname);
dnsname[0] = '\0';
get_myfullname(dnsname);
- strlower(dnsname);
+ strlower_m(dnsname);
if (chal_flags & NTLMSSP_CHAL_TARGET_INFO)
{
@@ -190,7 +190,6 @@ static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state,
target_name_dns = dnsname;
}
- /* the numbers here are the string type flags */
msrpc_gen(&struct_blob, "aaaaa",
ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_DOMAIN, target_name,
ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_SERVER, ntlmssp_state->get_global_myname(),
@@ -410,6 +409,10 @@ static NTSTATUS ntlmssp_client_initial(struct ntlmssp_client_state *ntlmssp_stat
ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE;
}
+ if (ntlmssp_state->use_ntlmv2) {
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2;
+ }
+
/* generate the ntlmssp negotiate packet */
msrpc_gen(next_request, "CddAA",
"NTLMSSP",
@@ -436,7 +439,7 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_st
uint32 chal_flags, ntlmssp_command, unkn1, unkn2;
DATA_BLOB server_domain_blob;
DATA_BLOB challenge_blob;
- DATA_BLOB struct_blob;
+ DATA_BLOB struct_blob = data_blob(NULL, 0);
char *server_domain;
const char *chal_parse_string;
const char *auth_gen_string;
@@ -444,28 +447,48 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_st
DATA_BLOB nt_response = data_blob(NULL, 0);
DATA_BLOB session_key = data_blob(NULL, 0);
uint8 datagram_sess_key[16];
+ size_t datagram_sess_key_len;
+#if 0 /* until we know what flag to tigger it on */
generate_random_buffer(datagram_sess_key, sizeof(datagram_sess_key), False);
+ datagram_sess_key_len = sizeof(datagram_sess_key);
+#else
+ ZERO_STRUCT(datagram_sess_key);
+ datagram_sess_key_len = 0;
+#endif
if (!msrpc_parse(&reply, "CdBd",
"NTLMSSP",
&ntlmssp_command,
&server_domain_blob,
&chal_flags)) {
- DEBUG(0, ("Failed to parse the NTLMSSP Challenge\n"));
+ DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#1)\n"));
+ dump_data(2, reply.data, reply.length);
+
return NT_STATUS_INVALID_PARAMETER;
}
data_blob_free(&server_domain_blob);
+ DEBUG(3, ("Got challenge flags:\n"));
+ debug_ntlmssp_flags(chal_flags);
+
if (chal_flags & NTLMSSP_NEGOTIATE_UNICODE) {
- chal_parse_string = "CdUdbddB";
+ if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) {
+ chal_parse_string = "CdUdbddB";
+ } else {
+ chal_parse_string = "CdUdbdd";
+ }
auth_gen_string = "CdBBUUUBd";
ntlmssp_state->unicode = True;
ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE;
ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_OEM;
} else if (chal_flags & NTLMSSP_NEGOTIATE_OEM) {
- chal_parse_string = "CdAdbddB";
+ if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) {
+ chal_parse_string = "CdAdbddB";
+ } else {
+ chal_parse_string = "CdAdbdd";
+ }
auth_gen_string = "CdBBAAABd";
ntlmssp_state->unicode = False;
ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_UNICODE;
@@ -474,6 +497,25 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_st
return NT_STATUS_INVALID_PARAMETER;
}
+ if (chal_flags & NTLMSSP_NEGOTIATE_LM_KEY && lp_client_lanman_auth()) {
+ /* server forcing us to use LM */
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_LM_KEY;
+ ntlmssp_state->use_ntlmv2 = False;
+ } else {
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
+ }
+
+ if (!(chal_flags & NTLMSSP_NEGOTIATE_NTLM2)) {
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
+ }
+
+ if (!(chal_flags & NTLMSSP_NEGOTIATE_128)) {
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_128;
+ }
+
+ DEBUG(3, ("NTLMSSP: Set final flags:\n"));
+ debug_ntlmssp_flags(ntlmssp_state->neg_flags);
+
if (!msrpc_parse(&reply, chal_parse_string,
"NTLMSSP",
&ntlmssp_command,
@@ -482,34 +524,43 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_st
&challenge_blob, 8,
&unkn1, &unkn2,
&struct_blob)) {
- DEBUG(0, ("Failed to parse the NTLMSSP Challenge\n"));
+ DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#2)\n"));
+ dump_data(2, reply.data, reply.length);
return NT_STATUS_INVALID_PARAMETER;
}
SAFE_FREE(server_domain);
- data_blob_free(&struct_blob);
-
if (challenge_blob.length != 8) {
+ data_blob_free(&struct_blob);
return NT_STATUS_INVALID_PARAMETER;
}
if (ntlmssp_state->use_ntlmv2) {
+ if (!struct_blob.length) {
+ /* be lazy, match win2k - we can't do NTLMv2 without it */
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
/* TODO: if the remote server is standalone, then we should replace 'domain'
with the server name as supplied above */
if (!SMBNTLMv2encrypt(ntlmssp_state->user,
ntlmssp_state->domain,
- ntlmssp_state->password, challenge_blob,
+ ntlmssp_state->password, &challenge_blob,
+ &struct_blob,
&lm_response, &nt_response, &session_key)) {
data_blob_free(&challenge_blob);
+ data_blob_free(&struct_blob);
return NT_STATUS_NO_MEMORY;
}
} else {
+ uchar lm_hash[16];
uchar nt_hash[16];
+ E_deshash(ntlmssp_state->password, lm_hash);
E_md4hash(ntlmssp_state->password, nt_hash);
- /* non encrypted password supplied. Ignore ntpass. */
+ /* lanman auth is insecure, it may be disabled */
if (lp_client_lanman_auth()) {
lm_response = data_blob(NULL, 24);
SMBencrypt(ntlmssp_state->password,challenge_blob.data,
@@ -519,9 +570,17 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_st
nt_response = data_blob(NULL, 24);
SMBNTencrypt(ntlmssp_state->password,challenge_blob.data,
nt_response.data);
+
session_key = data_blob(NULL, 16);
- SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data);
+ if ((ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY)
+ && lp_client_lanman_auth()) {
+ SMBsesskeygen_lmv1(lm_hash, lm_response.data,
+ session_key.data);
+ } else {
+ SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data);
+ }
}
+ data_blob_free(&struct_blob);
/* this generates the actual auth packet */
if (!msrpc_gen(next_request, auth_gen_string,
@@ -532,7 +591,7 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_st
ntlmssp_state->domain,
ntlmssp_state->user,
ntlmssp_state->get_global_myname(),
- datagram_sess_key, 16,
+ datagram_sess_key, datagram_sess_key_len,
ntlmssp_state->neg_flags)) {
data_blob_free(&lm_response);
@@ -574,6 +633,8 @@ NTSTATUS ntlmssp_client_start(NTLMSSP_CLIENT_STATE **ntlmssp_state)
(*ntlmssp_state)->unicode = True;
+ (*ntlmssp_state)->use_ntlmv2 = lp_client_ntlmv2_auth();
+
(*ntlmssp_state)->neg_flags =
NTLMSSP_NEGOTIATE_128 |
NTLMSSP_NEGOTIATE_NTLM |
@@ -595,6 +656,7 @@ NTSTATUS ntlmssp_client_end(NTLMSSP_CLIENT_STATE **ntlmssp_state)
data_blob_free(&(*ntlmssp_state)->lm_resp);
data_blob_free(&(*ntlmssp_state)->nt_resp);
data_blob_free(&(*ntlmssp_state)->session_key);
+ data_blob_free(&(*ntlmssp_state)->stored_response);
talloc_destroy(mem_ctx);
}
@@ -605,12 +667,18 @@ NTSTATUS ntlmssp_client_end(NTLMSSP_CLIENT_STATE **ntlmssp_state)
NTSTATUS ntlmssp_client_update(NTLMSSP_CLIENT_STATE *ntlmssp_state,
DATA_BLOB reply, DATA_BLOB *next_request)
{
+ NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
uint32 ntlmssp_command;
*next_request = data_blob(NULL, 0);
if (!reply.length) {
- return ntlmssp_client_initial(ntlmssp_state, reply, next_request);
- }
+ /* If there is a cached reply, use it - otherwise this is the first packet */
+ if (!ntlmssp_state->stored_response.length) {
+ return ntlmssp_client_initial(ntlmssp_state, reply, next_request);
+ }
+
+ reply = ntlmssp_state->stored_response;
+ }
if (!msrpc_parse(&reply, "Cd",
"NTLMSSP",
@@ -619,9 +687,12 @@ NTSTATUS ntlmssp_client_update(NTLMSSP_CLIENT_STATE *ntlmssp_state,
}
if (ntlmssp_command == NTLMSSP_CHALLENGE) {
- return ntlmssp_client_challenge(ntlmssp_state, reply, next_request);
+ nt_status = ntlmssp_client_challenge(ntlmssp_state, reply, next_request);
+ }
+ if (ntlmssp_state->stored_response.length) {
+ data_blob_free(&ntlmssp_state->stored_response);
}
- return NT_STATUS_INVALID_PARAMETER;
+ return nt_status;
}
NTSTATUS ntlmssp_set_username(NTLMSSP_CLIENT_STATE *ntlmssp_state, const char *user)
@@ -650,3 +721,16 @@ NTSTATUS ntlmssp_set_domain(NTLMSSP_CLIENT_STATE *ntlmssp_state, const char *dom
}
return NT_STATUS_OK;
}
+
+/**
+ * Store a DATA_BLOB containing an NTLMSSP response, for use later.
+ * This 'keeps' the data blob - the caller must *not* free it.
+ */
+
+NTSTATUS ntlmssp_client_store_response(NTLMSSP_CLIENT_STATE *ntlmssp_state,
+ DATA_BLOB response)
+{
+ data_blob_free(&ntlmssp_state->stored_response);
+ ntlmssp_state->stored_response = response;
+ return NT_STATUS_OK;
+}
diff --git a/source3/libsmb/ntlmssp_parse.c b/source3/libsmb/ntlmssp_parse.c
index ac779a3906..f53afcdcd0 100644
--- a/source3/libsmb/ntlmssp_parse.c
+++ b/source3/libsmb/ntlmssp_parse.c
@@ -220,23 +220,27 @@ BOOL msrpc_parse(const DATA_BLOB *blob,
len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
ptr = IVAL(blob->data, head_ofs); head_ofs += 4;
- /* make sure its in the right format - be strict */
- if (len1 != len2 || ptr + len1 > blob->length) {
- return False;
- }
- if (len1 & 1) {
- /* if odd length and unicode */
- return False;
- }
-
ps = va_arg(ap, char **);
- if (0 < len1) {
- pull_string(NULL, p, blob->data + ptr, sizeof(p),
- len1,
- STR_UNICODE|STR_NOALIGN);
- (*ps) = smb_xstrdup(p);
+ if (len1 == 0 && len2 == 0) {
+ *ps = smb_xstrdup("");
} else {
- (*ps) = smb_xstrdup("");
+ /* make sure its in the right format - be strict */
+ if (len1 != len2 || ptr + len1 > blob->length) {
+ return False;
+ }
+ if (len1 & 1) {
+ /* if odd length and unicode */
+ return False;
+ }
+
+ if (0 < len1) {
+ pull_string(NULL, p, blob->data + ptr, sizeof(p),
+ len1,
+ STR_UNICODE|STR_NOALIGN);
+ (*ps) = smb_xstrdup(p);
+ } else {
+ (*ps) = smb_xstrdup("");
+ }
}
break;
case 'A':
@@ -245,19 +249,23 @@ BOOL msrpc_parse(const DATA_BLOB *blob,
len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
ptr = IVAL(blob->data, head_ofs); head_ofs += 4;
- /* make sure its in the right format - be strict */
- if (len1 != len2 || ptr + len1 > blob->length) {
- return False;
- }
-
ps = va_arg(ap, char **);
- if (0 < len1) {
- pull_string(NULL, p, blob->data + ptr, sizeof(p),
- len1,
- STR_ASCII|STR_NOALIGN);
- (*ps) = smb_xstrdup(p);
+ /* make sure its in the right format - be strict */
+ if (len1 == 0 && len2 == 0) {
+ *ps = smb_xstrdup("");
} else {
- (*ps) = smb_xstrdup("");
+ if (len1 != len2 || ptr + len1 > blob->length) {
+ return False;
+ }
+
+ if (0 < len1) {
+ pull_string(NULL, p, blob->data + ptr, sizeof(p),
+ len1,
+ STR_ASCII|STR_NOALIGN);
+ (*ps) = smb_xstrdup(p);
+ } else {
+ (*ps) = smb_xstrdup("");
+ }
}
break;
case 'B':
@@ -265,12 +273,17 @@ BOOL msrpc_parse(const DATA_BLOB *blob,
len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
ptr = IVAL(blob->data, head_ofs); head_ofs += 4;
- /* make sure its in the right format - be strict */
- if (len1 != len2 || ptr + len1 > blob->length) {
- return False;
- }
+
b = (DATA_BLOB *)va_arg(ap, void *);
- *b = data_blob(blob->data + ptr, len1);
+ if (len1 == 0 && len2 == 0) {
+ *b = data_blob(NULL, 0);
+ } else {
+ /* make sure its in the right format - be strict */
+ if (len1 != len2 || ptr + len1 > blob->length) {
+ return False;
+ }
+ *b = data_blob(blob->data + ptr, len1);
+ }
break;
case 'b':
b = (DATA_BLOB *)va_arg(ap, void *);
diff --git a/source3/libsmb/ntlmssp_sign.c b/source3/libsmb/ntlmssp_sign.c
index 86faf1f5e6..748c008963 100644
--- a/source3/libsmb/ntlmssp_sign.c
+++ b/source3/libsmb/ntlmssp_sign.c
@@ -79,13 +79,18 @@ static void calc_hash(unsigned char *hash, const char *k2, int k2l)
}
static void calc_ntlmv2_hash(unsigned char hash[16], char digest[16],
- const char encrypted_response[16],
+ DATA_BLOB session_key,
const char *constant)
{
struct MD5Context ctx3;
+ /* NOTE: This code is currently complate fantasy - it's
+ got more in common with reality than the previous code
+ (the LM session key is not the right thing to use) but
+ it still needs work */
+
MD5Init(&ctx3);
- MD5Update(&ctx3, encrypted_response, 5);
+ MD5Update(&ctx3, session_key.data, session_key.length);
MD5Update(&ctx3, constant, strlen(constant));
MD5Final(digest, &ctx3);
@@ -113,25 +118,28 @@ static NTSTATUS ntlmssp_make_packet_signiture(NTLMSSP_CLIENT_STATE *ntlmssp_stat
hmac_md5_update(data, length, &ctx);
hmac_md5_final(digest, &ctx);
- if (!msrpc_gen(sig, "Bd", digest, sizeof(digest), ntlmssp_state->ntlmssp_seq_num)) {
+ if (!msrpc_gen(sig, "dBd", NTLMSSP_SIGN_VERSION, digest, 8 /* only copy first 8 bytes */
+ , ntlmssp_state->ntlmssp_seq_num)) {
return NT_STATUS_NO_MEMORY;
}
switch (direction) {
case NTLMSSP_SEND:
- NTLMSSPcalc_ap(ntlmssp_state->cli_sign_hash, sig->data, sig->length);
+ NTLMSSPcalc_ap(ntlmssp_state->cli_sign_hash, sig->data+4, sig->length-4);
break;
case NTLMSSP_RECEIVE:
- NTLMSSPcalc_ap(ntlmssp_state->srv_sign_hash, sig->data, sig->length);
+ NTLMSSPcalc_ap(ntlmssp_state->srv_sign_hash, sig->data+4, sig->length-4);
break;
}
} else {
uint32 crc;
crc = crc32_calc_buffer(data, length);
- if (!msrpc_gen(sig, "ddd", 0, crc, ntlmssp_state->ntlmssp_seq_num)) {
+ if (!msrpc_gen(sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmssp_seq_num)) {
return NT_STATUS_NO_MEMORY;
}
- NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, sig->data, sig->length);
+ dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
+ sizeof(ntlmssp_state->ntlmssp_hash));
+ NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, sig->data+4, sig->length-4);
}
return NT_STATUS_OK;
}
@@ -140,8 +148,11 @@ NTSTATUS ntlmssp_client_sign_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
const uchar *data, size_t length,
DATA_BLOB *sig)
{
+ NTSTATUS nt_status = ntlmssp_make_packet_signiture(ntlmssp_state, data, length, NTLMSSP_SEND, sig);
+
+ /* increment counter on send */
ntlmssp_state->ntlmssp_seq_num++;
- return ntlmssp_make_packet_signiture(ntlmssp_state, data, length, NTLMSSP_SEND, sig);
+ return nt_status;
}
/**
@@ -151,8 +162,8 @@ NTSTATUS ntlmssp_client_sign_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
*/
NTSTATUS ntlmssp_client_check_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
- const uchar *data, size_t length,
- const DATA_BLOB *sig)
+ const uchar *data, size_t length,
+ const DATA_BLOB *sig)
{
DATA_BLOB local_sig;
NTSTATUS nt_status;
@@ -170,9 +181,7 @@ NTSTATUS ntlmssp_client_check_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
return nt_status;
}
- if (memcmp(sig->data, local_sig.data, MIN(sig->length, local_sig.length)) == 0) {
- return NT_STATUS_OK;
- } else {
+ if (memcmp(sig->data+sig->length - 8, local_sig.data+local_sig.length - 8, 8) != 0) {
DEBUG(5, ("BAD SIG: wanted signature of\n"));
dump_data(5, local_sig.data, local_sig.length);
@@ -182,6 +191,97 @@ NTSTATUS ntlmssp_client_check_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
DEBUG(0, ("NTLMSSP packet check failed due to invalid signiture!\n"));
return NT_STATUS_ACCESS_DENIED;
}
+
+ /* increment counter on recieive */
+ ntlmssp_state->ntlmssp_seq_num++;
+
+ return NT_STATUS_OK;
+}
+
+
+/**
+ * Seal data with the NTLMSSP algorithm
+ *
+ */
+
+NTSTATUS ntlmssp_client_seal_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
+ uchar *data, size_t length,
+ DATA_BLOB *sig)
+{
+ DEBUG(10,("ntlmssp_client_seal_data: seal\n"));
+ dump_data_pw("ntlmssp clear data\n", data, length);
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+ HMACMD5Context ctx;
+ char seq_num[4];
+ uchar digest[16];
+ SIVAL(seq_num, 0, ntlmssp_state->ntlmssp_seq_num);
+
+ hmac_md5_init_limK_to_64(ntlmssp_state->cli_sign_const, 16, &ctx);
+ hmac_md5_update(seq_num, 4, &ctx);
+ hmac_md5_update(data, length, &ctx);
+ hmac_md5_final(digest, &ctx);
+
+ if (!msrpc_gen(sig, "dBd", NTLMSSP_SIGN_VERSION, digest, 8 /* only copy first 8 bytes */
+ , ntlmssp_state->ntlmssp_seq_num)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ dump_data_pw("ntlmssp client sealing hash:\n",
+ ntlmssp_state->cli_seal_hash,
+ sizeof(ntlmssp_state->cli_seal_hash));
+ NTLMSSPcalc_ap(ntlmssp_state->cli_seal_hash, data, length);
+ dump_data_pw("ntlmssp client signing hash:\n",
+ ntlmssp_state->cli_sign_hash,
+ sizeof(ntlmssp_state->cli_sign_hash));
+ NTLMSSPcalc_ap(ntlmssp_state->cli_sign_hash, sig->data+4, sig->length-4);
+ } else {
+ uint32 crc;
+ crc = crc32_calc_buffer(data, length);
+ if (!msrpc_gen(sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmssp_seq_num)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* The order of these two operations matters - we must first seal the packet,
+ then seal the sequence number - this is becouse the ntlmssp_hash is not
+ constant, but is is rather updated with each iteration */
+
+ dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
+ sizeof(ntlmssp_state->ntlmssp_hash));
+ NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, data, length);
+
+ dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
+ sizeof(ntlmssp_state->ntlmssp_hash));
+ NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, sig->data+4, sig->length-4);
+ }
+ dump_data_pw("ntlmssp sealed data\n", data, length);
+
+ /* increment counter on send */
+ ntlmssp_state->ntlmssp_seq_num++;
+
+ return NT_STATUS_OK;
+}
+
+/**
+ * Unseal data with the NTLMSSP algorithm
+ *
+ */
+
+NTSTATUS ntlmssp_client_unseal_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
+ uchar *data, size_t length,
+ DATA_BLOB *sig)
+{
+ DEBUG(10,("ntlmssp_client_unseal_data: seal\n"));
+ dump_data_pw("ntlmssp sealed data\n", data, length);
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+ NTLMSSPcalc_ap(ntlmssp_state->srv_seal_hash, data, length);
+ } else {
+ dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
+ sizeof(ntlmssp_state->ntlmssp_hash));
+ NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, data, length);
+ }
+ dump_data_pw("ntlmssp clear data\n", data, length);
+
+ return ntlmssp_client_check_packet(ntlmssp_state, data, length, sig);
}
/**
@@ -190,37 +290,69 @@ NTSTATUS ntlmssp_client_check_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
NTSTATUS ntlmssp_client_sign_init(NTLMSSP_CLIENT_STATE *ntlmssp_state)
{
unsigned char p24[24];
- unsigned char lm_hash[16];
+ ZERO_STRUCT(p24);
+
+ DEBUG(3, ("NTLMSSP Sign/Seal - Initialising with flags:\n"));
+ debug_ntlmssp_flags(ntlmssp_state->neg_flags);
- if (!ntlmssp_state->lm_resp.data) {
- /* can't sign or check signitures yet */
- return NT_STATUS_UNSUCCESSFUL;
- }
-
- E_deshash(ntlmssp_state->password, lm_hash);
-
- NTLMSSPOWFencrypt(lm_hash, ntlmssp_state->lm_resp.data, p24);
-
if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2)
{
- calc_ntlmv2_hash(ntlmssp_state->cli_sign_hash, ntlmssp_state->cli_sign_const, p24, CLI_SIGN);
- calc_ntlmv2_hash(ntlmssp_state->cli_seal_hash, ntlmssp_state->cli_seal_const, p24, CLI_SEAL);
- calc_ntlmv2_hash(ntlmssp_state->srv_sign_hash, ntlmssp_state->srv_sign_const, p24, SRV_SIGN);
- calc_ntlmv2_hash(ntlmssp_state->srv_seal_hash, ntlmssp_state->srv_seal_const, p24, SRV_SEAL);
- }
- else
- {
- char k2[8];
- memcpy(k2, p24, 5);
- k2[5] = 0xe5;
- k2[6] = 0x38;
- k2[7] = 0xb0;
+
+ calc_ntlmv2_hash(ntlmssp_state->cli_sign_hash,
+ ntlmssp_state->cli_sign_const,
+ ntlmssp_state->session_key, CLI_SIGN);
+ dump_data_pw("NTLMSSP client sign hash:\n",
+ ntlmssp_state->cli_sign_hash,
+ sizeof(ntlmssp_state->cli_sign_hash));
+
+ calc_ntlmv2_hash(ntlmssp_state->cli_seal_hash,
+ ntlmssp_state->cli_seal_const,
+ ntlmssp_state->session_key, CLI_SEAL);
+ dump_data_pw("NTLMSSP client sesl hash:\n",
+ ntlmssp_state->cli_seal_hash,
+ sizeof(ntlmssp_state->cli_seal_hash));
+
+ calc_ntlmv2_hash(ntlmssp_state->srv_sign_hash,
+ ntlmssp_state->srv_sign_const,
+ ntlmssp_state->session_key, SRV_SIGN);
+ dump_data_pw("NTLMSSP server sign hash:\n",
+ ntlmssp_state->srv_sign_hash,
+ sizeof(ntlmssp_state->srv_sign_hash));
+
+ calc_ntlmv2_hash(ntlmssp_state->srv_seal_hash,
+ ntlmssp_state->srv_seal_const,
+ ntlmssp_state->session_key, SRV_SEAL);
+ dump_data_pw("NTLMSSP server seal hash:\n",
+ ntlmssp_state->cli_sign_hash,
+ sizeof(ntlmssp_state->cli_sign_hash));
+ }
+ else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) {
+ if (!ntlmssp_state->session_key.data || ntlmssp_state->session_key.length < 8) {
+ /* can't sign or check signitures yet */
+ DEBUG(5, ("NTLMSSP Sign/Seal - cannot use LM KEY yet\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ DEBUG(5, ("NTLMSSP Sign/Seal - using LM KEY\n"));
+
+ calc_hash(ntlmssp_state->ntlmssp_hash, ntlmssp_state->session_key.data, 8);
+ dump_data_pw("NTLMSSP hash:\n", ntlmssp_state->ntlmssp_hash,
+ sizeof(ntlmssp_state->ntlmssp_hash));
+ } else {
+ if (!ntlmssp_state->session_key.data || ntlmssp_state->session_key.length < 16) {
+ /* can't sign or check signitures yet */
+ DEBUG(5, ("NTLMSSP Sign/Seal - cannot use NT KEY yet\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
- calc_hash(ntlmssp_state->ntlmssp_hash, k2, 8);
+ DEBUG(5, ("NTLMSSP Sign/Seal - using NT KEY\n"));
+
+ calc_hash(ntlmssp_state->ntlmssp_hash, ntlmssp_state->session_key.data, 16);
+ dump_data_pw("NTLMSSP hash:\n", ntlmssp_state->ntlmssp_hash,
+ sizeof(ntlmssp_state->ntlmssp_hash));
}
ntlmssp_state->ntlmssp_seq_num = 0;
- ZERO_STRUCT(lm_hash);
return NT_STATUS_OK;
}
diff --git a/source3/libsmb/pwd_cache.c b/source3/libsmb/pwd_cache.c
index 7ddcf853c4..f45832d7d7 100644
--- a/source3/libsmb/pwd_cache.c
+++ b/source3/libsmb/pwd_cache.c
@@ -43,15 +43,10 @@ static void pwd_init(struct pwd_info *pwd)
static void pwd_make_lm_nt_16(struct pwd_info *pwd, const char *clr)
{
- pstring dos_passwd;
-
pwd_init(pwd);
- push_ascii_pstring(dos_passwd, clr);
-
- nt_lm_owf_gen(dos_passwd, pwd->smb_nt_pwd, pwd->smb_lm_pwd);
+ nt_lm_owf_gen(clr, pwd->smb_nt_pwd, pwd->smb_lm_pwd);
pwd->null_pwd = False;
- pwd->cleartext = False;
pwd->crypted = False;
}
@@ -61,12 +56,9 @@ static void pwd_make_lm_nt_16(struct pwd_info *pwd, const char *clr)
void pwd_set_cleartext(struct pwd_info *pwd, const char *clr)
{
- pwd_init(pwd);
- push_ascii_fstring(pwd->password, clr);
- pwd->cleartext = True;
- pwd->null_pwd = False;
- pwd->crypted = False;
pwd_make_lm_nt_16(pwd, clr);
+ fstrcpy(pwd->password, clr);
+ pwd->cleartext = True;
}
/****************************************************************************
diff --git a/source3/libsmb/smb_signing.c b/source3/libsmb/smb_signing.c
index 4e9b895a1b..d4f77bf07c 100644
--- a/source3/libsmb/smb_signing.c
+++ b/source3/libsmb/smb_signing.c
@@ -21,20 +21,58 @@
#include "includes.h"
+/* Lookup a packet's MID (multiplex id) and figure out it's sequence number */
+struct outstanding_packet_lookup {
+ uint16 mid;
+ uint32 reply_seq_num;
+ struct outstanding_packet_lookup *prev, *next;
+};
+
struct smb_basic_signing_context {
DATA_BLOB mac_key;
uint32 send_seq_num;
- uint32 reply_seq_num;
+ struct outstanding_packet_lookup *outstanding_packet_list;
};
+static void store_sequence_for_reply(struct outstanding_packet_lookup **list,
+ uint16 mid, uint32 reply_seq_num)
+{
+ struct outstanding_packet_lookup *t;
+ struct outstanding_packet_lookup *tmp;
+
+ t = smb_xmalloc(sizeof(*t));
+ ZERO_STRUCTP(t);
+
+ DLIST_ADD_END(*list, t, tmp);
+ t->mid = mid;
+ t->reply_seq_num = reply_seq_num;
+}
+
+static BOOL get_sequence_for_reply(struct outstanding_packet_lookup **list,
+ uint16 mid, uint32 *reply_seq_num)
+{
+ struct outstanding_packet_lookup *t;
+
+ for (t = *list; t; t = t->next) {
+ if (t->mid == mid) {
+ *reply_seq_num = t->reply_seq_num;
+ DLIST_REMOVE(*list, t);
+ return True;
+ }
+ }
+ DEBUG(0, ("Unexpected incoming packet, it's MID (%u) does not match"
+ " a MID in our outstanding list!\n", mid));
+ return False;
+}
+
/***********************************************************
SMB signing - Common code before we set a new signing implementation
************************************************************/
-static BOOL set_smb_signing_common(struct cli_state *cli)
+static BOOL cli_set_smb_signing_common(struct cli_state *cli)
{
if (!cli->sign_info.negotiated_smb_signing
- && !cli->sign_info.mandetory_signing) {
+ && !cli->sign_info.mandatory_signing) {
return False;
}
@@ -56,9 +94,9 @@ static BOOL set_smb_signing_common(struct cli_state *cli)
SMB signing - Common code for 'real' implementations
************************************************************/
-static BOOL set_smb_signing_real_common(struct cli_state *cli)
+static BOOL cli_set_smb_signing_real_common(struct cli_state *cli)
{
- if (cli->sign_info.mandetory_signing) {
+ if (cli->sign_info.mandatory_signing) {
DEBUG(5, ("Mandatory SMB signing enabled!\n"));
cli->sign_info.doing_signing = True;
}
@@ -68,7 +106,7 @@ static BOOL set_smb_signing_real_common(struct cli_state *cli)
return True;
}
-static void mark_packet_signed(struct cli_state *cli)
+static void cli_mark_packet_signed(struct cli_state *cli)
{
uint16 flags2;
flags2 = SVAL(cli->outbuf,smb_flg2);
@@ -76,7 +114,7 @@ static void mark_packet_signed(struct cli_state *cli)
SSVAL(cli->outbuf,smb_flg2, flags2);
}
-static BOOL signing_good(struct cli_state *cli, BOOL good)
+static BOOL cli_signing_good(struct cli_state *cli, BOOL good)
{
DEBUG(10, ("got SMB signature of\n"));
dump_data(10,&cli->inbuf[smb_ss_field] , 8);
@@ -99,32 +137,67 @@ static BOOL signing_good(struct cli_state *cli, BOOL good)
}
/***********************************************************
- SMB signing - Simple implementation - calculate a MAC to send.
+ SMB signing - Simple implementation - calculate a MAC on the packet
************************************************************/
-static void cli_simple_sign_outgoing_message(struct cli_state *cli)
+static void simple_packet_signature(struct smb_basic_signing_context *data,
+ const uchar *buf, uint32 seq_number,
+ unsigned char calc_md5_mac[16])
{
- unsigned char calc_md5_mac[16];
+ const size_t offset_end_of_sig = (smb_ss_field + 8);
+ unsigned char sequence_buf[8];
struct MD5Context md5_ctx;
- struct smb_basic_signing_context *data = cli->sign_info.signing_context;
/*
* Firstly put the sequence number into the first 4 bytes.
* and zero out the next 4 bytes.
+ *
+ * We do this here, to avoid modifying the packet.
*/
- SIVAL(cli->outbuf, smb_ss_field,
- data->send_seq_num);
- SIVAL(cli->outbuf, smb_ss_field + 4, 0);
- /* mark the packet as signed - BEFORE we sign it...*/
- mark_packet_signed(cli);
+ SIVAL(sequence_buf, 0, seq_number);
+ SIVAL(sequence_buf, 4, 0);
- /* Calculate the 16 byte MAC and place first 8 bytes into the field. */
+ /* Calculate the 16 byte MAC - but don't alter the data in the
+ incoming packet.
+
+ This makes for a bit for fussing about, but it's not too bad.
+ */
MD5Init(&md5_ctx);
+
+ /* intialise with the key */
MD5Update(&md5_ctx, data->mac_key.data,
data->mac_key.length);
- MD5Update(&md5_ctx, cli->outbuf + 4, smb_len(cli->outbuf));
+
+ /* copy in the first bit of the SMB header */
+ MD5Update(&md5_ctx, buf + 4, smb_ss_field - 4);
+
+ /* copy in the sequence number, instead of the signature */
+ MD5Update(&md5_ctx, sequence_buf, sizeof(sequence_buf));
+
+ /* copy in the rest of the packet in, skipping the signature */
+ MD5Update(&md5_ctx, buf + offset_end_of_sig,
+ smb_len(buf) - (offset_end_of_sig - 4));
+
+ /* caclulate the MD5 sig */
MD5Final(calc_md5_mac, &md5_ctx);
+}
+
+
+/***********************************************************
+ SMB signing - Simple implementation - send the MAC.
+************************************************************/
+
+static void cli_simple_sign_outgoing_message(struct cli_state *cli)
+{
+ unsigned char calc_md5_mac[16];
+ struct smb_basic_signing_context *data = cli->sign_info.signing_context;
+
+ /* mark the packet as signed - BEFORE we sign it...*/
+ cli_mark_packet_signed(cli);
+
+ simple_packet_signature(data, cli->outbuf, data->send_seq_num,
+ calc_md5_mac);
DEBUG(10, ("sent SMB signature of\n"));
dump_data(10, calc_md5_mac, 8);
@@ -132,9 +205,12 @@ static void cli_simple_sign_outgoing_message(struct cli_state *cli)
memcpy(&cli->outbuf[smb_ss_field], calc_md5_mac, 8);
/* cli->outbuf[smb_ss_field+2]=0;
- Uncomment this to test if the remote server actually verifies signitures...*/
+ Uncomment this to test if the remote server actually verifies signatures...*/
+
data->send_seq_num++;
- data->reply_seq_num = data->send_seq_num;
+ store_sequence_for_reply(&data->outstanding_packet_list,
+ cli->mid,
+ data->send_seq_num);
data->send_seq_num++;
}
@@ -145,35 +221,21 @@ static void cli_simple_sign_outgoing_message(struct cli_state *cli)
static BOOL cli_simple_check_incoming_message(struct cli_state *cli)
{
BOOL good;
+ uint32 reply_seq_number;
unsigned char calc_md5_mac[16];
- unsigned char server_sent_mac[8];
- unsigned char sequence_buf[8];
- struct MD5Context md5_ctx;
+ unsigned char *server_sent_mac;
+
struct smb_basic_signing_context *data = cli->sign_info.signing_context;
- const size_t offset_end_of_sig = (smb_ss_field + 8);
- /*
- * Firstly put the sequence number into the first 4 bytes.
- * and zero out the next 4 bytes.
- */
+ if (!get_sequence_for_reply(&data->outstanding_packet_list,
+ SVAL(cli->inbuf, smb_mid),
+ &reply_seq_number)) {
+ return False;
+ }
- SIVAL(sequence_buf, 0, data->reply_seq_num);
- SIVAL(sequence_buf, 4, 0);
-
- /* get a copy of the server-sent mac */
- memcpy(server_sent_mac, &cli->inbuf[smb_ss_field], sizeof(server_sent_mac));
-
- /* Calculate the 16 byte MAC and place first 8 bytes into the field. */
- MD5Init(&md5_ctx);
- MD5Update(&md5_ctx, data->mac_key.data,
- data->mac_key.length);
- MD5Update(&md5_ctx, cli->inbuf + 4, smb_ss_field - 4);
- MD5Update(&md5_ctx, sequence_buf, sizeof(sequence_buf));
-
- MD5Update(&md5_ctx, cli->inbuf + offset_end_of_sig,
- smb_len(cli->inbuf) - (offset_end_of_sig - 4));
- MD5Final(calc_md5_mac, &md5_ctx);
+ simple_packet_signature(data, cli->inbuf, reply_seq_number, calc_md5_mac);
+ server_sent_mac = &cli->inbuf[smb_ss_field];
good = (memcmp(server_sent_mac, calc_md5_mac, 8) == 0);
if (!good) {
@@ -183,7 +245,7 @@ static BOOL cli_simple_check_incoming_message(struct cli_state *cli)
DEBUG(5, ("BAD SIG: got SMB signature of\n"));
dump_data(5, server_sent_mac, 8);
}
- return signing_good(cli, good);
+ return cli_signing_good(cli, good);
}
/***********************************************************
@@ -193,6 +255,13 @@ static BOOL cli_simple_check_incoming_message(struct cli_state *cli)
static void cli_simple_free_signing_context(struct cli_state *cli)
{
struct smb_basic_signing_context *data = cli->sign_info.signing_context;
+ struct outstanding_packet_lookup *list = data->outstanding_packet_list;
+
+ while (list) {
+ struct outstanding_packet_lookup *old_head = list;
+ DLIST_REMOVE(list, list);
+ SAFE_FREE(old_head);
+ }
data_blob_free(&data->mac_key);
SAFE_FREE(cli->sign_info.signing_context);
@@ -208,25 +277,32 @@ BOOL cli_simple_set_signing(struct cli_state *cli, const uchar user_session_key[
{
struct smb_basic_signing_context *data;
- if (!set_smb_signing_common(cli)) {
+ if (!user_session_key)
+ return False;
+
+ if (!cli_set_smb_signing_common(cli)) {
return False;
}
- if (!set_smb_signing_real_common(cli)) {
+ if (!cli_set_smb_signing_real_common(cli)) {
return False;
}
data = smb_xmalloc(sizeof(*data));
+
cli->sign_info.signing_context = data;
- data->mac_key = data_blob(NULL, MIN(response.length + 16, 40));
+ data->mac_key = data_blob(NULL, response.length + 16);
memcpy(&data->mac_key.data[0], user_session_key, 16);
- memcpy(&data->mac_key.data[16],response.data, MIN(response.length, 40 - 16));
+ memcpy(&data->mac_key.data[16],response.data, response.length);
/* Initialise the sequence number */
data->send_seq_num = 0;
+ /* Initialise the list of outstanding packets */
+ data->outstanding_packet_list = NULL;
+
cli->sign_info.sign_outgoing_message = cli_simple_sign_outgoing_message;
cli->sign_info.check_incoming_message = cli_simple_check_incoming_message;
cli->sign_info.free_signing_context = cli_simple_free_signing_context;
@@ -235,97 +311,6 @@ BOOL cli_simple_set_signing(struct cli_state *cli, const uchar user_session_key[
}
/***********************************************************
- SMB signing - NTLMSSP implementation - calculate a MAC to send.
-************************************************************/
-
-static void cli_ntlmssp_sign_outgoing_message(struct cli_state *cli)
-{
- NTSTATUS nt_status;
- DATA_BLOB sig;
- NTLMSSP_CLIENT_STATE *ntlmssp_state = cli->sign_info.signing_context;
-
- /* mark the packet as signed - BEFORE we sign it...*/
- mark_packet_signed(cli);
-
- nt_status = ntlmssp_client_sign_packet(ntlmssp_state, cli->outbuf + 4,
- smb_len(cli->outbuf), &sig);
-
- if (!NT_STATUS_IS_OK(nt_status)) {
- DEBUG(0, ("NTLMSSP signing failed with %s\n", nt_errstr(nt_status)));
- return;
- }
-
- DEBUG(10, ("sent SMB signature of\n"));
- dump_data(10, sig.data, MIN(sig.length, 8));
- memcpy(&cli->outbuf[smb_ss_field], sig.data, MIN(sig.length, 8));
-
- data_blob_free(&sig);
-}
-
-/***********************************************************
- SMB signing - NTLMSSP implementation - check a MAC sent by server.
-************************************************************/
-
-static BOOL cli_ntlmssp_check_incoming_message(struct cli_state *cli)
-{
- BOOL good;
- NTSTATUS nt_status;
- DATA_BLOB sig = data_blob(&cli->inbuf[smb_ss_field], 8);
-
- NTLMSSP_CLIENT_STATE *ntlmssp_state = cli->sign_info.signing_context;
-
- nt_status = ntlmssp_client_check_packet(ntlmssp_state, cli->outbuf + 4,
- smb_len(cli->outbuf), &sig);
-
- data_blob_free(&sig);
-
- good = NT_STATUS_IS_OK(nt_status);
- if (!NT_STATUS_IS_OK(nt_status)) {
- DEBUG(5, ("NTLMSSP signing failed with %s\n", nt_errstr(nt_status)));
- }
-
- return signing_good(cli, good);
-}
-
-/***********************************************************
- SMB signing - NTLMSSP implementation - free signing context
-************************************************************/
-
-static void cli_ntlmssp_free_signing_context(struct cli_state *cli)
-{
- ntlmssp_client_end((NTLMSSP_CLIENT_STATE **)&cli->sign_info.signing_context);
-}
-
-/***********************************************************
- SMB signing - NTLMSSP implementation - setup the MAC key.
-************************************************************/
-
-BOOL cli_ntlmssp_set_signing(struct cli_state *cli,
- NTLMSSP_CLIENT_STATE *ntlmssp_state)
-{
- if (!set_smb_signing_common(cli)) {
- return False;
- }
-
- if (!NT_STATUS_IS_OK(ntlmssp_client_sign_init(ntlmssp_state))) {
- return False;
- }
-
- if (!set_smb_signing_real_common(cli)) {
- return False;
- }
-
- cli->sign_info.signing_context = ntlmssp_state;
- ntlmssp_state->ref_count++;
-
- cli->sign_info.sign_outgoing_message = cli_ntlmssp_sign_outgoing_message;
- cli->sign_info.check_incoming_message = cli_ntlmssp_check_incoming_message;
- cli->sign_info.free_signing_context = cli_ntlmssp_free_signing_context;
-
- return True;
-}
-
-/***********************************************************
SMB signing - NULL implementation - calculate a MAC to send.
************************************************************/
@@ -380,7 +365,7 @@ BOOL cli_null_set_signing(struct cli_state *cli)
static void cli_temp_sign_outgoing_message(struct cli_state *cli)
{
/* mark the packet as signed - BEFORE we sign it...*/
- mark_packet_signed(cli);
+ cli_mark_packet_signed(cli);
/* I wonder what BSRSPYL stands for - but this is what MS
actually sends! */
@@ -412,7 +397,7 @@ static void cli_temp_free_signing_context(struct cli_state *cli)
BOOL cli_temp_set_signing(struct cli_state *cli)
{
- if (!set_smb_signing_common(cli)) {
+ if (!cli_set_smb_signing_common(cli)) {
return False;
}
@@ -473,4 +458,3 @@ BOOL cli_check_sign_mac(struct cli_state *cli)
return True;
}
-
diff --git a/source3/libsmb/smbencrypt.c b/source3/libsmb/smbencrypt.c
index 28160d9609..7a1a2d7d18 100644
--- a/source3/libsmb/smbencrypt.c
+++ b/source3/libsmb/smbencrypt.c
@@ -76,10 +76,9 @@ void E_deshash(const char *passwd, uchar p16[16])
{
fstring dospwd;
ZERO_STRUCT(dospwd);
- ZERO_STRUCTP(p16);
/* Password must be converted to DOS charset - null terminated, uppercase. */
- push_ascii(dospwd, (const char *)passwd, sizeof(dospwd), STR_UPPER|STR_TERMINATE);
+ push_ascii(dospwd, passwd, sizeof(dospwd), STR_UPPER|STR_TERMINATE);
/* Only the fisrt 14 chars are considered, password need not be null terminated. */
E_P16(dospwd, p16);
@@ -250,21 +249,21 @@ BOOL make_oem_passwd_hash(char data[516], const char *passwd, uchar old_pw_hash[
/* Does the md5 encryption from the NT hash for NTLMv2. */
void SMBOWFencrypt_ntv2(const uchar kr[16],
- const DATA_BLOB srv_chal,
- const DATA_BLOB cli_chal,
+ const DATA_BLOB *srv_chal,
+ const DATA_BLOB *cli_chal,
uchar resp_buf[16])
{
HMACMD5Context ctx;
hmac_md5_init_limK_to_64(kr, 16, &ctx);
- hmac_md5_update(srv_chal.data, srv_chal.length, &ctx);
- hmac_md5_update(cli_chal.data, cli_chal.length, &ctx);
+ hmac_md5_update(srv_chal->data, srv_chal->length, &ctx);
+ hmac_md5_update(cli_chal->data, cli_chal->length, &ctx);
hmac_md5_final(resp_buf, &ctx);
#ifdef DEBUG_PASSWORD
DEBUG(100, ("SMBOWFencrypt_ntv2: srv_chal, cli_chal, resp_buf\n"));
- dump_data(100, srv_chal.data, srv_chal.length);
- dump_data(100, cli_chal.data, cli_chal.length);
+ dump_data(100, srv_chal->data, srv_chal->length);
+ dump_data(100, cli_chal->data, cli_chal->length);
dump_data(100, resp_buf, 16);
#endif
}
@@ -272,6 +271,8 @@ void SMBOWFencrypt_ntv2(const uchar kr[16],
void SMBsesskeygen_ntv2(const uchar kr[16],
const uchar * nt_resp, uint8 sess_key[16])
{
+ /* a very nice, 128 bit, variable session key */
+
HMACMD5Context ctx;
hmac_md5_init_limK_to_64(kr, 16, &ctx);
@@ -287,6 +288,9 @@ void SMBsesskeygen_ntv2(const uchar kr[16],
void SMBsesskeygen_ntv1(const uchar kr[16],
const uchar * nt_resp, uint8 sess_key[16])
{
+ /* yes, this session key does not change - yes, this
+ is a problem - but it is 128 bits */
+
mdfour((unsigned char *)sess_key, kr, 16);
#ifdef DEBUG_PASSWORD
@@ -295,36 +299,125 @@ void SMBsesskeygen_ntv1(const uchar kr[16],
#endif
}
-static DATA_BLOB NTLMv2_generate_response(uchar ntlm_v2_hash[16],
- DATA_BLOB server_chal, size_t client_chal_length)
+void SMBsesskeygen_lmv1(const uchar lm_hash[16],
+ const uchar lm_resp[24], /* only uses 8 */
+ uint8 sess_key[16])
+{
+ /* Calculate the LM session key (effective length 40 bits,
+ but changes with each session) */
+
+ uchar p24[24];
+ uchar partial_lm_hash[16];
+
+ memcpy(partial_lm_hash, lm_hash, 8);
+ memset(partial_lm_hash + 8, 0xbd, 8);
+
+ SMBOWFencrypt(lm_hash, lm_resp, p24);
+
+ memcpy(sess_key, p24, 16);
+ sess_key[5] = 0xe5;
+ sess_key[6] = 0x38;
+ sess_key[7] = 0xb0;
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("SMBsesskeygen_lmv1:\n"));
+ dump_data(100, sess_key, 16);
+#endif
+}
+
+DATA_BLOB NTLMv2_generate_names_blob(const char *hostname,
+ const char *domain)
+{
+ DATA_BLOB names_blob = data_blob(NULL, 0);
+
+ msrpc_gen(&names_blob, "aaa",
+ True, NTLMSSP_NAME_TYPE_DOMAIN, domain,
+ True, NTLMSSP_NAME_TYPE_SERVER, hostname,
+ True, 0, "");
+ return names_blob;
+}
+
+static DATA_BLOB NTLMv2_generate_client_data(const DATA_BLOB *names_blob)
+{
+ uchar client_chal[8];
+ DATA_BLOB response = data_blob(NULL, 0);
+ char long_date[8];
+
+ generate_random_buffer(client_chal, sizeof(client_chal), False);
+
+ put_long_date(long_date, time(NULL));
+
+ /* See http://www.ubiqx.org/cifs/SMB.html#SMB.8.5 */
+
+ msrpc_gen(&response, "ddbbdb",
+ 0x00000101, /* Header */
+ 0, /* 'Reserved' */
+ long_date, 8, /* Timestamp */
+ client_chal, 8, /* client challenge */
+ 0, /* Unknown */
+ names_blob->data, names_blob->length); /* End of name list */
+
+ return response;
+}
+
+static DATA_BLOB NTLMv2_generate_response(const uchar ntlm_v2_hash[16],
+ const DATA_BLOB *server_chal,
+ const DATA_BLOB *names_blob)
{
uchar ntlmv2_response[16];
DATA_BLOB ntlmv2_client_data;
DATA_BLOB final_response;
/* NTLMv2 */
+ /* generate some data to pass into the response function - including
+ the hostname and domain name of the server */
+ ntlmv2_client_data = NTLMv2_generate_client_data(names_blob);
- /* We also get to specify some random data */
- ntlmv2_client_data = data_blob(NULL, client_chal_length);
- generate_random_buffer(ntlmv2_client_data.data, ntlmv2_client_data.length, False);
-
/* Given that data, and the challenge from the server, generate a response */
- SMBOWFencrypt_ntv2(ntlm_v2_hash, server_chal, ntlmv2_client_data, ntlmv2_response);
+ SMBOWFencrypt_ntv2(ntlm_v2_hash, server_chal, &ntlmv2_client_data, ntlmv2_response);
- /* put it into nt_response, for the code below to put into the packet */
- final_response = data_blob(NULL, ntlmv2_client_data.length + sizeof(ntlmv2_response));
+ final_response = data_blob(NULL, sizeof(ntlmv2_response) + ntlmv2_client_data.length);
+
memcpy(final_response.data, ntlmv2_response, sizeof(ntlmv2_response));
- /* after the first 16 bytes is the random data we generated above, so the server can verify us with it */
- memcpy(final_response.data + sizeof(ntlmv2_response), ntlmv2_client_data.data, ntlmv2_client_data.length);
+
+ memcpy(final_response.data+sizeof(ntlmv2_response),
+ ntlmv2_client_data.data, ntlmv2_client_data.length);
+
data_blob_free(&ntlmv2_client_data);
return final_response;
}
+static DATA_BLOB LMv2_generate_response(const uchar ntlm_v2_hash[16],
+ const DATA_BLOB *server_chal)
+{
+ uchar lmv2_response[16];
+ DATA_BLOB lmv2_client_data = data_blob(NULL, 8);
+ DATA_BLOB final_response = data_blob(NULL, 24);
+
+ /* LMv2 */
+ /* client-supplied random data */
+ generate_random_buffer(lmv2_client_data.data, lmv2_client_data.length, False);
+
+ /* Given that data, and the challenge from the server, generate a response */
+ SMBOWFencrypt_ntv2(ntlm_v2_hash, server_chal, &lmv2_client_data, lmv2_response);
+ memcpy(final_response.data, lmv2_response, sizeof(lmv2_response));
+
+ /* after the first 16 bytes is the random data we generated above,
+ so the server can verify us with it */
+ memcpy(final_response.data+sizeof(lmv2_response),
+ lmv2_client_data.data, lmv2_client_data.length);
+
+ data_blob_free(&lmv2_client_data);
+
+ return final_response;
+}
+
BOOL SMBNTLMv2encrypt(const char *user, const char *domain, const char *password,
- const DATA_BLOB server_chal,
+ const DATA_BLOB *server_chal,
+ const DATA_BLOB *names_blob,
DATA_BLOB *lm_response, DATA_BLOB *nt_response,
- DATA_BLOB *session_key)
+ DATA_BLOB *nt_session_key)
{
uchar nt_hash[16];
uchar ntlm_v2_hash[16];
@@ -338,18 +431,24 @@ BOOL SMBNTLMv2encrypt(const char *user, const char *domain, const char *password
return False;
}
- *nt_response = NTLMv2_generate_response(ntlm_v2_hash, server_chal, 64 /* pick a number, > 8 */);
+ if (nt_response) {
+ *nt_response = NTLMv2_generate_response(ntlm_v2_hash, server_chal,
+ names_blob);
+ if (nt_session_key) {
+ *nt_session_key = data_blob(NULL, 16);
+
+ /* The NTLMv2 calculations also provide a session key, for signing etc later */
+ /* use only the first 16 bytes of nt_response for session key */
+ SMBsesskeygen_ntv2(ntlm_v2_hash, nt_response->data, nt_session_key->data);
+ }
+ }
/* LMv2 */
- *lm_response = NTLMv2_generate_response(ntlm_v2_hash, server_chal, 8);
-
- *session_key = data_blob(NULL, 16);
+ if (lm_response) {
+ *lm_response = LMv2_generate_response(ntlm_v2_hash, server_chal);
+ }
- /* The NTLMv2 calculations also provide a session key, for signing etc later */
- /* use only the first 16 bytes of nt_response for session key */
- SMBsesskeygen_ntv2(ntlm_v2_hash, nt_response->data, session_key->data);
-
return True;
}
diff --git a/source3/libsmb/trustdom_cache.c b/source3/libsmb/trustdom_cache.c
index cddbb2daa6..8378125088 100644
--- a/source3/libsmb/trustdom_cache.c
+++ b/source3/libsmb/trustdom_cache.c
@@ -26,6 +26,7 @@
#define DBGC_CLASS DBGC_ALL /* there's no proper class yet */
#define TDOMKEY_FMT "TDOM/%s"
+#define TDOMTSKEY "TDOMCACHE/TIMESTAMP"
/**
@@ -89,7 +90,7 @@ BOOL trustdom_cache_shutdown(void)
static char* trustdom_cache_key(const char* name)
{
- char* keystr;
+ char* keystr = NULL;
asprintf(&keystr, TDOMKEY_FMT, strupper_static(name));
return keystr;
@@ -165,11 +166,14 @@ BOOL trustdom_cache_fetch(const char* name, DOM_SID* sid)
/* prepare a key and get the value */
key = trustdom_cache_key(name);
+ if (!key) return False;
if (!gencache_get(key, &value, &timeout)) {
DEBUG(5, ("no entry for trusted domain %s found.\n", name));
+ SAFE_FREE(key);
return False;
} else {
+ SAFE_FREE(key);
DEBUG(5, ("trusted domain %s found (%s)\n", name, value));
}
@@ -183,6 +187,71 @@ BOOL trustdom_cache_fetch(const char* name, DOM_SID* sid)
}
+/*******************************************************************
+ fetch the timestamp from the last update
+*******************************************************************/
+
+uint32 trustdom_cache_fetch_timestamp( void )
+{
+ char *value;
+ time_t timeout;
+ uint32 timestamp;
+
+ /* init the cache */
+ if (!gencache_init())
+ return False;
+
+ if (!gencache_get(TDOMTSKEY, &value, &timeout)) {
+ DEBUG(5, ("no timestamp for trusted domain cache located.\n"));
+ return 0;
+ }
+
+ timestamp = atoi(value);
+
+ return timestamp;
+}
+
+/*******************************************************************
+ store the timestamp from the last update
+*******************************************************************/
+
+BOOL trustdom_cache_store_timestamp( uint32 t, time_t timeout )
+{
+ fstring value;
+
+ /* init the cache */
+ if (!gencache_init())
+ return False;
+
+ snprintf(value, sizeof(value), "%d", t );
+
+ if (!gencache_set(TDOMTSKEY, value, timeout)) {
+ DEBUG(5, ("failed to set timestamp for trustdom_cache\n"));
+ return False;
+ }
+
+ return True;
+}
+
+
+/*******************************************************************
+ lock the timestamp entry in the trustdom_cache
+*******************************************************************/
+
+BOOL trustdom_cache_lock_timestamp( void )
+{
+ return gencache_lock_entry( TDOMTSKEY ) != -1;
+}
+
+/*******************************************************************
+ unlock the timestamp entry in the trustdom_cache
+*******************************************************************/
+
+void trustdom_cache_unlock_timestamp( void )
+{
+ gencache_unlock_entry( TDOMTSKEY );
+}
+
/**
* Delete single trustdom entry. Look at the
* gencache_iterate definition.
@@ -213,3 +282,61 @@ void trustdom_cache_flush(void)
DEBUG(5, ("Trusted domains cache flushed\n"));
}
+/********************************************************************
+ update the trustdom_cache if needed
+********************************************************************/
+#define TRUSTDOM_UPDATE_INTERVAL 600
+
+void update_trustdom_cache( void )
+{
+ char **domain_names;
+ DOM_SID *dom_sids;
+ uint32 num_domains;
+ uint32 last_check;
+ int time_diff;
+ TALLOC_CTX *mem_ctx = NULL;
+ time_t now = time(NULL);
+ int i;
+
+ /* get the timestamp. We have to initialise it if the last timestamp == 0 */
+
+ if ( (last_check = trustdom_cache_fetch_timestamp()) == 0 )
+ trustdom_cache_store_timestamp(0, now+TRUSTDOM_UPDATE_INTERVAL);
+
+ time_diff = now - last_check;
+
+ if ( (time_diff > 0) && (time_diff < TRUSTDOM_UPDATE_INTERVAL) ) {
+ DEBUG(10,("update_trustdom_cache: not time to update trustdom_cache yet\n"));
+ return;
+ }
+
+ /* lock the timestamp */
+ if ( !trustdom_cache_lock_timestamp() )
+ return;
+
+ if ( !(mem_ctx = talloc_init("update_trustdom_cache")) ) {
+ DEBUG(0,("update_trustdom_cache: talloc_init() failed!\n"));
+ goto done;
+ }
+
+ /* get the domains and store them */
+
+ if ( enumerate_domain_trusts(mem_ctx, lp_workgroup(), &domain_names,
+ &num_domains, &dom_sids) )
+ {
+ for ( i=0; i<num_domains; i++ ) {
+ trustdom_cache_store( domain_names[i], NULL, &dom_sids[i],
+ now+TRUSTDOM_UPDATE_INTERVAL);
+ }
+
+ trustdom_cache_store_timestamp( now, now+TRUSTDOM_UPDATE_INTERVAL );
+ }
+
+done:
+ /* unlock and we're done */
+ trustdom_cache_unlock_timestamp();
+
+ talloc_destroy( mem_ctx );
+
+ return;
+}
diff --git a/source3/libsmb/trusts_util.c b/source3/libsmb/trusts_util.c
index 6244c844f2..77e63709aa 100644
--- a/source3/libsmb/trusts_util.c
+++ b/source3/libsmb/trusts_util.c
@@ -1,4 +1,4 @@
-/*
+/*
* Unix SMB/CIFS implementation.
* Routines to operate on various trust relationships
* Copyright (C) Andrew Bartlett 2001
@@ -123,47 +123,68 @@ NTSTATUS trust_pw_find_change_and_store_it(struct cli_state *cli,
}
+/*********************************************************************
+ Enumerate the list of trusted domains from a DC
+*********************************************************************/
-/**
- * Verify whether or not given domain is trusted.
- *
- * @param domain_name name of the domain to be verified
- * @return true if domain is one of the trusted once or
- * false if otherwise
- **/
-
-BOOL is_trusted_domain(const char* dom_name)
+BOOL enumerate_domain_trusts( TALLOC_CTX *mem_ctx, const char *domain,
+ char ***domain_names, uint32 *num_domains,
+ DOM_SID **sids )
{
- DOM_SID trustdom_sid;
- char *pass = NULL;
- time_t lct;
- BOOL ret;
-
- if (lp_server_role() == ROLE_DOMAIN_BDC || lp_server_role() == ROLE_DOMAIN_PDC) {
- /*
- * Query the secrets db as an ultimate source of information
- * about trusted domain names. This is PDC or BDC case.
- */
- ret = secrets_fetch_trusted_domain_password(dom_name, &pass, &trustdom_sid, &lct);
- SAFE_FREE(pass);
- if (ret)
- return ret;
+ POLICY_HND pol;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ fstring dc_name;
+ struct in_addr dc_ip;
+ uint32 enum_ctx = 0;
+ struct cli_state *cli = NULL;
+ BOOL retry;
+
+ *domain_names = NULL;
+ *num_domains = 0;
+ *sids = NULL;
+
+ /* lookup a DC first */
+
+ if ( !get_dc_name(domain, dc_name, &dc_ip) ) {
+ DEBUG(3,("enumerate_domain_trusts: can't locate a DC for domain %s\n",
+ domain));
+ return False;
}
- /*
- * Query the trustdom_cache updated periodically. The only
- * way for domain member server.
- */
- if (trustdom_cache_enable() &&
- trustdom_cache_fetch(dom_name, &trustdom_sid)) {
- trustdom_cache_shutdown();
- return True;
+ /* setup the anonymous connection */
+
+ result = cli_full_connection( &cli, global_myname(), dc_name, &dc_ip, 0, "IPC$", "IPC",
+ "", "", "", 0, &retry);
+ if ( !NT_STATUS_IS_OK(result) )
+ goto done;
+
+ /* open the LSARPC_PIPE */
+
+ if ( !cli_nt_session_open( cli, PI_LSARPC ) ) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
}
- /*
- * if nothing's been found, then give up here, although
- * the last resort might be to query the PDC.
- */
- return False;
+ /* get a handle */
+
+ result = cli_lsa_open_policy(cli, mem_ctx, True,
+ POLICY_VIEW_LOCAL_INFORMATION, &pol);
+ if ( !NT_STATUS_IS_OK(result) )
+ goto done;
+
+ /* Lookup list of trusted domains */
+
+ result = cli_lsa_enum_trust_dom(cli, mem_ctx, &pol, &enum_ctx,
+ num_domains, domain_names, sids);
+ if ( !NT_STATUS_IS_OK(result) )
+ goto done;
+
+done:
+ /* cleanup */
+
+ cli_nt_session_close( cli );
+ cli_shutdown( cli );
+
+ return NT_STATUS_IS_OK(result);
}