49c89085be2a0340c59d11350a20e92424dd078b
[ira/wip.git] / libcli / auth / schannel_state_tdb.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    module to store/fetch session keys for the schannel server
5
6    Copyright (C) Andrew Tridgell 2004
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006-2009
8    Copyright (C) Guenther Deschner 2009
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "../libcli/auth/libcli_auth.h"
26 #include "../libcli/auth/schannel_state.h"
27 #include "../librpc/gen_ndr/ndr_schannel.h"
28
29 /********************************************************************
30  ********************************************************************/
31
32 NTSTATUS schannel_store_session_key_tdb(struct tdb_context *tdb,
33                                         TALLOC_CTX *mem_ctx,
34                                         struct netlogon_creds_CredentialState *creds)
35 {
36         enum ndr_err_code ndr_err;
37         DATA_BLOB blob;
38         TDB_DATA value;
39         int ret;
40         char *keystr;
41
42         keystr = talloc_asprintf_strupper_m(mem_ctx, "%s/%s",
43                                             SECRETS_SCHANNEL_STATE,
44                                             creds->computer_name);
45         if (!keystr) {
46                 return NT_STATUS_NO_MEMORY;
47         }
48
49         ndr_err = ndr_push_struct_blob(&blob, mem_ctx, NULL, creds,
50                         (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
51         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
52                 talloc_free(keystr);
53                 return ndr_map_error2ntstatus(ndr_err);
54         }
55
56         value.dptr = blob.data;
57         value.dsize = blob.length;
58
59         ret = tdb_store_bystring(tdb, keystr, value, TDB_REPLACE);
60         if (ret != TDB_SUCCESS) {
61                 DEBUG(0,("Unable to add %s to session key db - %s\n",
62                          keystr, tdb_errorstr(tdb)));
63                 talloc_free(keystr);
64                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
65         }
66
67         DEBUG(3,("schannel_store_session_key_tdb: stored schannel info with key %s\n",
68                 keystr));
69
70         if (DEBUGLEVEL >= 10) {
71                 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
72         }
73
74         talloc_free(keystr);
75
76         return NT_STATUS_OK;
77 }
78
79 /********************************************************************
80  ********************************************************************/
81
82 NTSTATUS schannel_fetch_session_key_tdb(struct tdb_context *tdb,
83                                         TALLOC_CTX *mem_ctx,
84                                         const char *computer_name,
85                                         struct netlogon_creds_CredentialState **pcreds)
86 {
87         NTSTATUS status;
88         TDB_DATA value;
89         enum ndr_err_code ndr_err;
90         DATA_BLOB blob;
91         struct netlogon_creds_CredentialState *creds = NULL;
92         char *keystr = NULL;
93
94         *pcreds = NULL;
95
96         keystr = talloc_asprintf_strupper_m(mem_ctx, "%s/%s",
97                                             SECRETS_SCHANNEL_STATE,
98                                             computer_name);
99         if (!keystr) {
100                 status = NT_STATUS_NO_MEMORY;
101                 goto done;
102         }
103
104         value = tdb_fetch_bystring(tdb, keystr);
105         if (!value.dptr) {
106                 DEBUG(0,("schannel_fetch_session_key_tdb: Failed to find entry with key %s\n",
107                         keystr ));
108                 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
109                 goto done;
110         }
111
112         creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
113         if (!creds) {
114                 status = NT_STATUS_NO_MEMORY;
115                 goto done;
116         }
117
118         blob = data_blob_const(value.dptr, value.dsize);
119
120         ndr_err = ndr_pull_struct_blob(&blob, creds, NULL, creds,
121                         (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
122         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
123                 status = ndr_map_error2ntstatus(ndr_err);
124                 goto done;
125         }
126
127         if (DEBUGLEVEL >= 10) {
128                 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
129         }
130
131         DEBUG(3,("schannel_fetch_session_key_tdb: restored schannel info key %s\n",
132                 keystr));
133
134         status = NT_STATUS_OK;
135
136  done:
137
138         talloc_free(keystr);
139
140         if (!NT_STATUS_IS_OK(status)) {
141                 talloc_free(creds);
142                 return status;
143         }
144
145         *pcreds = creds;
146
147         return NT_STATUS_OK;
148 }
149
150 /********************************************************************
151
152   Validate an incoming authenticator against the credentials for the remote
153   machine.
154
155   The credentials are (re)read and from the schannel database, and
156   written back after the caclulations are performed.
157
158   The creds_out parameter (if not NULL) returns the credentials, if
159   the caller needs some of that information.
160
161  ********************************************************************/
162
163 NTSTATUS schannel_creds_server_step_check_tdb(struct tdb_context *tdb,
164                                               TALLOC_CTX *mem_ctx,
165                                               const char *computer_name,
166                                               struct netr_Authenticator *received_authenticator,
167                                               struct netr_Authenticator *return_authenticator,
168                                               struct netlogon_creds_CredentialState **creds_out)
169 {
170         struct netlogon_creds_CredentialState *creds;
171         NTSTATUS status;
172         int ret;
173
174         ret = tdb_transaction_start(tdb);
175         if (ret != 0) {
176                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
177         }
178
179         /* Because this is a shared structure (even across
180          * disconnects) we must update the database every time we
181          * update the structure */
182
183         status = schannel_fetch_session_key_tdb(tdb, mem_ctx, computer_name,
184                                                 &creds);
185
186         if (NT_STATUS_IS_OK(status)) {
187                 status = netlogon_creds_server_step_check(creds,
188                                                           received_authenticator,
189                                                           return_authenticator);
190         }
191
192         if (NT_STATUS_IS_OK(status)) {
193                 status = schannel_store_session_key_tdb(tdb, mem_ctx, creds);
194         }
195
196         if (NT_STATUS_IS_OK(status)) {
197                 tdb_transaction_commit(tdb);
198                 if (creds_out) {
199                         *creds_out = creds;
200                         talloc_steal(mem_ctx, creds);
201                 }
202         } else {
203                 tdb_transaction_cancel(tdb);
204         }
205
206         return status;
207 }