diff options
author | Jeremy Allison <jra@samba.org> | 2005-10-07 01:46:19 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 11:04:54 -0500 |
commit | e127501d4589a5a9c92e2f400fc67bda5a8e6855 (patch) | |
tree | 69886234b25530aaa8a7027e8aeb96cc93d822d3 /source3/passdb/secrets.c | |
parent | 8cbe35f6f8fea2757fb3df49c2b9baa94cf5fe84 (diff) | |
download | samba-e127501d4589a5a9c92e2f400fc67bda5a8e6855.tar.gz samba-e127501d4589a5a9c92e2f400fc67bda5a8e6855.tar.bz2 samba-e127501d4589a5a9c92e2f400fc67bda5a8e6855.zip |
r10792: Fix the "schannel not stored across client disconnects" problem.
Based on the Samba4 solution - stores data in
$samba/private/schannel_store.tdb.
This tdb is not left open but open and closed on demand.
Jeremy.
(This used to be commit a6d8a4b1ff31c5552075455dbd98cb58795958a9)
Diffstat (limited to 'source3/passdb/secrets.c')
-rw-r--r-- | source3/passdb/secrets.c | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/source3/passdb/secrets.c b/source3/passdb/secrets.c index 743bdd1942..35ccb2c725 100644 --- a/source3/passdb/secrets.c +++ b/source3/passdb/secrets.c @@ -942,3 +942,212 @@ void secrets_fetch_ipc_userpass(char **username, char **domain, char **password) } } +/****************************************************************************** + Open or create the schannel session store tdb. +*******************************************************************************/ + +static TDB_CONTEXT *open_schannel_session_store(TALLOC_CTX *mem_ctx) +{ + TDB_DATA vers; + uint32 ver; + TDB_CONTEXT *tdb_sc = NULL; + char *fname = talloc_asprintf(mem_ctx, "%s/schannel_store.tdb", lp_private_dir()); + + if (!fname) { + return NULL; + } + + tdb_sc = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600); + + if (!tdb_sc) { + DEBUG(0,("open_schannel_session_store: Failed to open %s\n", fname)); + talloc_free(fname); + return NULL; + } + + vers = tdb_fetch_bystring(tdb_sc, "SCHANNEL_STORE_VERSION"); + if (vers.dptr == NULL) { + /* First opener, no version. */ + SIVAL(&ver,0,1); + vers.dptr = (char *)&ver; + vers.dsize = 4; + tdb_store_bystring(tdb_sc, "SCHANNEL_STORE_VERSION", vers, TDB_REPLACE); + vers.dptr = NULL; + } else if (vers.dsize == 4) { + ver = IVAL(vers.dptr,0); + if (ver != 1) { + tdb_close(tdb_sc); + tdb_sc = NULL; + DEBUG(0,("open_schannel_session_store: wrong version number %d in %s\n", + (int)ver, fname )); + } + } else { + tdb_close(tdb_sc); + tdb_sc = NULL; + DEBUG(0,("open_schannel_session_store: wrong version number size %d in %s\n", + (int)vers.dsize, fname )); + } + + SAFE_FREE(vers.dptr); + talloc_free(fname); + + return tdb_sc; +} + +/****************************************************************************** + Store the schannel state after an AUTH2 call. + Note we must be root here. +*******************************************************************************/ + +BOOL secrets_store_schannel_session_info(TALLOC_CTX *mem_ctx, const struct dcinfo *pdc) +{ + TDB_CONTEXT *tdb_sc = NULL; + TDB_DATA value; + BOOL ret; + char *keystr = talloc_asprintf(mem_ctx, "%s/%s", SECRETS_SCHANNEL_STATE, + pdc->remote_machine); + if (!keystr) { + return False; + } + + strupper_m(keystr); + + /* Work out how large the record is. */ + value.dsize = tdb_pack(NULL, 0, "dBBBBBfff", + pdc->sequence, + 8, pdc->seed_chal.data, + 8, pdc->clnt_chal.data, + 8, pdc->srv_chal.data, + 8, pdc->sess_key, + 16, pdc->mach_pw, + pdc->mach_acct, + pdc->remote_machine, + pdc->domain); + + value.dptr = TALLOC(mem_ctx, value.dsize); + if (!value.dptr) { + talloc_free(keystr); + return False; + } + + value.dsize = tdb_pack(value.dptr, value.dsize, "dBBBBBfff", + pdc->sequence, + 8, pdc->seed_chal.data, + 8, pdc->clnt_chal.data, + 8, pdc->srv_chal.data, + 8, pdc->sess_key, + 16, pdc->mach_pw, + pdc->mach_acct, + pdc->remote_machine, + pdc->domain); + + tdb_sc = open_schannel_session_store(mem_ctx); + if (!tdb_sc) { + talloc_free(keystr); + talloc_free(value.dptr); + return False; + } + + ret = (tdb_store_bystring(tdb_sc, keystr, value, TDB_REPLACE) == 0 ? True : False); + + DEBUG(3,("secrets_store_schannel_session_info: stored schannel info with key %s\n", + keystr )); + + tdb_close(tdb_sc); + talloc_free(keystr); + talloc_free(value.dptr); + return ret; +} + +/****************************************************************************** + Restore the schannel state on a client reconnect. + Note we must be root here. +*******************************************************************************/ + +BOOL secrets_restore_schannel_session_info(TALLOC_CTX *mem_ctx, + const char *remote_machine, + struct dcinfo *pdc) +{ + TDB_CONTEXT *tdb_sc = NULL; + TDB_DATA value; + unsigned char *pseed_chal = NULL; + unsigned char *pclnt_chal = NULL; + unsigned char *psrv_chal = NULL; + unsigned char *psess_key = NULL; + unsigned char *pmach_pw = NULL; + uint32 l1, l2, l3, l4, l5; + int ret; + char *keystr = talloc_asprintf(mem_ctx, "%s/%s", SECRETS_SCHANNEL_STATE, + remote_machine); + + ZERO_STRUCTP(pdc); + + if (!keystr) { + return False; + } + + strupper_m(keystr); + + tdb_sc = open_schannel_session_store(mem_ctx); + if (!tdb_sc) { + talloc_free(keystr); + return False; + } + + value = tdb_fetch_bystring(tdb_sc, keystr); + if (!value.dptr) { + DEBUG(0,("secrets_restore_schannel_session_info: Failed to find entry with key %s\n", + keystr )); + tdb_close(tdb_sc); + return False; + } + + tdb_close(tdb_sc); + + /* Retrieve the record. */ + ret = tdb_unpack(value.dptr, value.dsize, "dBBBBBfff", + &pdc->sequence, + &l1, &pseed_chal, + &l2, &pclnt_chal, + &l3, &psrv_chal, + &l4, &psess_key, + &l5, &pmach_pw, + &pdc->mach_acct, + &pdc->remote_machine, + &pdc->domain); + + if (ret == -1 || l1 != 8 || l2 != 8 || l3 != 8 || l4 != 8 || l5 != 16) { + talloc_free(keystr); + SAFE_FREE(pseed_chal); + SAFE_FREE(pclnt_chal); + SAFE_FREE(psrv_chal); + SAFE_FREE(psess_key); + SAFE_FREE(pmach_pw); + SAFE_FREE(value.dptr); + ZERO_STRUCTP(pdc); + return False; + } + + memcpy(pdc->seed_chal.data, pseed_chal, 8); + memcpy(pdc->clnt_chal.data, pclnt_chal, 8); + memcpy(pdc->srv_chal.data, psrv_chal, 8); + memcpy(pdc->sess_key, psess_key, 8); + memcpy(pdc->mach_pw, pmach_pw, 16); + + /* We know these are true so didn't bother to store them. */ + pdc->challenge_sent = True; + pdc->authenticated = True; + + DEBUG(3,("secrets_store_schannel_session_info: restored schannel info key %s\n", + keystr )); + + SAFE_FREE(pseed_chal); + SAFE_FREE(pclnt_chal); + SAFE_FREE(psrv_chal); + SAFE_FREE(psess_key); + SAFE_FREE(pmach_pw); + + talloc_free(keystr); + SAFE_FREE(value.dptr); + return True; +} |