summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/secrets.h2
-rw-r--r--source3/passdb/secrets.c209
-rw-r--r--source3/rpc_server/srv_netlog_nt.c10
-rw-r--r--source3/rpc_server/srv_pipe.c29
4 files changed, 231 insertions, 19 deletions
diff --git a/source3/include/secrets.h b/source3/include/secrets.h
index 4b8d5db66b..f2d1afd96b 100644
--- a/source3/include/secrets.h
+++ b/source3/include/secrets.h
@@ -98,4 +98,6 @@ struct afs_keyfile {
#define SECRETS_AFS_KEYFILE "SECRETS/AFS_KEYFILE"
+#define SECRETS_SCHANNEL_STATE "SECRETS/SCHANNEL"
+
#endif /* _SECRETS_H */
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;
+}
diff --git a/source3/rpc_server/srv_netlog_nt.c b/source3/rpc_server/srv_netlog_nt.c
index 1ad058b519..2dd8b821d8 100644
--- a/source3/rpc_server/srv_netlog_nt.c
+++ b/source3/rpc_server/srv_netlog_nt.c
@@ -26,8 +26,6 @@
#include "includes.h"
-extern struct dcinfo last_dcinfo;
-extern BOOL server_auth2_negotiated;
extern userdom_struct current_user_info;
#undef DBGC_CLASS
@@ -438,10 +436,14 @@ NTSTATUS _net_auth_2(pipes_struct *p, NET_Q_AUTH_2 *q_u, NET_R_AUTH_2 *r_u)
fstrcpy(p->dc->mach_acct, mach_acct);
fstrcpy(p->dc->remote_machine, remote_machine);
+ fstrcpy(p->dc->domain, lp_workgroup() );
- server_auth2_negotiated = True;
p->dc->authenticated = True;
- last_dcinfo = *p->dc;
+
+ /* Store off the state so we can continue after client disconnect. */
+ become_root();
+ secrets_store_schannel_session_info(p->mem_ctx, p->dc);
+ unbecome_root();
return r_u->status;
}
diff --git a/source3/rpc_server/srv_pipe.c b/source3/rpc_server/srv_pipe.c
index ba6d9704e8..1ca5210842 100644
--- a/source3/rpc_server/srv_pipe.c
+++ b/source3/rpc_server/srv_pipe.c
@@ -36,15 +36,6 @@ extern struct current_user current_user;
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_RPC_SRV
-/*************************************************************
- HACK Alert!
- We need to transfer the session key from one rpc bind to the
- next. This is the way the netlogon schannel works.
-**************************************************************/
-
-struct dcinfo last_dcinfo;
-BOOL server_auth2_negotiated = False;
-
static void free_pipe_ntlmssp_auth_data(struct pipe_auth_data *auth)
{
AUTH_NTLMSSP_STATE *a = auth->a_u.auth_ntlmssp_state;
@@ -1218,15 +1209,23 @@ static BOOL pipe_schannel_auth_bind(pipes_struct *p, prs_struct *rpc_in_p,
RPC_HDR_AUTH auth_info;
RPC_AUTH_SCHANNEL_NEG neg;
RPC_AUTH_VERIFIER auth_verifier;
+ BOOL ret;
+ struct dcinfo stored_dcinfo;
uint32 flags;
- if (!server_auth2_negotiated) {
- DEBUG(0, ("pipe_schannel_auth_bind: Attempt to bind using schannel without successful serverauth2\n"));
+ if (!smb_io_rpc_auth_schannel_neg("", &neg, rpc_in_p, 0)) {
+ DEBUG(0,("pipe_schannel_auth_bind: Could not unmarshal SCHANNEL auth neg\n"));
return False;
}
- if (!smb_io_rpc_auth_schannel_neg("", &neg, rpc_in_p, 0)) {
- DEBUG(0,("pipe_schannel_auth_bind: Could not unmarshal SCHANNEL auth neg\n"));
+ ZERO_STRUCT(stored_dcinfo);
+
+ become_root();
+ ret = secrets_restore_schannel_session_info(p->mem_ctx, neg.myname, &stored_dcinfo);
+ unbecome_root();
+
+ if (!ret) {
+ DEBUG(0, ("pipe_schannel_auth_bind: Attempt to bind using schannel without successful serverauth2\n"));
return False;
}
@@ -1236,7 +1235,7 @@ static BOOL pipe_schannel_auth_bind(pipes_struct *p, prs_struct *rpc_in_p,
}
memset(p->auth.a_u.schannel_auth->sess_key, 0, sizeof(p->auth.a_u.schannel_auth->sess_key));
- memcpy(p->auth.a_u.schannel_auth->sess_key, last_dcinfo.sess_key, sizeof(last_dcinfo.sess_key));
+ memcpy(p->auth.a_u.schannel_auth->sess_key, stored_dcinfo.sess_key, sizeof(stored_dcinfo.sess_key));
p->auth.a_u.schannel_auth->seq_num = 0;
@@ -1253,7 +1252,7 @@ static BOOL pipe_schannel_auth_bind(pipes_struct *p, prs_struct *rpc_in_p,
if (!p->dc) {
return False;
}
- *p->dc = last_dcinfo;
+ *p->dc = stored_dcinfo;
init_rpc_hdr_auth(&auth_info, RPC_SCHANNEL_AUTH_TYPE, pauth_info->auth_level, RPC_HDR_AUTH_LEN, 1);
if(!smb_io_rpc_hdr_auth("", &auth_info, pout_auth, 0)) {