2 Unix SMB/CIFS implementation.
3 Net_sam_logon info3 helpers
4 Copyright (C) Alexander Bokovoy 2002.
5 Copyright (C) Andrew Bartlett 2002.
6 Copyright (C) Gerald Carter 2003.
7 Copyright (C) Tim Potter 2003.
8 Copyright (C) Guenther Deschner 2008.
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.
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.
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/>.
25 #include "samlogon_cache.h"
26 #include "system/filesys.h"
27 #include "system/time.h"
28 #include "lib/util/debug.h"
29 #include "lib/util/talloc_stack.h"
30 #include "source3/lib/util_path.h"
31 #include "librpc/gen_ndr/ndr_krb5pac.h"
32 #include "../libcli/security/security.h"
35 #define NETSAMLOGON_TDB "netsamlogon_cache.tdb"
37 static TDB_CONTEXT
*netsamlogon_tdb
= NULL
;
39 /***********************************************************************
41 ***********************************************************************/
43 bool netsamlogon_cache_init(void)
45 bool first_try
= true;
48 struct tdb_context
*tdb
;
50 if (netsamlogon_tdb
) {
54 path
= cache_path(talloc_tos(), NETSAMLOGON_TDB
);
59 tdb
= tdb_open_log(path
, 0, TDB_DEFAULT
|TDB_INCOMPATIBLE_HASH
,
60 O_RDWR
| O_CREAT
, 0600);
62 DEBUG(0,("tdb_open_log('%s') - failed\n", path
));
66 ret
= tdb_check(tdb
, NULL
, NULL
);
69 DEBUG(0,("tdb_check('%s') - failed\n", path
));
73 netsamlogon_tdb
= tdb
;
84 DEBUG(0,("retry after truncate for '%s'\n", path
));
85 ret
= truncate(path
, 0);
87 DBG_ERR("truncate failed: %s\n", strerror(errno
));
95 /***********************************************************************
96 Clear cache getpwnam and getgroups entries from the winbindd cache
97 ***********************************************************************/
99 void netsamlogon_clear_cached_user(const struct dom_sid
*user_sid
)
101 struct dom_sid_buf keystr
;
103 if (!netsamlogon_cache_init()) {
104 DEBUG(0,("netsamlogon_clear_cached_user: cannot open "
110 /* Prepare key as DOMAIN-SID/USER-RID string */
111 dom_sid_str_buf(user_sid
, &keystr
);
113 DBG_DEBUG("SID [%s]\n", keystr
.buf
);
115 tdb_delete_bystring(netsamlogon_tdb
, keystr
.buf
);
118 /***********************************************************************
119 Store a netr_SamInfo3 structure in a tdb for later user
120 username should be in UTF-8 format
121 ***********************************************************************/
123 bool netsamlogon_cache_store(const char *username
, struct netr_SamInfo3
*info3
)
126 TDB_DATA data
= { .dptr
= &dummy
, .dsize
= sizeof(dummy
) };
127 struct dom_sid_buf keystr
;
129 struct dom_sid user_sid
;
130 TALLOC_CTX
*tmp_ctx
= talloc_stackframe();
132 enum ndr_err_code ndr_err
;
133 struct netsamlogoncache_entry r
;
140 if (!netsamlogon_cache_init()) {
141 DEBUG(0,("netsamlogon_cache_store: cannot open %s for write!\n",
147 * First write a record with just the domain sid for
148 * netsamlogon_cache_domain_known. Use TDB_INSERT to avoid
149 * overwriting potentially other data. We're just interested
150 * in the existence of that record.
152 dom_sid_str_buf(info3
->base
.domain_sid
, &keystr
);
154 ret
= tdb_store_bystring(netsamlogon_tdb
, keystr
.buf
, data
, TDB_INSERT
);
156 if ((ret
== -1) && (tdb_error(netsamlogon_tdb
) != TDB_ERR_EXISTS
)) {
157 DBG_WARNING("Could not store domain marker for %s: %s\n",
158 keystr
.buf
, tdb_errorstr(netsamlogon_tdb
));
162 sid_compose(&user_sid
, info3
->base
.domain_sid
, info3
->base
.rid
);
164 /* Prepare key as DOMAIN-SID/USER-RID string */
165 dom_sid_str_buf(&user_sid
, &keystr
);
167 DBG_DEBUG("SID [%s]\n", keystr
.buf
);
171 if (info3
->base
.full_name
.string
== NULL
) {
172 struct netr_SamInfo3
*cached_info3
;
173 const char *full_name
= NULL
;
175 cached_info3
= netsamlogon_cache_get(tmp_ctx
, &user_sid
);
176 if (cached_info3
!= NULL
) {
177 full_name
= cached_info3
->base
.full_name
.string
;
180 if (full_name
!= NULL
) {
181 info3
->base
.full_name
.string
= talloc_strdup(info3
, full_name
);
182 if (info3
->base
.full_name
.string
== NULL
) {
188 /* only Samba fills in the username, not sure why NT doesn't */
189 /* so we fill it in since winbindd_getpwnam() makes use of it */
191 if (!info3
->base
.account_name
.string
) {
192 info3
->base
.account_name
.string
= talloc_strdup(info3
, username
);
193 if (info3
->base
.account_name
.string
== NULL
) {
198 r
.timestamp
= time(NULL
);
201 /* avoid storing secret information */
202 ZERO_STRUCT(r
.info3
.base
.key
);
203 ZERO_STRUCT(r
.info3
.base
.LMSessKey
);
205 if (DEBUGLEVEL
>= 10) {
206 NDR_PRINT_DEBUG(netsamlogoncache_entry
, &r
);
209 ndr_err
= ndr_push_struct_blob(&blob
, tmp_ctx
, &r
,
210 (ndr_push_flags_fn_t
)ndr_push_netsamlogoncache_entry
);
211 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
212 DBG_WARNING("failed to push entry to cache: %s\n",
213 ndr_errstr(ndr_err
));
217 data
.dsize
= blob
.length
;
218 data
.dptr
= blob
.data
;
220 if (tdb_store_bystring(netsamlogon_tdb
, keystr
.buf
, data
, TDB_REPLACE
) == 0) {
225 TALLOC_FREE(tmp_ctx
);
229 /***********************************************************************
230 Retrieves a netr_SamInfo3 structure from a tdb. Caller must
231 free the user_info struct (talloced memory)
232 ***********************************************************************/
234 struct netr_SamInfo3
*netsamlogon_cache_get(TALLOC_CTX
*mem_ctx
, const struct dom_sid
*user_sid
)
236 struct netr_SamInfo3
*info3
= NULL
;
238 struct dom_sid_buf keystr
;
239 enum ndr_err_code ndr_err
;
241 struct netsamlogoncache_entry r
;
243 if (!netsamlogon_cache_init()) {
244 DEBUG(0,("netsamlogon_cache_get: cannot open %s for write!\n",
249 /* Prepare key as DOMAIN-SID/USER-RID string */
250 dom_sid_str_buf(user_sid
, &keystr
);
251 DBG_DEBUG("SID [%s]\n", keystr
.buf
);
252 data
= tdb_fetch_bystring( netsamlogon_tdb
, keystr
.buf
);
258 info3
= talloc_zero(mem_ctx
, struct netr_SamInfo3
);
263 blob
= data_blob_const(data
.dptr
, data
.dsize
);
265 ndr_err
= ndr_pull_struct_blob_all(
267 (ndr_pull_flags_fn_t
)ndr_pull_netsamlogoncache_entry
);
269 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
270 DEBUG(0,("netsamlogon_cache_get: failed to pull entry from cache\n"));
271 tdb_delete_bystring(netsamlogon_tdb
, keystr
.buf
);
276 if (DEBUGLEVEL
>= 10) {
277 NDR_PRINT_DEBUG(netsamlogoncache_entry
, &r
);
280 info3
= (struct netr_SamInfo3
*)talloc_memdup(mem_ctx
, &r
.info3
,
284 SAFE_FREE(data
.dptr
);
289 bool netsamlogon_cache_have(const struct dom_sid
*sid
)
291 struct dom_sid_buf keystr
;
294 if (!netsamlogon_cache_init()) {
295 DBG_WARNING("Cannot open %s\n", NETSAMLOGON_TDB
);
299 dom_sid_str_buf(sid
, &keystr
);
301 ok
= tdb_exists(netsamlogon_tdb
, string_term_tdb_data(keystr
.buf
));
305 struct netsamlog_cache_forall_state
{
307 int (*cb
)(const char *sid_str
,
309 struct netr_SamInfo3
*,
314 static int netsamlog_cache_traverse_cb(struct tdb_context
*tdb
,
319 struct netsamlog_cache_forall_state
*state
=
320 (struct netsamlog_cache_forall_state
*)private_data
;
321 TALLOC_CTX
*mem_ctx
= NULL
;
323 const char *sid_str
= NULL
;
325 struct netsamlogoncache_entry r
;
326 enum ndr_err_code ndr_err
;
330 if (key
.dsize
== 0) {
333 if (key
.dptr
[key
.dsize
- 1] != '\0') {
336 if (data
.dptr
== NULL
) {
339 sid_str
= (char *)key
.dptr
;
341 ok
= string_to_sid(&sid
, sid_str
);
343 DBG_ERR("String to SID failed for %s\n", sid_str
);
347 if (sid
.num_auths
!= 5) {
351 mem_ctx
= talloc_new(state
->mem_ctx
);
352 if (mem_ctx
== NULL
) {
356 blob
= data_blob_const(data
.dptr
, data
.dsize
);
358 ndr_err
= ndr_pull_struct_blob(
359 &blob
, state
->mem_ctx
, &r
,
360 (ndr_pull_flags_fn_t
)ndr_pull_netsamlogoncache_entry
);
362 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
363 DBG_ERR("failed to pull entry from cache\n");
367 ret
= state
->cb(sid_str
, r
.timestamp
, &r
.info3
, state
->private_data
);
369 TALLOC_FREE(mem_ctx
);
373 int netsamlog_cache_for_all(int (*cb
)(const char *sid_str
,
375 struct netr_SamInfo3
*,
380 TALLOC_CTX
*mem_ctx
= NULL
;
381 struct netsamlog_cache_forall_state state
;
383 if (!netsamlogon_cache_init()) {
384 DBG_ERR("Cannot open %s\n", NETSAMLOGON_TDB
);
388 mem_ctx
= talloc_init("netsamlog_cache_for_all");
389 if (mem_ctx
== NULL
) {
393 state
= (struct netsamlog_cache_forall_state
) {
396 .private_data
= private_data
,
399 ret
= tdb_traverse_read(netsamlogon_tdb
,
400 netsamlog_cache_traverse_cb
,
403 TALLOC_FREE(state
.mem_ctx
);