summaryrefslogtreecommitdiffstats
path: root/source/libsmb/credentials.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/libsmb/credentials.c')
-rw-r--r--source/libsmb/credentials.c295
1 files changed, 179 insertions, 116 deletions
diff --git a/source/libsmb/credentials.c b/source/libsmb/credentials.c
index 0d521bae8ac..3f2dcd850b3 100644
--- a/source/libsmb/credentials.c
+++ b/source/libsmb/credentials.c
@@ -2,6 +2,7 @@
Unix SMB/CIFS implementation.
code to manipulate domain credentials
Copyright (C) Andrew Tridgell 1997-1998
+ Largely rewritten by Jeremy Allison 2005.
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
@@ -21,8 +22,9 @@
#include "includes.h"
/****************************************************************************
-represent a credential as a string
+ Represent a credential as a string.
****************************************************************************/
+
char *credstr(const uchar *cred)
{
static fstring buf;
@@ -34,182 +36,243 @@ char *credstr(const uchar *cred)
/****************************************************************************
- setup the session key.
-Input: 8 byte challenge block
+ Setup the session key.
+ Input: 8 byte challenge block
8 byte server challenge block
16 byte md4 encrypted password
-Output:
- 8 byte session key
+ Output:
+ 16 byte session key (last 8 bytes zero).
****************************************************************************/
-void cred_session_key(const DOM_CHAL *clnt_chal, const DOM_CHAL *srv_chal, const uchar *pass,
- uchar session_key[8])
+
+static void cred_create_session_key(const DOM_CHAL *clnt_chal_in,
+ const DOM_CHAL *srv_chal_in,
+ const uchar *pass_in,
+ uchar session_key_out[16])
{
uint32 sum[2];
unsigned char sum2[8];
- sum[0] = IVAL(clnt_chal->data, 0) + IVAL(srv_chal->data, 0);
- sum[1] = IVAL(clnt_chal->data, 4) + IVAL(srv_chal->data, 4);
+ sum[0] = IVAL(clnt_chal_in->data, 0) + IVAL(srv_chal_in->data, 0);
+ sum[1] = IVAL(clnt_chal_in->data, 4) + IVAL(srv_chal_in->data, 4);
SIVAL(sum2,0,sum[0]);
SIVAL(sum2,4,sum[1]);
- cred_hash1(session_key, sum2, pass);
+ cred_hash1(session_key_out, sum2, pass_in);
+ memset(&session_key_out[8], '\0', 8);
/* debug output */
- DEBUG(4,("cred_session_key\n"));
+ DEBUG(4,("cred_create_session_key\n"));
- DEBUG(5,(" clnt_chal: %s\n", credstr(clnt_chal->data)));
- DEBUG(5,(" srv_chal : %s\n", credstr(srv_chal->data)));
+ DEBUG(5,(" clnt_chal_in: %s\n", credstr(clnt_chal_in->data)));
+ DEBUG(5,(" srv_chal_in : %s\n", credstr(srv_chal_in->data)));
DEBUG(5,(" clnt+srv : %s\n", credstr(sum2)));
- DEBUG(5,(" sess_key : %s\n", credstr(session_key)));
+ DEBUG(5,(" sess_key_out : %s\n", credstr(session_key_out)));
}
-
/****************************************************************************
-create a credential
-
-Input:
- 8 byte sesssion key
- 8 byte stored credential
- 4 byte timestamp
-
-Output:
- 8 byte credential
+ Utility function to step credential chain one forward.
+ Deliberately doesn't update the seed. See reseed comment below.
****************************************************************************/
-void cred_create(uchar session_key[8], DOM_CHAL *stor_cred, UTIME timestamp,
- DOM_CHAL *cred)
+
+static void creds_step(struct dcinfo *dc)
{
- DOM_CHAL time_cred;
+ DOM_CHAL time_chal;
- SIVAL(time_cred.data, 0, IVAL(stor_cred->data, 0) + timestamp.time);
- SIVAL(time_cred.data, 4, IVAL(stor_cred->data, 4));
+ DEBUG(5,("\tsequence = 0x%x\n", (unsigned int)dc->sequence ));
- cred_hash2(cred->data, time_cred.data, session_key);
+ DEBUG(5,("\tseed: %s\n", credstr(dc->seed_chal.data) ));
- /* debug output*/
- DEBUG(4,("cred_create\n"));
+ SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence);
+ SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
+
+ DEBUG(5,("\tseed+seq %s\n", credstr(time_chal.data) ));
- DEBUG(5,(" sess_key : %s\n", credstr(session_key)));
- DEBUG(5,(" stor_cred: %s\n", credstr(stor_cred->data)));
- DEBUG(5,(" timestamp: %x\n" , timestamp.time));
- DEBUG(5,(" timecred : %s\n", credstr(time_cred.data)));
- DEBUG(5,(" calc_cred: %s\n", credstr(cred->data)));
-}
+ cred_hash2(dc->clnt_chal.data, time_chal.data, dc->sess_key);
+ DEBUG(5,("\tCLIENT %s\n", credstr(dc->clnt_chal.data) ));
-/****************************************************************************
- check a supplied credential
+ SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence + 1);
+ SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
+
+ DEBUG(5,("\tseed+seq+1 %s\n", credstr(time_chal.data) ));
-Input:
- 8 byte received credential
- 8 byte sesssion key
- 8 byte stored credential
- 4 byte timestamp
+ cred_hash2(dc->srv_chal.data, time_chal.data, dc->sess_key);
+
+ DEBUG(5,("\tSERVER %s\n", credstr(dc->srv_chal.data) ));
+}
-Output:
- returns 1 if computed credential matches received credential
- returns 0 otherwise
+
+/****************************************************************************
+ Create a server credential struct.
****************************************************************************/
-int cred_assert(DOM_CHAL *cred, uchar session_key[8], DOM_CHAL *stored_cred,
- UTIME timestamp)
+
+void creds_server_init(struct dcinfo *dc,
+ DOM_CHAL *clnt_chal,
+ DOM_CHAL *srv_chal,
+ const char mach_pw[16],
+ DOM_CHAL *init_chal_out)
{
- DOM_CHAL cred2;
+ DEBUG(10,("creds_server_init: client chal : %s\n", credstr(clnt_chal->data) ));
+ DEBUG(10,("creds_server_init: server chal : %s\n", credstr(srv_chal->data) ));
+ dump_data_pw("creds_server_init: machine pass", mach_pw, 16);
- cred_create(session_key, stored_cred, timestamp, &cred2);
+ /* Just in case this isn't already there */
+ memcpy(dc->mach_pw, mach_pw, 16);
- /* debug output*/
- DEBUG(4,("cred_assert\n"));
+ /* Generate the session key. */
+ cred_create_session_key(clnt_chal, /* Stored client challenge. */
+ srv_chal, /* Stored server challenge. */
+ dc->mach_pw, /* input machine password. */
+ dc->sess_key); /* output session key. */
- DEBUG(5,(" challenge : %s\n", credstr(cred->data)));
- DEBUG(5,(" calculated: %s\n", credstr(cred2.data)));
+ dump_data_pw("creds_server_init: session key", dc->sess_key, 16);
- if (memcmp(cred->data, cred2.data, 8) == 0)
- {
- DEBUG(5, ("credentials check ok\n"));
- return True;
- }
- else
- {
- DEBUG(5, ("credentials check wrong\n"));
+ /* Generate the next client and server creds. */
+ cred_hash2(dc->clnt_chal.data, /* output */
+ clnt_chal->data, /* input */
+ dc->sess_key); /* input */
+
+ cred_hash2(dc->srv_chal.data, /* output */
+ srv_chal->data, /* input */
+ dc->sess_key); /* input */
+
+ /* Seed is the client chal. */
+ memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
+
+ DEBUG(10,("creds_server_init: clnt : %s\n", credstr(dc->clnt_chal.data) ));
+ DEBUG(10,("creds_server_init: server : %s\n", credstr(dc->srv_chal.data) ));
+ DEBUG(10,("creds_server_init: seed : %s\n", credstr(dc->seed_chal.data) ));
+
+ memcpy(init_chal_out->data, dc->srv_chal.data, 8);
+}
+
+/****************************************************************************
+ Check a credential sent by the client.
+****************************************************************************/
+
+BOOL creds_server_check(const struct dcinfo *dc, const DOM_CHAL *rcv_cli_chal_in)
+{
+ if (memcmp(dc->clnt_chal.data, rcv_cli_chal_in->data, 8)) {
+ DEBUG(5,("creds_server_check: challenge : %s\n", credstr(rcv_cli_chal_in->data)));
+ DEBUG(5,("calculated: %s\n", credstr(dc->clnt_chal.data)));
+ DEBUG(0,("creds_server_check: credentials check failed.\n"));
return False;
}
+ DEBUG(10,("creds_server_check: credentials check OK.\n"));
+ return True;
}
-
/****************************************************************************
- checks credentials; generates next step in the credential chain
+ Replace current seed chal. Internal function - due to split server step below.
****************************************************************************/
-BOOL clnt_deal_with_creds(uchar sess_key[8],
- DOM_CRED *sto_clnt_cred, DOM_CRED *rcv_srv_cred)
+
+static void creds_reseed(struct dcinfo *dc)
{
- UTIME new_clnt_time;
- uint32 new_cred;
+ DOM_CHAL time_chal;
- DEBUG(5,("clnt_deal_with_creds: %d\n", __LINE__));
+ SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence + 1);
+ SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
- /* increment client time by one second */
- new_clnt_time.time = sto_clnt_cred->timestamp.time + 1;
+ dc->seed_chal = time_chal;
- /* check that the received server credentials are valid */
- if (!cred_assert(&rcv_srv_cred->challenge, sess_key,
- &sto_clnt_cred->challenge, new_clnt_time))
- {
- return False;
- }
+ DEBUG(5,("cred_reseed: seed %s\n", credstr(dc->seed_chal.data) ));
+}
- /* first 4 bytes of the new seed is old client 4 bytes + clnt time + 1 */
- new_cred = IVAL(sto_clnt_cred->challenge.data, 0);
- new_cred += new_clnt_time.time;
+/****************************************************************************
+ Step the server credential chain one forward.
+****************************************************************************/
- /* store new seed in client credentials */
- SIVAL(sto_clnt_cred->challenge.data, 0, new_cred);
+BOOL creds_server_step(struct dcinfo *dc, const DOM_CRED *received_cred, DOM_CRED *cred_out)
+{
+ dc->sequence = received_cred->timestamp.time;
- DEBUG(5,(" new clnt cred: %s\n", credstr(sto_clnt_cred->challenge.data)));
- return True;
-}
+ creds_step(dc);
+
+ /* Create the outgoing credentials */
+ cred_out->timestamp.time = dc->sequence + 1;
+ cred_out->challenge = dc->srv_chal;
+ creds_reseed(dc);
+
+ return creds_server_check(dc, &received_cred->challenge);
+}
/****************************************************************************
- checks credentials; generates next step in the credential chain
+ Create a client credential struct.
****************************************************************************/
-BOOL deal_with_creds(uchar sess_key[8],
- DOM_CRED *sto_clnt_cred,
- DOM_CRED *rcv_clnt_cred, DOM_CRED *rtn_srv_cred)
+
+void creds_client_init(struct dcinfo *dc,
+ DOM_CHAL *clnt_chal,
+ DOM_CHAL *srv_chal,
+ const char mach_pw[16],
+ DOM_CHAL *init_chal_out)
{
- UTIME new_clnt_time;
- uint32 new_cred;
+ dc->sequence = time(NULL);
- DEBUG(5,("deal_with_creds: %d\n", __LINE__));
+ DEBUG(10,("creds_client_init: client chal : %s\n", credstr(clnt_chal->data) ));
+ DEBUG(10,("creds_client_init: server chal : %s\n", credstr(srv_chal->data) ));
+ dump_data_pw("creds_client_init: machine pass", mach_pw, 16);
- /* check that the received client credentials are valid */
- if (!cred_assert(&rcv_clnt_cred->challenge, sess_key,
- &sto_clnt_cred->challenge, rcv_clnt_cred->timestamp))
- {
- return False;
- }
+ /* Just in case this isn't already there */
+ memcpy(dc->mach_pw, mach_pw, 16);
- /* increment client time by one second */
- new_clnt_time.time = rcv_clnt_cred->timestamp.time + 1;
+ /* Generate the session key. */
+ cred_create_session_key(clnt_chal, /* Stored client challenge. */
+ srv_chal, /* Stored server challenge. */
+ dc->mach_pw, /* input machine password. */
+ dc->sess_key); /* output session key. */
- /* first 4 bytes of the new seed is old client 4 bytes + clnt time + 1 */
- new_cred = IVAL(sto_clnt_cred->challenge.data, 0);
- new_cred += new_clnt_time.time;
+ dump_data_pw("creds_client_init: session key", dc->sess_key, 16);
- DEBUG(5,("deal_with_creds: new_cred[0]=%x\n", new_cred));
+ /* Generate the next client and server creds. */
+ cred_hash2(dc->clnt_chal.data, /* output */
+ clnt_chal->data, /* input */
+ dc->sess_key); /* input */
- /* doesn't matter that server time is 0 */
- rtn_srv_cred->timestamp.time = 0;
+ cred_hash2(dc->srv_chal.data, /* output */
+ srv_chal->data, /* input */
+ dc->sess_key); /* input */
- DEBUG(5,("deal_with_creds: new_clnt_time=%x\n", new_clnt_time.time));
+ /* Seed is the client cred. */
+ memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
- /* create return credentials for inclusion in the reply */
- cred_create(sess_key, &sto_clnt_cred->challenge, new_clnt_time,
- &rtn_srv_cred->challenge);
-
- DEBUG(5,("deal_with_creds: clnt_cred=%s\n", credstr(sto_clnt_cred->challenge.data)));
+ DEBUG(10,("creds_client_init: clnt : %s\n", credstr(dc->clnt_chal.data) ));
+ DEBUG(10,("creds_client_init: server : %s\n", credstr(dc->srv_chal.data) ));
+ DEBUG(10,("creds_client_init: seed : %s\n", credstr(dc->seed_chal.data) ));
- /* store new seed in client credentials */
- SIVAL(sto_clnt_cred->challenge.data, 0, new_cred);
+ memcpy(init_chal_out->data, dc->clnt_chal.data, 8);
+}
+
+/****************************************************************************
+ Check a credential returned by the server.
+****************************************************************************/
+BOOL creds_client_check(const struct dcinfo *dc, const DOM_CHAL *rcv_srv_chal_in)
+{
+ if (memcmp(dc->srv_chal.data, rcv_srv_chal_in->data, 8)) {
+ DEBUG(5,("creds_client_check: challenge : %s\n", credstr(rcv_srv_chal_in->data)));
+ DEBUG(5,("calculated: %s\n", credstr(dc->srv_chal.data)));
+ DEBUG(0,("creds_client_check: credentials check failed.\n"));
+ return False;
+ }
+ DEBUG(10,("creds_client_check: credentials check OK.\n"));
return True;
}
+
+/****************************************************************************
+ Step the client credentials to the next element in the chain, updating the
+ current client and server credentials and the seed
+ produce the next authenticator in the sequence ready to send to
+ the server
+****************************************************************************/
+
+void creds_client_step(struct dcinfo *dc, DOM_CRED *next_cred_out)
+{
+ dc->sequence += 2;
+ creds_step(dc);
+ creds_reseed(dc);
+
+ next_cred_out->challenge = dc->clnt_chal;
+ next_cred_out->timestamp.time = dc->sequence;
+}