2
Unix SMB/CIFS implementation.
4
module to store/fetch session keys for the schannel server
6
Copyright (C) Andrew Tridgell 2004
8
This program is free software; you can redistribute it and/or modify
9
it under the terms of the GNU General Public License as published by
10
the Free Software Foundation; either version 3 of the License, or
11
(at your option) any later version.
13
This program is distributed in the hope that it will be useful,
14
but WITHOUT ANY WARRANTY; without even the implied warranty of
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
GNU General Public License for more details.
18
You should have received a copy of the GNU General Public License
19
along with this program. If not, see <http://www.gnu.org/licenses/>.
23
#include "lib/ldb/include/ldb.h"
24
#include "librpc/gen_ndr/ndr_security.h"
26
#include "../lib/util/util_ldb.h"
27
#include "libcli/auth/libcli_auth.h"
28
#include "auth/auth.h"
29
#include "param/param.h"
30
#include "auth/gensec/schannel_state.h"
32
static struct ldb_val *schannel_dom_sid_ldb_val(TALLOC_CTX *mem_ctx,
33
struct smb_iconv_convenience *smbiconv,
36
enum ndr_err_code ndr_err;
39
v = talloc(mem_ctx, struct ldb_val);
42
ndr_err = ndr_push_struct_blob(v, mem_ctx, smbiconv, sid,
43
(ndr_push_flags_fn_t)ndr_push_dom_sid);
44
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
52
static struct dom_sid *schannel_ldb_val_dom_sid(TALLOC_CTX *mem_ctx,
53
const struct ldb_val *v)
55
enum ndr_err_code ndr_err;
58
sid = talloc(mem_ctx, struct dom_sid);
59
if (!sid) return NULL;
61
ndr_err = ndr_pull_struct_blob(v, sid, NULL, sid,
62
(ndr_pull_flags_fn_t)ndr_pull_dom_sid);
63
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
72
connect to the schannel ldb
74
struct ldb_context *schannel_db_connect(TALLOC_CTX *mem_ctx, struct tevent_context *ev_ctx,
75
struct loadparm_context *lp_ctx)
78
struct ldb_context *ldb;
80
const char *init_ldif =
82
"computerName: CASE_INSENSITIVE\n" \
83
"flatname: CASE_INSENSITIVE\n";
85
path = private_path(mem_ctx, lp_ctx, "schannel.ldb");
90
existed = file_exist(path);
92
ldb = ldb_wrap_connect(mem_ctx, ev_ctx, lp_ctx, path,
93
system_session(mem_ctx, lp_ctx),
94
NULL, LDB_FLG_NOSYNC, NULL);
101
gendb_add_ldif(ldb, init_ldif);
108
remember an established session key for a netr server authentication
109
use a simple ldb structure
111
NTSTATUS schannel_store_session_key_ldb(TALLOC_CTX *mem_ctx,
112
struct ldb_context *ldb,
113
struct creds_CredentialState *creds)
115
struct ldb_message *msg;
116
struct ldb_val val, seed, client_state, server_state;
117
struct smb_iconv_convenience *smbiconv;
118
struct ldb_val *sid_val;
123
f = talloc_asprintf(mem_ctx, "%u", (unsigned int)creds->negotiate_flags);
126
return NT_STATUS_NO_MEMORY;
129
sct = talloc_asprintf(mem_ctx, "%u", (unsigned int)creds->secure_channel_type);
132
return NT_STATUS_NO_MEMORY;
135
msg = ldb_msg_new(ldb);
137
return NT_STATUS_NO_MEMORY;
140
msg->dn = ldb_dn_new_fmt(msg, ldb, "computerName=%s", creds->computer_name);
142
return NT_STATUS_NO_MEMORY;
145
smbiconv = lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm"));
146
sid_val = schannel_dom_sid_ldb_val(msg, smbiconv, creds->sid);
147
if (sid_val == NULL) {
148
return NT_STATUS_NO_MEMORY;
151
val.data = creds->session_key;
152
val.length = sizeof(creds->session_key);
154
seed.data = creds->seed.data;
155
seed.length = sizeof(creds->seed.data);
157
client_state.data = creds->client.data;
158
client_state.length = sizeof(creds->client.data);
159
server_state.data = creds->server.data;
160
server_state.length = sizeof(creds->server.data);
162
ldb_msg_add_string(msg, "objectClass", "schannelState");
163
ldb_msg_add_value(msg, "sessionKey", &val, NULL);
164
ldb_msg_add_value(msg, "seed", &seed, NULL);
165
ldb_msg_add_value(msg, "clientState", &client_state, NULL);
166
ldb_msg_add_value(msg, "serverState", &server_state, NULL);
167
ldb_msg_add_string(msg, "negotiateFlags", f);
168
ldb_msg_add_string(msg, "secureChannelType", sct);
169
ldb_msg_add_string(msg, "accountName", creds->account_name);
170
ldb_msg_add_string(msg, "computerName", creds->computer_name);
171
ldb_msg_add_string(msg, "flatname", creds->domain);
172
ldb_msg_add_value(msg, "objectSid", sid_val, NULL);
174
ldb_delete(ldb, msg->dn);
176
ret = ldb_add(ldb, msg);
179
DEBUG(0,("Unable to add %s to session key db - %s\n",
180
ldb_dn_get_linearized(msg->dn), ldb_errstring(ldb)));
181
return NT_STATUS_INTERNAL_DB_CORRUPTION;
187
NTSTATUS schannel_store_session_key(TALLOC_CTX *mem_ctx,
188
struct tevent_context *ev_ctx,
189
struct loadparm_context *lp_ctx,
190
struct creds_CredentialState *creds)
192
struct ldb_context *ldb;
196
ldb = schannel_db_connect(mem_ctx, ev_ctx, lp_ctx);
198
return NT_STATUS_ACCESS_DENIED;
201
ret = ldb_transaction_start(ldb);
204
return NT_STATUS_INTERNAL_DB_CORRUPTION;
207
nt_status = schannel_store_session_key_ldb(mem_ctx, ldb, creds);
209
if (NT_STATUS_IS_OK(nt_status)) {
210
ret = ldb_transaction_commit(ldb);
212
ret = ldb_transaction_cancel(ldb);
216
DEBUG(0,("Unable to commit adding credentials for %s to schannel key db - %s\n",
217
creds->computer_name, ldb_errstring(ldb)));
219
return NT_STATUS_INTERNAL_DB_CORRUPTION;
227
read back a credentials back for a computer
229
NTSTATUS schannel_fetch_session_key_ldb(TALLOC_CTX *mem_ctx,
230
struct ldb_context *ldb,
231
const char *computer_name,
233
struct creds_CredentialState **creds)
235
struct ldb_result *res;
237
const struct ldb_val *val;
239
*creds = talloc_zero(mem_ctx, struct creds_CredentialState);
241
return NT_STATUS_NO_MEMORY;
244
ret = ldb_search(ldb, mem_ctx, &res,
245
NULL, LDB_SCOPE_SUBTREE, NULL,
246
"(&(computerName=%s)(flatname=%s))", computer_name, domain);
247
if (ret != LDB_SUCCESS) {
248
DEBUG(3,("schannel: Failed to find a record for client %s: %s\n", computer_name, ldb_errstring(ldb)));
249
return NT_STATUS_INVALID_HANDLE;
251
if (res->count != 1) {
252
DEBUG(3,("schannel: Failed to find a record for client: %s (found %d records)\n", computer_name, res->count));
254
return NT_STATUS_INVALID_HANDLE;
257
val = ldb_msg_find_ldb_val(res->msgs[0], "sessionKey");
258
if (val == NULL || val->length != 16) {
259
DEBUG(1,("schannel: record in schannel DB must contain a sessionKey of length 16, when searching for client: %s\n", computer_name));
261
return NT_STATUS_INTERNAL_ERROR;
264
memcpy((*creds)->session_key, val->data, 16);
266
val = ldb_msg_find_ldb_val(res->msgs[0], "seed");
267
if (val == NULL || val->length != 8) {
268
DEBUG(1,("schannel: record in schannel DB must contain a vaid seed of length 8, when searching for client: %s\n", computer_name));
270
return NT_STATUS_INTERNAL_ERROR;
273
memcpy((*creds)->seed.data, val->data, 8);
275
val = ldb_msg_find_ldb_val(res->msgs[0], "clientState");
276
if (val == NULL || val->length != 8) {
277
DEBUG(1,("schannel: record in schannel DB must contain a vaid clientState of length 8, when searching for client: %s\n", computer_name));
279
return NT_STATUS_INTERNAL_ERROR;
281
memcpy((*creds)->client.data, val->data, 8);
283
val = ldb_msg_find_ldb_val(res->msgs[0], "serverState");
284
if (val == NULL || val->length != 8) {
285
DEBUG(1,("schannel: record in schannel DB must contain a vaid serverState of length 8, when searching for client: %s\n", computer_name));
287
return NT_STATUS_INTERNAL_ERROR;
289
memcpy((*creds)->server.data, val->data, 8);
291
(*creds)->negotiate_flags = ldb_msg_find_attr_as_int(res->msgs[0], "negotiateFlags", 0);
293
(*creds)->secure_channel_type = ldb_msg_find_attr_as_int(res->msgs[0], "secureChannelType", 0);
295
(*creds)->account_name = talloc_strdup(*creds, ldb_msg_find_attr_as_string(res->msgs[0], "accountName", NULL));
296
if ((*creds)->account_name == NULL) {
298
return NT_STATUS_NO_MEMORY;
301
(*creds)->computer_name = talloc_strdup(*creds, ldb_msg_find_attr_as_string(res->msgs[0], "computerName", NULL));
302
if ((*creds)->computer_name == NULL) {
304
return NT_STATUS_NO_MEMORY;
307
(*creds)->domain = talloc_strdup(*creds, ldb_msg_find_attr_as_string(res->msgs[0], "flatname", NULL));
308
if ((*creds)->domain == NULL) {
310
return NT_STATUS_NO_MEMORY;
313
val = ldb_msg_find_ldb_val(res->msgs[0], "objectSid");
315
DEBUG(1,("schannel: missing ObjectSid for client: %s\n", computer_name));
317
return NT_STATUS_INTERNAL_ERROR;
319
(*creds)->sid = schannel_ldb_val_dom_sid(*creds, val);
320
if ((*creds)->sid == NULL) {
322
return NT_STATUS_INTERNAL_ERROR;
329
NTSTATUS schannel_fetch_session_key(TALLOC_CTX *mem_ctx,
330
struct tevent_context *ev_ctx,
331
struct loadparm_context *lp_ctx,
332
const char *computer_name,
334
struct creds_CredentialState **creds)
337
struct ldb_context *ldb;
339
ldb = schannel_db_connect(mem_ctx, ev_ctx, lp_ctx);
341
return NT_STATUS_ACCESS_DENIED;
344
nt_status = schannel_fetch_session_key_ldb(mem_ctx, ldb,
345
computer_name, domain,