nsssrv_mmap_cache.c revision a3c8390d19593b1e5277d95bfb4ab206d4785150
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen NSS Responder - Mmap Cache
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen Copyright (C) Simo Sorce <ssorce@redhat.com> 2011
e8434aad92ea6ff1c915b708294dbd0c7ff5908dMichael M Slusarz This program is free software; you can redistribute it and/or modify
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen it under the terms of the GNU General Public License as published by
de5f478d9e7ae7b8e58082e0b30b6ce1f034236aTimo Sirainen the Free Software Foundation; either version 3 of the License, or
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen (at your option) any later version.
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen This program is distributed in the hope that it will be useful,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen but WITHOUT ANY WARRANTY; without even the implied warranty of
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen GNU General Public License for more details.
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen You should have received a copy of the GNU General Public License
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen along with this program. If not, see <http://www.gnu.org/licenses/>.
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen/* arbitrary (avg of my /etc/passwd) */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen#define SSS_AVG_PASSWD_PAYLOAD (MC_SLOT_SIZE * 4)
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen/* short group name and no gids (private user group */
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen#define SSS_AVG_GROUP_PAYLOAD (MC_SLOT_SIZE * 3)
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen#define MC_NEXT_BARRIER(val) ((((val) + 1) & 0x00ffffff) | 0xf0000000)
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen#define MC_RAISE_BARRIER(m) do { \
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen#define MC_LOWER_BARRIER(m) do { \
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen uint32_t seed; /* pseudo-random seed to avoid collision attacks */
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen time_t valid_time_slot; /* maximum time the entry is valid in seconds */
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen uint32_t *hash_table; /* hash table address (in mmap) */
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen uint32_t next_slot; /* the next slot after last allocation */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen uint8_t *data_table; /* data table address (in mmap) */
07038d3a12a915e98f794566f56a0ed12e0653ebAki Tuomi if (*b & c) used = true; \
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen else used = false; \
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenuint32_t sss_mc_next_slot_with_hash(struct sss_mc_rec *rec,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* it should never happen. */
2a24f3565c61cb429d1e428601f153ce53b8bae3Timo Sirainenvoid sss_mc_chain_slot_to_record_with_hash(struct sss_mc_rec *rec,
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen /* changing a single uint32_t is atomic, so there is no
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen * need to use barriers in this case */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen/* This function will store corrupted memcache to disk for later
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen * analysis. */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic void sss_mc_save_corrupted(struct sss_mc_ctx *mc_ctx)
61f39b0358a72ebc693d84ba5bac74489ee7df41Timo Sirainen "Cannot store uninitialized cache. Nothing to do.\n");
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory.\n");
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory.\n");
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* We will always store only the last problematic cache state */
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen "Failed to open file '%s' [%d]: %s\n",
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen written = sss_atomic_write_s(fd, mc_ctx->mmap_base, mc_ctx->mmap_size);
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen "write() failed [%d]: %s\n", err, strerror(err));
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen "write() returned %zd (expected (%zd))\n",
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen "Stored copy of corrupted mmap cache in file '%s\n'", file);
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainenstatic uint32_t sss_mc_hash(struct sss_mc_ctx *mcc,
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen return murmurhash3(key, len, mcc->seed) % MC_HT_ELEMS(mcc->ht_size);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic void sss_mc_add_rec_to_chain(struct sss_mc_ctx *mcc,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* Invalid hash. This should never happen, but better
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen * return than trying to access out of bounds memory */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* no previous record/collision, just add to hash table */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen mcc->hash_table[hash] = MC_PTR_TO_SLOT(mcc->data_table, rec);
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen cur = MC_SLOT_TO_PTR(mcc->data_table, slot, struct sss_mc_rec);
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen /* rec already stored in hash chain */
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen /* end of chain, append our record here */
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen sss_mc_chain_slot_to_record_with_hash(cur, hash, slot);
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainenstatic void sss_mc_rm_rec_from_chain(struct sss_mc_ctx *mcc,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* It can happen if rec->hash1 and rec->hash2 was the same.
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen * or it is invalid hash. It is better to return
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen * than trying to access out of bounds memory
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen /* record has already been removed. It may happen if rec->hash1 and
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen * rec->has2 are the same. (It is not very likely).
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen cur = MC_SLOT_TO_PTR(mcc->data_table, slot, struct sss_mc_rec);
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen mcc->hash_table[hash] = sss_mc_next_slot_with_hash(rec, hash);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen cur = MC_SLOT_TO_PTR(mcc->data_table, slot, struct sss_mc_rec);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen sss_mc_chain_slot_to_record_with_hash(prev, hash, slot);
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainenstatic void sss_mc_free_slots(struct sss_mc_ctx *mcc, struct sss_mc_rec *rec)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen for (i = 0; i < num; i++) {
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainenstatic void sss_mc_invalidate_rec(struct sss_mc_ctx *mcc,
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen /* record already invalid */
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen /* Remove from hash chains */
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen /* hash chain 1 */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen sss_mc_rm_rec_from_chain(mcc, rec, rec->hash1);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* hash chain 2 */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen sss_mc_rm_rec_from_chain(mcc, rec, rec->hash2);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* Clear from free_table */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* Invalidate record fields */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen memset(rec->data, MC_INVALID_VAL8, ((MC_SLOT_SIZE * MC_SIZE_TO_SLOTS(rec->len))
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen - sizeof(struct sss_mc_rec)));
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic bool sss_mc_is_valid_rec(struct sss_mc_ctx *mcc, struct sss_mc_rec *rec)
7c04ede0da5749691624a1fb962ac29cd0167050Timo Sirainen ((uint8_t *)rec > (mcc->data_table + mcc->dt_size - MC_SLOT_SIZE))) {
7c04ede0da5749691624a1fb962ac29cd0167050Timo Sirainen return false;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return false;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return false;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return false;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* next record can be invalid if there are no next records */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return false;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen while (slot != MC_INVALID_VAL32 && self != rec) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen self = MC_SLOT_TO_PTR(mcc->data_table, slot, struct sss_mc_rec);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen slot = sss_mc_next_slot_with_hash(self, rec->hash1);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return false;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen while (slot != MC_INVALID_VAL32 && self != rec) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen self = MC_SLOT_TO_PTR(mcc->data_table, slot, struct sss_mc_rec);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen slot = sss_mc_next_slot_with_hash(self, rec->hash2);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen return false;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* all tests passed */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen/* FIXME: This is a very simplistic, inefficient, memory allocator,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen * it will just free the oldest entries regardless of expiration if it
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen * cycled the whole freebits map and found no empty slot */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic errno_t sss_mc_find_free_slots(struct sss_mc_ctx *mcc,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* Try to find a free slot w/o removing anything first */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* FIXME: is it really worth it ? May be it is easier to
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen * just recycle the next set of slots ? */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if ((mcc->next_slot + num_slots) > tot_slots) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* search for enough (num_slots) consecutive zero bits, indicating
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen * consecutive empty slots */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* if all full in this byte skip directly to the next */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* at least one bit in this byte is marked as empty */
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen /* check if we have enough slots before hitting the table end */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* check if we have at least num_slots empty starting from the first
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen * we found in the previous steps */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* ok found num_slots consecutive free bits */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* no free slots found, free occupied slots after next_slot */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if ((mcc->next_slot + num_slots) > tot_slots) {
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen for (i = 0; i < num_slots; i++) {
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen /* the first used slot should be a record header, however we
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen * carefully check it is a valid header and hardfail if not */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen rec = MC_SLOT_TO_PTR(mcc->data_table, cur + i, struct sss_mc_rec);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* this is a fatal error, the caller should probaly just
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen * invalidate the whole cache */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* next loop skip the whole record */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* finally invalidate record completely */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic errno_t sss_mc_get_strs_offset(struct sss_mc_ctx *mcc,
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen *_offset = offsetof(struct sss_mc_pwd_data, strs);
6ea145a99eeee923602f04d3c9183bbdba6cd190Timo Sirainen *_offset = offsetof(struct sss_mc_grp_data, strs);
7cd055a212d44067e2d94452c05691d696c9f699Timo Sirainen DEBUG(SSSDBG_FATAL_FAILURE, "Unknown memory cache type.\n");
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic errno_t sss_mc_get_strs_len(struct sss_mc_ctx *mcc,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen *_len = ((struct sss_mc_pwd_data *)&rec->data)->strs_len;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen *_len = ((struct sss_mc_grp_data *)&rec->data)->strs_len;
e8434aad92ea6ff1c915b708294dbd0c7ff5908dMichael M Slusarz DEBUG(SSSDBG_FATAL_FAILURE, "Unknown memory cache type.\n");
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic struct sss_mc_rec *sss_mc_find_record(struct sss_mc_ctx *mcc,
ce74395e2a932342e04fb682395bcce111574969Timo Sirainen if (!MC_SLOT_WITHIN_BOUNDS(slot, mcc->dt_size)) {
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen /* Get max address of data table. */
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen ret = sss_mc_get_strs_offset(mcc, &strs_offset);
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen if (!MC_SLOT_WITHIN_BOUNDS(slot, mcc->dt_size)) {
a1044a46a8f3512173f4ea2684ef1fc3e61645c7Timo Sirainen "Corrupted fastcache. Slot number too big.\n");
f9eee365367f37b1692c07db6c23d30243844aaaTimo Sirainen rec = MC_SLOT_TO_PTR(mcc->data_table, slot, struct sss_mc_rec);
f9eee365367f37b1692c07db6c23d30243844aaaTimo Sirainen ret = sss_mc_get_strs_len(mcc, rec, &strs_len);
2599a77a28bde0653fa090802424469904d518eeTimo Sirainen safealign_memcpy(&name_ptr, rec->data, sizeof(rel_ptr_t), NULL);
2599a77a28bde0653fa090802424469904d518eeTimo Sirainen || (name_ptr + key->len) > (strs_offset + strs_len)
2599a77a28bde0653fa090802424469904d518eeTimo Sirainen || (uint8_t *)rec->data + strs_offset + strs_len > max_addr) {
f7d018e7e0980044e3d537958126e44ef4c45056Timo Sirainen "Corrupted fastcache. name_ptr value is %u.\n", name_ptr);
07038d3a12a915e98f794566f56a0ed12e0653ebAki Tuomistatic errno_t sss_mc_get_record(struct sss_mc_ctx **_mcc,
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen /* slot size changed, invalidate record and fall through to get a
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen * fully new record */
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen /* we are going to use more space, find enough free slots */
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen ret = sss_mc_find_free_slots(mcc, num_slots, &base_slot);
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen "Fatal internal mmap cache error, invalidating cache!\n");
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen (void)sss_mmap_cache_reinit(talloc_parent(mcc), -1, -1, _mcc);
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen rec = MC_SLOT_TO_PTR(mcc->data_table, base_slot, struct sss_mc_rec);
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen /* mark as not valid yet */
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen /* and now mark slots as used */
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen for (i = 0; i < num_slots; i++) {
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainenstatic inline void sss_mmap_set_rec_header(struct sss_mc_ctx *mcc,
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi rec->hash1 = sss_mc_hash(mcc, key1, key1_len);
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen rec->hash2 = sss_mc_hash(mcc, key2, key2_len);
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainenstatic inline void sss_mmap_chain_in_rec(struct sss_mc_ctx *mcc,
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen /* name first */
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen sss_mc_add_rec_to_chain(mcc, rec, rec->hash1);
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen sss_mc_add_rec_to_chain(mcc, rec, rec->hash2);
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen/***************************************************************************
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen * generic invalidation
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen ***************************************************************************/
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainenstatic errno_t sss_mmap_cache_invalidate(struct sss_mc_ctx *mcc,
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen /* cache not initialized ? */
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen /* nothing to invalidate */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen/***************************************************************************
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ***************************************************************************/
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenerrno_t sss_mmap_cache_pw_store(struct sss_mc_ctx **_mcc,
c72cfe4a2bda39fff3b8a8bd64b31a7cc14d7d11Timo Sirainen /* cache not initialized ? */
2599a77a28bde0653fa090802424469904d518eeTimo Sirainen data_len = name->len + pw->len + gecos->len + homedir->len + shell->len;
2599a77a28bde0653fa090802424469904d518eeTimo Sirainen sizeof(struct sss_mc_pwd_data) +
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen ret = sss_mc_get_record(_mcc, rec_len, name, &rec);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen sss_mmap_set_rec_header(mcc, rec, rec_len, mcc->valid_time_slot,
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen name->str, name->len, uidkey.str, uidkey.len);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* passwd struct */
709ee5a909d482f31611f9e6cc10d893a272e061Timo Sirainen memcpy(&data->strs[pos], name->str, name->len);
f0e416aa42058e7ccc0dc6deec0d4f4a19ee6ebeTimo Sirainen memcpy(&data->strs[pos], gecos->str, gecos->len);
ba4626cd5be3d225a7a89aa338d92b8fb411fd1cTimo Sirainen memcpy(&data->strs[pos], homedir->str, homedir->len);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen memcpy(&data->strs[pos], shell->str, shell->len);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* finally chain the rec in the hash table */
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainenerrno_t sss_mmap_cache_pw_invalidate(struct sss_mc_ctx *mcc,
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainenerrno_t sss_mmap_cache_pw_invalidate_uid(struct sss_mc_ctx *mcc, uid_t uid)
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen /* cache not initialized ? */
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen uidstr = talloc_asprintf(NULL, "%ld", (long)uid);
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen hash = sss_mc_hash(mcc, uidstr, strlen(uidstr) + 1);
b6c9cc2bf7517adcc0b9f98696c61bde321900f6Timo Sirainen if (!MC_SLOT_WITHIN_BOUNDS(slot, mcc->dt_size)) {
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen if (!MC_SLOT_WITHIN_BOUNDS(slot, mcc->dt_size)) {
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen DEBUG(SSSDBG_FATAL_FAILURE, "Corrupted fastcache.\n");
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen rec = MC_SLOT_TO_PTR(mcc->data_table, slot, struct sss_mc_rec);
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen data = (struct sss_mc_pwd_data *)(&rec->data);
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen/***************************************************************************
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen ***************************************************************************/
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainenint sss_mmap_cache_gr_store(struct sss_mc_ctx **_mcc,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* cache not initialized ? */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen sizeof(struct sss_mc_grp_data) +
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ret = sss_mc_get_record(_mcc, rec_len, name, &rec);
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen sss_mmap_set_rec_header(mcc, rec, rec_len, mcc->valid_time_slot,
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen name->str, name->len, gidkey.str, gidkey.len);
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen /* group struct */
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen memcpy(&data->strs[pos], name->str, name->len);
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen /* finally chain the rec in the hash table */
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainenerrno_t sss_mmap_cache_gr_invalidate(struct sss_mc_ctx *mcc,
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainenerrno_t sss_mmap_cache_gr_invalidate_gid(struct sss_mc_ctx *mcc, gid_t gid)
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen /* cache not initialized ? */
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen gidstr = talloc_asprintf(NULL, "%ld", (long)gid);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen hash = sss_mc_hash(mcc, gidstr, strlen(gidstr) + 1);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen if (!MC_SLOT_WITHIN_BOUNDS(slot, mcc->dt_size)) {
0098ac3b6dcd8ef6ac20f87a8285da201db75a01Timo Sirainen if (!MC_SLOT_WITHIN_BOUNDS(slot, mcc->dt_size)) {
0098ac3b6dcd8ef6ac20f87a8285da201db75a01Timo Sirainen DEBUG(SSSDBG_FATAL_FAILURE, "Corrupted fastcache.\n");
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen rec = MC_SLOT_TO_PTR(mcc->data_table, slot, struct sss_mc_rec);
caf029d36a826106e48b8682f15ea0fc01fdd8f4Timo Sirainen data = (struct sss_mc_grp_data *)(&rec->data);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen/***************************************************************************
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen * initialization
f9cf9852b0338910f1a710297374943d66fea480Timo Sirainen ***************************************************************************/
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen/* Copy of sss_mc_set_recycled is present in the src/tools/tools_mc_util.c.
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen * If you modify this function, you should modify the duplicated function
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen /* What do we do now ? */
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen ret = sss_atomic_write_s(fd, (uint8_t *)&w, sizeof(h.status));
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen /* Write error */
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen * When we (re)create a new file we must mark the current file as recycled
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen * so active clients will abandon its use asap.
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen * We unlink the current file and make a new one
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainenstatic errno_t sss_mc_create_file(struct sss_mc_ctx *mc_ctx)
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen ret = sss_br_lock_file(ofd, 0, 1, retries, t);
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen DEBUG(SSSDBG_FATAL_FAILURE, "Failed to mark mmap file %s as"
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen " recycled: %d(%s)\n",
2a24f3565c61cb429d1e428601f153ce53b8bae3Timo Sirainen "Failed to open old memory cache file %s: %d(%s).\n",
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen DEBUG(SSSDBG_TRACE_FUNC, "Failed to rm mmap file %s: %d(%s)\n",
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* temporarily relax umask as we need the file to be readable
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen * by everyone for now */
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen mc_ctx->fd = open(mc_ctx->file, O_CREAT | O_EXCL | O_RDWR, 0644);
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen DEBUG(SSSDBG_CRIT_FAILURE, "Failed to open mmap file %s: %d(%s)\n",
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ret = sss_br_lock_file(mc_ctx->fd, 0, 1, retries, t);
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen /* Report on unlink failures but don't overwrite the errno
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen * from sss_br_lock_file
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen DEBUG(SSSDBG_TRACE_FUNC, "Failed to rm mmap file %s: %d(%s)\n",
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainenstatic void sss_mc_header_update(struct sss_mc_ctx *mc_ctx, int status)
1128c114416bdc4df0b41d3e15429a1522e5cfe4Timo Sirainen /* update header using barriers */
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen h = (struct sss_mc_header *)mc_ctx->mmap_base;
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen /* no reason to update anything else if the file is recycled or
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen * right before reset */
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen h->hash_table = MC_PTR_DIFF(mc_ctx->hash_table, mc_ctx->mmap_base);
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen h->free_table = MC_PTR_DIFF(mc_ctx->free_table, mc_ctx->mmap_base);
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen h->data_table = MC_PTR_DIFF(mc_ctx->data_table, mc_ctx->mmap_base);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainenstatic int mc_ctx_destructor(struct sss_mc_ctx *mc_ctx)
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen /* Print debug message to logs if munmap() or close()
4db61af2cfe2b206113bcc4b6153521679702bb4Timo Sirainen * fail but always return 0 */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ret = munmap(mc_ctx->mmap_base, mc_ctx->mmap_size);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen "Failed to unmap old memory cache file."
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainen "Failed to close old memory cache file."
a5f2707224b10f26e3d478a2b11e8d01f1b8f609Timo Sirainenerrno_t sss_mmap_cache_init(TALLOC_CTX *mem_ctx, const char *name,
1fb5e50695bbbc0da082e5a6f19f29d2bb2f6531Timo Sirainen unsigned int rseed;
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen mc_ctx = talloc_zero(mem_ctx, struct sss_mc_ctx);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen talloc_set_destructor(mc_ctx, mc_ctx_destructor);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen mc_ctx->file = talloc_asprintf(mc_ctx, "%s/%s",
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* elements must always be multiple of 8 to make things easier to handle,
e07677bb15404a3c18ad205efae86d6db31c3150Timo Sirainen * so we increase by the necessary amount if they are not a multiple */
e07677bb15404a3c18ad205efae86d6db31c3150Timo Sirainen /* We can use MC_ALIGN64 for this */
e07677bb15404a3c18ad205efae86d6db31c3150Timo Sirainen /* hash table is double the size because it will store both forward and
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen * reverse keys (name/uid, name/gid, ..) */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen mc_ctx->dt_size = MC_DT_SIZE(n_elem, payload);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* for now ALWAYS create a new file on restart */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen ret = ftruncate(mc_ctx->fd, mc_ctx->mmap_size);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen DEBUG(SSSDBG_CRIT_FAILURE, "Failed to resize file %s: %d(%s)\n",
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen mc_ctx->mmap_base = mmap(NULL, mc_ctx->mmap_size,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen DEBUG(SSSDBG_CRIT_FAILURE, "Failed to mmap file %s(%zu): %d(%s)\n",
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen mc_ctx->data_table = MC_PTR_ADD(mc_ctx->mmap_base, MC_HEADER_SIZE);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen mc_ctx->free_table = MC_PTR_ADD(mc_ctx->data_table,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen mc_ctx->hash_table = MC_PTR_ADD(mc_ctx->free_table,
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen memset(mc_ctx->data_table, 0xff, mc_ctx->dt_size);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen memset(mc_ctx->free_table, 0x00, mc_ctx->ft_size);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen memset(mc_ctx->hash_table, 0xff, mc_ctx->ht_size);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* generate a pseudo-random seed.
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen * Needed to fend off dictionary based collision attacks */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen sss_mc_header_update(mc_ctx, SSS_MC_HEADER_ALIVE);
61f39b0358a72ebc693d84ba5bac74489ee7df41Timo Sirainen /* Closing the file descriptor and ummaping the file
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen * from memory is done in the mc_ctx_destructor. */
61f39b0358a72ebc693d84ba5bac74489ee7df41Timo Sirainen if (mc_ctx && mc_ctx->file && mc_ctx->fd != -1) {
b096ecf3188cdb9162460ed7ae885c03f3161462Timo Sirainen "Failed to rm mmap file %s: %d(%s)\n", mc_ctx->file,
b096ecf3188cdb9162460ed7ae885c03f3161462Timo Sirainenerrno_t sss_mmap_cache_reinit(TALLOC_CTX *mem_ctx, size_t n_elem,
769cbb608e9ed620063708aff49fc1b6e924394aTimo Sirainen "Unable to re-init unitialized memory cache.\n");
769cbb608e9ed620063708aff49fc1b6e924394aTimo Sirainen DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory.\n");
769cbb608e9ed620063708aff49fc1b6e924394aTimo Sirainen name = talloc_strdup(tmp_ctx, (*mc_ctx)->name);
b096ecf3188cdb9162460ed7ae885c03f3161462Timo Sirainen DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory.\n");
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* make sure we do not leave a potentially freed pointer around */
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen ret = sss_mmap_cache_init(mem_ctx, name, type, n_elem, timeout, mc_ctx);
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen DEBUG(SSSDBG_CRIT_FAILURE, "Failed to re-initialize mmap cache.\n");
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen/* Erase all contents of the mmap cache. This will bring the cache
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainen * to the same state as if it was just initialized. */
dd3d20d9b5821077164183a260af9bde0db3ff3fTimo Sirainenvoid sss_mmap_cache_reset(struct sss_mc_ctx *mc_ctx)
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen "Fastcache not initialized. Nothing to do.\n");
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen sss_mc_header_update(mc_ctx, SSS_MC_HEADER_UNINIT);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen /* Reset the mmaped area */
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen memset(mc_ctx->data_table, 0xff, mc_ctx->dt_size);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen memset(mc_ctx->free_table, 0x00, mc_ctx->ft_size);
b772ddf3cfb606dddaa465b317a0dc01bf06c6e4Timo Sirainen memset(mc_ctx->hash_table, 0xff, mc_ctx->ht_size);