diff options
Diffstat (limited to 'source/libsmb/credentials.c')
-rw-r--r-- | source/libsmb/credentials.c | 295 |
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; +} |