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 char keystr
[DOM_SID_STR_BUFLEN
];
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_string_buf(user_sid
, keystr
, sizeof(keystr
));
113 DEBUG(10,("netsamlogon_clear_cached_user: SID [%s]\n", keystr
));
115 tdb_delete_bystring(netsamlogon_tdb
, keystr
);
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 char keystr
[DOM_SID_STR_BUFLEN
];
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_string_buf(info3
->base
.domain_sid
, keystr
, sizeof(keystr
));
154 ret
= tdb_store_bystring(netsamlogon_tdb
, keystr
, 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
, tdb_errorstr(netsamlogon_tdb
));
159 TALLOC_FREE(tmp_ctx
);
163 sid_compose(&user_sid
, info3
->base
.domain_sid
, info3
->base
.rid
);
165 /* Prepare key as DOMAIN-SID/USER-RID string */
166 dom_sid_string_buf(&user_sid
, keystr
, sizeof(keystr
));
168 DEBUG(10,("netsamlogon_cache_store: SID [%s]\n", keystr
));
172 if (info3
->base
.full_name
.string
== NULL
) {
173 struct netr_SamInfo3
*cached_info3
;
174 const char *full_name
= NULL
;
176 cached_info3
= netsamlogon_cache_get(tmp_ctx
, &user_sid
);
177 if (cached_info3
!= NULL
) {
178 full_name
= cached_info3
->base
.full_name
.string
;
181 if (full_name
!= NULL
) {
182 info3
->base
.full_name
.string
= talloc_strdup(info3
, full_name
);
186 /* only Samba fills in the username, not sure why NT doesn't */
187 /* so we fill it in since winbindd_getpwnam() makes use of it */
189 if (!info3
->base
.account_name
.string
) {
190 info3
->base
.account_name
.string
= talloc_strdup(info3
, username
);
193 r
.timestamp
= time(NULL
);
196 /* avoid storing secret information */
197 ZERO_STRUCT(r
.info3
.base
.key
);
198 ZERO_STRUCT(r
.info3
.base
.LMSessKey
);
200 if (DEBUGLEVEL
>= 10) {
201 NDR_PRINT_DEBUG(netsamlogoncache_entry
, &r
);
204 ndr_err
= ndr_push_struct_blob(&blob
, tmp_ctx
, &r
,
205 (ndr_push_flags_fn_t
)ndr_push_netsamlogoncache_entry
);
206 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
207 DEBUG(0,("netsamlogon_cache_store: failed to push entry to cache\n"));
208 TALLOC_FREE(tmp_ctx
);
212 data
.dsize
= blob
.length
;
213 data
.dptr
= blob
.data
;
215 if (tdb_store_bystring(netsamlogon_tdb
, keystr
, data
, TDB_REPLACE
) == 0) {
219 TALLOC_FREE(tmp_ctx
);
224 /***********************************************************************
225 Retrieves a netr_SamInfo3 structure from a tdb. Caller must
226 free the user_info struct (talloced memory)
227 ***********************************************************************/
229 struct netr_SamInfo3
*netsamlogon_cache_get(TALLOC_CTX
*mem_ctx
, const struct dom_sid
*user_sid
)
231 struct netr_SamInfo3
*info3
= NULL
;
233 char keystr
[DOM_SID_STR_BUFLEN
];
234 enum ndr_err_code ndr_err
;
236 struct netsamlogoncache_entry r
;
238 if (!netsamlogon_cache_init()) {
239 DEBUG(0,("netsamlogon_cache_get: cannot open %s for write!\n",
244 /* Prepare key as DOMAIN-SID/USER-RID string */
245 dom_sid_string_buf(user_sid
, keystr
, sizeof(keystr
));
246 DEBUG(10,("netsamlogon_cache_get: SID [%s]\n", keystr
));
247 data
= tdb_fetch_bystring( netsamlogon_tdb
, keystr
);
253 info3
= talloc_zero(mem_ctx
, struct netr_SamInfo3
);
258 blob
= data_blob_const(data
.dptr
, data
.dsize
);
260 ndr_err
= ndr_pull_struct_blob_all(
262 (ndr_pull_flags_fn_t
)ndr_pull_netsamlogoncache_entry
);
264 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
265 DEBUG(0,("netsamlogon_cache_get: failed to pull entry from cache\n"));
266 tdb_delete_bystring(netsamlogon_tdb
, keystr
);
271 if (DEBUGLEVEL
>= 10) {
272 NDR_PRINT_DEBUG(netsamlogoncache_entry
, &r
);
275 info3
= (struct netr_SamInfo3
*)talloc_memdup(mem_ctx
, &r
.info3
,
279 SAFE_FREE(data
.dptr
);
284 bool netsamlogon_cache_have(const struct dom_sid
*sid
)
286 char keystr
[DOM_SID_STR_BUFLEN
];
289 if (!netsamlogon_cache_init()) {
290 DBG_WARNING("Cannot open %s\n", NETSAMLOGON_TDB
);
294 dom_sid_string_buf(sid
, keystr
, sizeof(keystr
));
296 ok
= tdb_exists(netsamlogon_tdb
, string_term_tdb_data(keystr
));
300 struct netsamlog_cache_forall_state
{
302 int (*cb
)(const char *sid_str
,
304 struct netr_SamInfo3
*,
309 static int netsamlog_cache_traverse_cb(struct tdb_context
*tdb
,
314 struct netsamlog_cache_forall_state
*state
=
315 (struct netsamlog_cache_forall_state
*)private_data
;
316 TALLOC_CTX
*mem_ctx
= NULL
;
318 const char *sid_str
= NULL
;
320 struct netsamlogoncache_entry r
;
321 enum ndr_err_code ndr_err
;
325 if (key
.dsize
== 0) {
328 if (key
.dptr
[key
.dsize
- 1] != '\0') {
331 if (data
.dptr
== NULL
) {
334 sid_str
= (char *)key
.dptr
;
336 ok
= string_to_sid(&sid
, sid_str
);
338 DBG_ERR("String to SID failed for %s\n", sid_str
);
342 if (sid
.num_auths
!= 5) {
346 mem_ctx
= talloc_new(state
->mem_ctx
);
347 if (mem_ctx
== NULL
) {
351 blob
= data_blob_const(data
.dptr
, data
.dsize
);
353 ndr_err
= ndr_pull_struct_blob(
354 &blob
, state
->mem_ctx
, &r
,
355 (ndr_pull_flags_fn_t
)ndr_pull_netsamlogoncache_entry
);
357 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
358 DBG_ERR("failed to pull entry from cache\n");
362 ret
= state
->cb(sid_str
, r
.timestamp
, &r
.info3
, state
->private_data
);
364 TALLOC_FREE(mem_ctx
);
368 int netsamlog_cache_for_all(int (*cb
)(const char *sid_str
,
370 struct netr_SamInfo3
*,
375 TALLOC_CTX
*mem_ctx
= NULL
;
376 struct netsamlog_cache_forall_state state
;
378 if (!netsamlogon_cache_init()) {
379 DBG_ERR("Cannot open %s\n", NETSAMLOGON_TDB
);
383 mem_ctx
= talloc_init("netsamlog_cache_for_all");
384 if (mem_ctx
== NULL
) {
388 state
= (struct netsamlog_cache_forall_state
) {
391 .private_data
= private_data
,
394 ret
= tdb_traverse_read(netsamlogon_tdb
,
395 netsamlog_cache_traverse_cb
,
398 TALLOC_FREE(state
.mem_ctx
);