s3:tldap: add tldap_extended*
[samba.git] / source3 / lib / gencache.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Generic, persistent and shared between processes cache mechanism for use
5    by various parts of the Samba code
6
7    Copyright (C) Rafal Szczesniak    2002
8    Copyright (C) Volker Lendecke     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 "lib/gencache.h"
26 #include "system/filesys.h"
27 #include "system/glob.h"
28 #include "util_tdb.h"
29 #include "tdb_wrap/tdb_wrap.h"
30 #include "zlib.h"
31 #include "lib/util/strv.h"
32 #include "lib/util/util_paths.h"
33
34 #undef  DBGC_CLASS
35 #define DBGC_CLASS DBGC_TDB
36
37 #define GENCACHE_USER_PATH "~/.cache/samba/gencache.tdb"
38
39 static struct tdb_wrap *cache;
40
41 /**
42  * @file gencache.c
43  * @brief Generic, persistent and shared between processes cache mechanism
44  *        for use by various parts of the Samba code
45  *
46  **/
47
48 static bool gencache_pull_timeout(TDB_DATA key,
49                                   TDB_DATA data,
50                                   time_t *pres,
51                                   DATA_BLOB *payload);
52
53 struct gencache_timeout {
54         time_t timeout;
55 };
56
57 bool gencache_timeout_expired(const struct gencache_timeout *t)
58 {
59         return t->timeout <= time(NULL);
60 }
61
62 /**
63  * Cache initialisation function. Opens cache tdb file or creates
64  * it if does not exist.
65  *
66  * @return true on successful initialisation of the cache or
67  *         false on failure
68  **/
69
70 static bool gencache_init(void)
71 {
72         char* cache_fname = NULL;
73         int open_flags = O_RDWR|O_CREAT;
74         int tdb_flags = TDB_INCOMPATIBLE_HASH|TDB_NOSYNC|TDB_MUTEX_LOCKING;
75         int hash_size;
76
77         /* skip file open if it's already opened */
78         if (cache) {
79                 return true;
80         }
81
82         hash_size = lp_parm_int(-1, "gencache", "hash_size", 10000);
83
84         cache_fname = lock_path(talloc_tos(), "gencache.tdb");
85         if (cache_fname == NULL) {
86                 return false;
87         }
88
89         DEBUG(5, ("Opening cache file at %s\n", cache_fname));
90
91         cache = tdb_wrap_open(NULL, cache_fname, hash_size,
92                               tdb_flags,
93                               open_flags, 0644);
94         /*
95          * Allow client tools to create a gencache in the home directory
96          * as a normal user.
97          */
98         if (cache == NULL && errno == EACCES && geteuid() != 0) {
99                 char *cache_dname = NULL, *tmp = NULL;
100                 bool ok;
101
102                 TALLOC_FREE(cache_fname);
103
104                 cache_fname = path_expand_tilde(talloc_tos(),
105                                                 GENCACHE_USER_PATH);
106                 if (cache_fname == NULL) {
107                         DBG_ERR("Failed to expand path: %s\n",
108                                 GENCACHE_USER_PATH);
109                         return false;
110                 }
111
112                 tmp = talloc_strdup(talloc_tos(), cache_fname);
113                 if (tmp == NULL) {
114                         DBG_ERR("No memory!\n");
115                         TALLOC_FREE(cache_fname);
116                         return false;
117                 }
118
119                 cache_dname = dirname(tmp);
120                 if (cache_dname == NULL) {
121                         DBG_ERR("Invalid path: %s\n", cache_fname);
122                         TALLOC_FREE(tmp);
123                         TALLOC_FREE(cache_fname);
124                         return false;
125                 }
126
127                 ok = directory_create_or_exists_recursive(cache_dname, 0700);
128                 if (!ok) {
129                         DBG_ERR("Failed to create directory: %s - %s\n",
130                                 cache_dname, strerror(errno));
131                         TALLOC_FREE(tmp);
132                         TALLOC_FREE(cache_fname);
133                         return false;
134                 }
135                 TALLOC_FREE(tmp);
136
137                 cache = tdb_wrap_open(NULL,
138                                       cache_fname,
139                                       hash_size,
140                                       tdb_flags,
141                                       open_flags,
142                                       0644);
143                 if (cache != NULL) {
144                         DBG_INFO("Opening user cache file %s.\n",
145                                  cache_fname);
146                 }
147         }
148
149         if (cache == NULL) {
150                 DEBUG(5, ("Opening %s failed: %s\n", cache_fname,
151                           strerror(errno)));
152                 TALLOC_FREE(cache_fname);
153                 return false;
154         }
155         TALLOC_FREE(cache_fname);
156
157         return true;
158 }
159
160 /*
161  * Walk the hash chain for "key", deleting all expired entries for
162  * that hash chain
163  */
164 struct gencache_prune_expired_state {
165         TALLOC_CTX *mem_ctx;
166         char *keys;
167 };
168
169 static int gencache_prune_expired_fn(struct tdb_context *tdb,
170                                      TDB_DATA key,
171                                      TDB_DATA data,
172                                      void *private_data)
173 {
174         struct gencache_prune_expired_state *state = private_data;
175         struct gencache_timeout t;
176         bool ok = false;
177         bool expired = false;
178
179         if ((key.dsize == 0) || (key.dptr[key.dsize-1] != '\0')) {
180                 /* not a valid record, should never happen */
181                 return 0;
182         }
183
184         ok = gencache_pull_timeout(key, data, &t.timeout, NULL);
185         if (ok) {
186                 expired = gencache_timeout_expired(&t);
187         }
188
189         if (!ok || expired) {
190                 int ret;
191
192                 ret = strv_add(state->mem_ctx, &state->keys, (char *)key.dptr);
193                 if (ret != 0) {
194                         /*
195                          * Exit the loop. It's unlikely that it will
196                          * succeed next time.
197                          */
198                         return -1;
199                 }
200         }
201
202         return 0;
203 }
204
205 static void gencache_prune_expired(struct tdb_context *tdb,
206                                    TDB_DATA chain_key)
207 {
208         struct gencache_prune_expired_state state = {
209                 .mem_ctx = talloc_tos(),
210         };
211         char *keystr = NULL;
212         int ret;
213
214         ret = tdb_traverse_key_chain(
215                 tdb, chain_key, gencache_prune_expired_fn, &state);
216         if (ret == -1) {
217                 DBG_DEBUG("tdb_traverse_key_chain failed: %s\n",
218                           tdb_errorstr(tdb));
219                 return;
220         }
221
222         while ((keystr = strv_next(state.keys, keystr)) != NULL) {
223                 TDB_DATA key = string_term_tdb_data(keystr);
224
225                 /*
226                  * We expect the hash chain of "chain_key" to be
227                  * locked. So between gencache_prune_expired_fn
228                  * figuring out "keystr" is expired and the
229                  * tdb_delete, nobody can have reset the timeout.
230                  */
231                 tdb_delete(tdb, key);
232         }
233
234         TALLOC_FREE(state.keys);
235 }
236
237 /**
238  * Set an entry in the cache file. If there's no such
239  * one, then add it.
240  *
241  * @param keystr string that represents a key of this entry
242  * @param blob DATA_BLOB value being cached
243  * @param timeout time when the value is expired
244  *
245  * @retval true when entry is successfully stored
246  * @retval false on failure
247  **/
248
249 bool gencache_set_data_blob(const char *keystr, DATA_BLOB blob,
250                             time_t timeout)
251 {
252         TDB_DATA key;
253         int ret;
254         TDB_DATA dbufs[3];
255         uint32_t crc;
256
257         if ((keystr == NULL) || (blob.data == NULL)) {
258                 return false;
259         }
260
261         key = string_term_tdb_data(keystr);
262
263         if (!gencache_init()) {
264                 return false;
265         }
266
267         dbufs[0] = (TDB_DATA) { .dptr = (uint8_t *)&timeout,
268                                 .dsize = sizeof(time_t) };
269         dbufs[1] = (TDB_DATA) { .dptr = blob.data, .dsize = blob.length };
270
271         crc = crc32(0, Z_NULL, 0);
272         crc = crc32(crc, key.dptr, key.dsize);
273         crc = crc32(crc, dbufs[0].dptr, dbufs[0].dsize);
274         crc = crc32(crc, dbufs[1].dptr, dbufs[1].dsize);
275
276         dbufs[2] = (TDB_DATA) { .dptr = (uint8_t *)&crc,
277                                 .dsize = sizeof(crc) };
278
279         DBG_DEBUG("Adding cache entry with key=[%s] and timeout="
280                    "[%s] (%ld seconds %s)\n", keystr,
281                    timestring(talloc_tos(), timeout),
282                    ((long int)timeout) - time(NULL),
283                    timeout > time(NULL) ? "ahead" : "in the past");
284
285         ret = tdb_chainlock(cache->tdb, key);
286         if (ret == -1) {
287                 DBG_WARNING("tdb_chainlock for key [%s] failed: %s\n",
288                             keystr, tdb_errorstr(cache->tdb));
289                 return false;
290         }
291
292         gencache_prune_expired(cache->tdb, key);
293
294         ret = tdb_storev(cache->tdb, key, dbufs, ARRAY_SIZE(dbufs), 0);
295
296         tdb_chainunlock(cache->tdb, key);
297
298         if (ret == 0) {
299                 return true;
300         }
301         if (tdb_error(cache->tdb) != TDB_ERR_CORRUPT) {
302                 return false;
303         }
304
305         ret = tdb_wipe_all(cache->tdb);
306         SMB_ASSERT(ret == 0);
307
308         return false;
309 }
310
311 /**
312  * Delete one entry from the cache file.
313  *
314  * @param keystr string that represents a key of this entry
315  *
316  * @retval true upon successful deletion
317  * @retval false in case of failure
318  **/
319
320 bool gencache_del(const char *keystr)
321 {
322         TDB_DATA key = string_term_tdb_data(keystr);
323         int ret;
324
325         if (keystr == NULL) {
326                 return false;
327         }
328
329         if (!gencache_init()) {
330                 return false;
331         }
332
333         DEBUG(10, ("Deleting cache entry (key=[%s])\n", keystr));
334
335         ret = tdb_delete(cache->tdb, key);
336
337         if (ret == 0) {
338                 return true;
339         }
340         if (tdb_error(cache->tdb) != TDB_ERR_CORRUPT) {
341                 return false;
342         }
343
344         ret = tdb_wipe_all(cache->tdb);
345         SMB_ASSERT(ret == 0);
346
347         return true;            /* We've deleted a bit more... */
348 }
349
350 static bool gencache_pull_timeout(TDB_DATA key,
351                                   TDB_DATA data,
352                                   time_t *pres,
353                                   DATA_BLOB *payload)
354 {
355         size_t crc_ofs;
356         uint32_t crc, stored_crc;
357
358         if ((data.dptr == NULL) ||
359             (data.dsize < (sizeof(time_t) + sizeof(uint32_t)))) {
360                 return false;
361         }
362
363         crc_ofs = data.dsize - sizeof(uint32_t);
364
365         crc = crc32(0, Z_NULL, 0);
366         crc = crc32(crc, key.dptr, key.dsize);
367         crc = crc32(crc, data.dptr, crc_ofs);
368
369         memcpy(&stored_crc, data.dptr + crc_ofs, sizeof(uint32_t));
370
371         if (stored_crc != crc) {
372                 return false;
373         }
374
375         if (pres != NULL) {
376                 memcpy(pres, data.dptr, sizeof(time_t));
377         }
378         if (payload != NULL) {
379                 *payload = (DATA_BLOB) {
380                         .data = data.dptr+sizeof(time_t),
381                         .length = data.dsize-sizeof(time_t)-sizeof(uint32_t),
382                 };
383         }
384         return true;
385 }
386
387 struct gencache_parse_state {
388         void (*parser)(const struct gencache_timeout *timeout,
389                        DATA_BLOB blob,
390                        void *private_data);
391         void *private_data;
392         bool format_error;
393 };
394
395 static int gencache_parse_fn(TDB_DATA key, TDB_DATA data, void *private_data)
396 {
397         struct gencache_parse_state *state = private_data;
398         struct gencache_timeout t;
399         DATA_BLOB payload;
400         bool ret;
401
402         ret = gencache_pull_timeout(key, data, &t.timeout, &payload);
403         if (!ret) {
404                 state->format_error = true;
405                 return 0;
406         }
407         state->parser(&t, payload, state->private_data);
408
409         return 0;
410 }
411
412 bool gencache_parse(const char *keystr,
413                     void (*parser)(const struct gencache_timeout *timeout,
414                                    DATA_BLOB blob,
415                                    void *private_data),
416                     void *private_data)
417 {
418         struct gencache_parse_state state = {
419                 .parser = parser, .private_data = private_data
420         };
421         TDB_DATA key = string_term_tdb_data(keystr);
422         int ret;
423
424         if (keystr == NULL) {
425                 return false;
426         }
427         if (!gencache_init()) {
428                 return false;
429         }
430
431         ret = tdb_parse_record(cache->tdb, key,
432                                gencache_parse_fn, &state);
433         if ((ret == -1) && (tdb_error(cache->tdb) == TDB_ERR_CORRUPT)) {
434                 goto wipe;
435         }
436         if (ret == -1) {
437                 return false;
438         }
439         if (state.format_error) {
440                 ret = tdb_delete(cache->tdb, key);
441                 if (ret == -1) {
442                         goto wipe;
443                 }
444                 return false;
445         }
446         return true;
447
448 wipe:
449         ret = tdb_wipe_all(cache->tdb);
450         SMB_ASSERT(ret == 0);
451         return false;
452 }
453
454 struct gencache_get_data_blob_state {
455         TALLOC_CTX *mem_ctx;
456         DATA_BLOB *blob;
457         time_t timeout;
458         bool result;
459 };
460
461 static void gencache_get_data_blob_parser(const struct gencache_timeout *t,
462                                           DATA_BLOB blob,
463                                           void *private_data)
464 {
465         struct gencache_get_data_blob_state *state =
466                 (struct gencache_get_data_blob_state *)private_data;
467
468         if (t->timeout == 0) {
469                 state->result = false;
470                 return;
471         }
472         state->timeout = t->timeout;
473
474         if (state->blob == NULL) {
475                 state->result = true;
476                 return;
477         }
478
479         *state->blob = data_blob_talloc(state->mem_ctx, blob.data,
480                                         blob.length);
481         if (state->blob->data == NULL) {
482                 state->result = false;
483                 return;
484         }
485         state->result = true;
486 }
487
488 /**
489  * Get existing entry from the cache file.
490  *
491  * @param keystr string that represents a key of this entry
492  * @param blob DATA_BLOB that is filled with entry's blob
493  * @param timeout pointer to a time_t that is filled with entry's
494  *        timeout
495  *
496  * @retval true when entry is successfully fetched
497  * @retval false for failure
498  **/
499
500 bool gencache_get_data_blob(const char *keystr, TALLOC_CTX *mem_ctx,
501                             DATA_BLOB *blob,
502                             time_t *timeout, bool *was_expired)
503 {
504         struct gencache_get_data_blob_state state;
505         bool expired = false;
506
507         state.result = false;
508         state.mem_ctx = mem_ctx;
509         state.blob = blob;
510
511         if (!gencache_parse(keystr, gencache_get_data_blob_parser, &state)) {
512                 goto fail;
513         }
514         if (!state.result) {
515                 goto fail;
516         }
517         if (state.timeout <= time(NULL)) {
518                 /*
519                  * We're expired, delete the entry. We can't use gencache_del
520                  * here, because that uses gencache_get_data_blob for checking
521                  * the existence of a record. We know the thing exists and
522                  * directly store an empty value with 0 timeout.
523                  */
524                 gencache_set(keystr, "", 0);
525                 expired = true;
526                 goto fail;
527         }
528         if (timeout) {
529                 *timeout = state.timeout;
530         }
531
532         return true;
533
534 fail:
535         if (was_expired != NULL) {
536                 *was_expired = expired;
537         }
538         if (state.result && state.blob) {
539                 data_blob_free(state.blob);
540         }
541         return false;
542
543
544 /**
545  * Get existing entry from the cache file.
546  *
547  * @param keystr string that represents a key of this entry
548  * @param valstr buffer that is allocated and filled with the entry value
549  *        buffer's disposing must be done outside
550  * @param timeout pointer to a time_t that is filled with entry's
551  *        timeout
552  *
553  * @retval true when entry is successfully fetched
554  * @retval false for failure
555  **/
556
557 bool gencache_get(const char *keystr, TALLOC_CTX *mem_ctx, char **value,
558                   time_t *ptimeout)
559 {
560         DATA_BLOB blob;
561         bool ret = false;
562
563         ret = gencache_get_data_blob(keystr, mem_ctx, &blob, ptimeout, NULL);
564         if (!ret) {
565                 return false;
566         }
567         if ((blob.data == NULL) || (blob.length == 0)) {
568                 data_blob_free(&blob);
569                 return false;
570         }
571         if (blob.data[blob.length-1] != '\0') {
572                 /* Not NULL terminated, can't be a string */
573                 data_blob_free(&blob);
574                 return false;
575         }
576         if (value) {
577                 /*
578                  * talloc_move generates a type-punned warning here. As we
579                  * leave the function immediately, do a simple talloc_steal.
580                  */
581                 *value = (char *)talloc_steal(mem_ctx, blob.data);
582                 return true;
583         }
584         data_blob_free(&blob);
585         return true;
586 }
587
588 /**
589  * Set an entry in the cache file. If there's no such
590  * one, then add it.
591  *
592  * @param keystr string that represents a key of this entry
593  * @param value text representation value being cached
594  * @param timeout time when the value is expired
595  *
596  * @retval true when entry is successfully stored
597  * @retval false on failure
598  **/
599
600 bool gencache_set(const char *keystr, const char *value, time_t timeout)
601 {
602         DATA_BLOB blob = data_blob_const(value, strlen(value)+1);
603         return gencache_set_data_blob(keystr, blob, timeout);
604 }
605
606 struct gencache_iterate_blobs_state {
607         void (*fn)(const char *key, DATA_BLOB value,
608                    time_t timeout, void *private_data);
609         const char *pattern;
610         void *private_data;
611 };
612
613 static int gencache_iterate_blobs_fn(struct tdb_context *tdb, TDB_DATA key,
614                                      TDB_DATA data, void *priv)
615 {
616         struct gencache_iterate_blobs_state *state =
617                 (struct gencache_iterate_blobs_state *)priv;
618         char *keystr;
619         char *free_key = NULL;
620         time_t timeout;
621         DATA_BLOB payload;
622
623         if (key.dptr[key.dsize-1] == '\0') {
624                 keystr = (char *)key.dptr;
625         } else {
626                 /* ensure 0-termination */
627                 keystr = talloc_strndup(talloc_tos(), (char *)key.dptr, key.dsize);
628                 free_key = keystr;
629                 if (keystr == NULL) {
630                         goto done;
631                 }
632         }
633
634         if (!gencache_pull_timeout(key, data, &timeout, &payload)) {
635                 goto done;
636         }
637
638         if (timeout == 0) {
639                 /* delete marker */
640                 goto done;
641         }
642
643         if (fnmatch(state->pattern, keystr, 0) != 0) {
644                 goto done;
645         }
646
647         DEBUG(10, ("Calling function with arguments "
648                    "(key=[%s], timeout=[%s])\n",
649                    keystr, timestring(talloc_tos(), timeout)));
650
651         state->fn(keystr, payload, timeout, state->private_data);
652
653  done:
654         TALLOC_FREE(free_key);
655         return 0;
656 }
657
658 void gencache_iterate_blobs(void (*fn)(const char *key, DATA_BLOB value,
659                                        time_t timeout, void *private_data),
660                             void *private_data, const char *pattern)
661 {
662         struct gencache_iterate_blobs_state state;
663         int ret;
664
665         if ((fn == NULL) || (pattern == NULL) || !gencache_init()) {
666                 return;
667         }
668
669         DEBUG(5, ("Searching cache keys with pattern %s\n", pattern));
670
671         state.fn = fn;
672         state.pattern = pattern;
673         state.private_data = private_data;
674
675         ret = tdb_traverse(cache->tdb, gencache_iterate_blobs_fn, &state);
676
677         if ((ret == -1) && (tdb_error(cache->tdb) == TDB_ERR_CORRUPT)) {
678                 ret = tdb_wipe_all(cache->tdb);
679                 SMB_ASSERT(ret == 0);
680         }
681 }
682
683 /**
684  * Iterate through all entries which key matches to specified pattern
685  *
686  * @param fn pointer to the function that will be supplied with each single
687  *        matching cache entry (key, value and timeout) as an arguments
688  * @param data void pointer to an arbitrary data that is passed directly to the fn
689  *        function on each call
690  * @param keystr_pattern pattern the existing entries' keys are matched to
691  *
692  **/
693
694 struct gencache_iterate_state {
695         void (*fn)(const char *key, const char *value, time_t timeout,
696                    void *priv);
697         void *private_data;
698 };
699
700 static void gencache_iterate_fn(const char *key, DATA_BLOB value,
701                                 time_t timeout, void *private_data)
702 {
703         struct gencache_iterate_state *state =
704                 (struct gencache_iterate_state *)private_data;
705         char *valstr;
706         char *free_val = NULL;
707
708         if (value.data[value.length-1] == '\0') {
709                 valstr = (char *)value.data;
710         } else {
711                 /* ensure 0-termination */
712                 valstr = talloc_strndup(talloc_tos(), (char *)value.data, value.length);
713                 free_val = valstr;
714                 if (valstr == NULL) {
715                         goto done;
716                 }
717         }
718
719         DEBUG(10, ("Calling function with arguments "
720                    "(key=[%s], value=[%s], timeout=[%s])\n",
721                    key, valstr, timestring(talloc_tos(), timeout)));
722
723         state->fn(key, valstr, timeout, state->private_data);
724
725   done:
726
727         TALLOC_FREE(free_val);
728 }
729
730 void gencache_iterate(void (*fn)(const char *key, const char *value,
731                                  time_t timeout, void *dptr),
732                       void *private_data, const char *pattern)
733 {
734         struct gencache_iterate_state state;
735
736         if (fn == NULL) {
737                 return;
738         }
739         state.fn = fn;
740         state.private_data = private_data;
741         gencache_iterate_blobs(gencache_iterate_fn, &state, pattern);
742 }