eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce NSS Responder - Mmap Cache
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce Copyright (C) Simo Sorce <ssorce@redhat.com> 2011
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce This program is free software; you can redistribute it and/or modify
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce it under the terms of the GNU General Public License as published by
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce the Free Software Foundation; either version 3 of the License, or
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce (at your option) any later version.
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce This program is distributed in the hope that it will be useful,
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce but WITHOUT ANY WARRANTY; without even the implied warranty of
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce GNU General Public License for more details.
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce You should have received a copy of the GNU General Public License
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce along with this program. If not, see <http://www.gnu.org/licenses/>.
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce/* arbitrary (avg of my /etc/passwd) */
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce/* short group name and no gids (private user group */
dda0258705de7255e6ec54b7f9adbde83a220996Lukas Slebodnik/* average place for 40 supplementary groups + 2 names */
dda0258705de7255e6ec54b7f9adbde83a220996Lukas Slebodnik#define SSS_AVG_INITGROUP_PAYLOAD (MC_SLOT_SIZE * 5)
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce#define MC_NEXT_BARRIER(val) ((((val) + 1) & 0x00ffffff) | 0xf0000000)
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce uint32_t seed; /* pseudo-random seed to avoid collision attacks */
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce time_t valid_time_slot; /* maximum time the entry is valid in seconds */
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce uint32_t *hash_table; /* hash table address (in mmap) */
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce uint32_t next_slot; /* the next slot after last allocation */
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce uint8_t *data_table; /* data table address (in mmap) */
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorce if (*b & c) used = true; \
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorce else used = false; \
581de96fc30b7fe44070f17a8a73f3374d38d6ffLukas Slebodnikuint32_t sss_mc_next_slot_with_hash(struct sss_mc_rec *rec,
581de96fc30b7fe44070f17a8a73f3374d38d6ffLukas Slebodnik /* it should never happen. */
581de96fc30b7fe44070f17a8a73f3374d38d6ffLukas Slebodnikvoid sss_mc_chain_slot_to_record_with_hash(struct sss_mc_rec *rec,
581de96fc30b7fe44070f17a8a73f3374d38d6ffLukas Slebodnik /* changing a single uint32_t is atomic, so there is no
581de96fc30b7fe44070f17a8a73f3374d38d6ffLukas Slebodnik * need to use barriers in this case */
f9091077bfbb09f052d08e25ac5e00af0baa6dfbMichal Zidek/* This function will store corrupted memcache to disk for later
f9091077bfbb09f052d08e25ac5e00af0baa6dfbMichal Zidek * analysis. */
f9091077bfbb09f052d08e25ac5e00af0baa6dfbMichal Zidekstatic void sss_mc_save_corrupted(struct sss_mc_ctx *mc_ctx)
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov "Cannot store uninitialized cache. Nothing to do.\n");
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory.\n");
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory.\n");
f9091077bfbb09f052d08e25ac5e00af0baa6dfbMichal Zidek /* We will always store only the last problematic cache state */
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov "Failed to open file '%s' [%d]: %s\n",
1f7fb30cc25765e54841e5d5f4192c12e3b29a16Michal Zidek written = sss_atomic_write_s(fd, mc_ctx->mmap_base, mc_ctx->mmap_size);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov "write() failed [%d]: %s\n", err, strerror(err));
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov "write() returned %zd (expected (%zd))\n",
f9091077bfbb09f052d08e25ac5e00af0baa6dfbMichal Zidek "Stored copy of corrupted mmap cache in file '%s\n'", file);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov "Failed to remove file '%s': %s.\n", file,
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorcestatic uint32_t sss_mc_hash(struct sss_mc_ctx *mcc,
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorce return murmurhash3(key, len, mcc->seed) % MC_HT_ELEMS(mcc->ht_size);
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorcestatic void sss_mc_add_rec_to_chain(struct sss_mc_ctx *mcc,
8437e782fdf97945e9e0c2a793ffaf49abc2c0caSimo Sorce /* Invalid hash. This should never happen, but better
8437e782fdf97945e9e0c2a793ffaf49abc2c0caSimo Sorce * return than trying to access out of bounds memory */
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorce /* no previous record/collision, just add to hash table */
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorce mcc->hash_table[hash] = MC_PTR_TO_SLOT(mcc->data_table, rec);
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorce cur = MC_SLOT_TO_PTR(mcc->data_table, slot, struct sss_mc_rec);
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorce /* rec already stored in hash chain */
581de96fc30b7fe44070f17a8a73f3374d38d6ffLukas Slebodnik slot = sss_mc_next_slot_with_hash(cur, hash);
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorce /* end of chain, append our record here */
581de96fc30b7fe44070f17a8a73f3374d38d6ffLukas Slebodnik slot = MC_PTR_TO_SLOT(mcc->data_table, rec);
581de96fc30b7fe44070f17a8a73f3374d38d6ffLukas Slebodnik sss_mc_chain_slot_to_record_with_hash(cur, hash, slot);
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorcestatic void sss_mc_rm_rec_from_chain(struct sss_mc_ctx *mcc,
b8d0374cd23db90fce203292ff547641f62e338aLukas Slebodnik /* It can happen if rec->hash1 and rec->hash2 was the same.
b8d0374cd23db90fce203292ff547641f62e338aLukas Slebodnik * or it is invalid hash. It is better to return
b8d0374cd23db90fce203292ff547641f62e338aLukas Slebodnik * than trying to access out of bounds memory
27ea6c34e9d8a914b0aeebe9ca98eb65dea404d0Lukas Slebodnik /* record has already been removed. It may happen if rec->hash1 and
27ea6c34e9d8a914b0aeebe9ca98eb65dea404d0Lukas Slebodnik * rec->has2 are the same. (It is not very likely).
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorce cur = MC_SLOT_TO_PTR(mcc->data_table, slot, struct sss_mc_rec);
581de96fc30b7fe44070f17a8a73f3374d38d6ffLukas Slebodnik mcc->hash_table[hash] = sss_mc_next_slot_with_hash(rec, hash);
581de96fc30b7fe44070f17a8a73f3374d38d6ffLukas Slebodnik slot = sss_mc_next_slot_with_hash(cur, hash);
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorce cur = MC_SLOT_TO_PTR(mcc->data_table, slot, struct sss_mc_rec);
581de96fc30b7fe44070f17a8a73f3374d38d6ffLukas Slebodnik slot = sss_mc_next_slot_with_hash(cur, hash);
581de96fc30b7fe44070f17a8a73f3374d38d6ffLukas Slebodnik sss_mc_chain_slot_to_record_with_hash(prev, hash, slot);
581de96fc30b7fe44070f17a8a73f3374d38d6ffLukas Slebodnik slot = sss_mc_next_slot_with_hash(cur, hash);
da4c23b6670adb45f71cf51aaeca8df30c2144beSimo Sorcestatic void sss_mc_free_slots(struct sss_mc_ctx *mcc, struct sss_mc_rec *rec)
da4c23b6670adb45f71cf51aaeca8df30c2144beSimo Sorce for (i = 0; i < num; i++) {
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorcestatic void sss_mc_invalidate_rec(struct sss_mc_ctx *mcc,
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorce /* record already invalid */
da4c23b6670adb45f71cf51aaeca8df30c2144beSimo Sorce /* Remove from hash chains */
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorce /* hash chain 1 */
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorce /* hash chain 2 */
da4c23b6670adb45f71cf51aaeca8df30c2144beSimo Sorce /* Clear from free_table */
da4c23b6670adb45f71cf51aaeca8df30c2144beSimo Sorce /* Invalidate record fields */
6acf7c92ab38ad388295b2d57cc97c4598aa95ccSimo Sorce memset(rec->data, MC_INVALID_VAL8, ((MC_SLOT_SIZE * MC_SIZE_TO_SLOTS(rec->len))
6acf7c92ab38ad388295b2d57cc97c4598aa95ccSimo Sorce - sizeof(struct sss_mc_rec)));
6acf7c92ab38ad388295b2d57cc97c4598aa95ccSimo Sorcestatic bool sss_mc_is_valid_rec(struct sss_mc_ctx *mcc, struct sss_mc_rec *rec)
6acf7c92ab38ad388295b2d57cc97c4598aa95ccSimo Sorce ((uint8_t *)rec > (mcc->data_table + mcc->dt_size - MC_SLOT_SIZE))) {
6acf7c92ab38ad388295b2d57cc97c4598aa95ccSimo Sorce return false;
6acf7c92ab38ad388295b2d57cc97c4598aa95ccSimo Sorce return false;
6acf7c92ab38ad388295b2d57cc97c4598aa95ccSimo Sorce return false;
6acf7c92ab38ad388295b2d57cc97c4598aa95ccSimo Sorce return false;
581de96fc30b7fe44070f17a8a73f3374d38d6ffLukas Slebodnik /* next record can be invalid if there are no next records */
6acf7c92ab38ad388295b2d57cc97c4598aa95ccSimo Sorce return false;
6acf7c92ab38ad388295b2d57cc97c4598aa95ccSimo Sorce while (slot != MC_INVALID_VAL32 && self != rec) {
6acf7c92ab38ad388295b2d57cc97c4598aa95ccSimo Sorce self = MC_SLOT_TO_PTR(mcc->data_table, slot, struct sss_mc_rec);
581de96fc30b7fe44070f17a8a73f3374d38d6ffLukas Slebodnik slot = sss_mc_next_slot_with_hash(self, rec->hash1);
6acf7c92ab38ad388295b2d57cc97c4598aa95ccSimo Sorce return false;
6acf7c92ab38ad388295b2d57cc97c4598aa95ccSimo Sorce while (slot != MC_INVALID_VAL32 && self != rec) {
6acf7c92ab38ad388295b2d57cc97c4598aa95ccSimo Sorce self = MC_SLOT_TO_PTR(mcc->data_table, slot, struct sss_mc_rec);
581de96fc30b7fe44070f17a8a73f3374d38d6ffLukas Slebodnik slot = sss_mc_next_slot_with_hash(self, rec->hash2);
6acf7c92ab38ad388295b2d57cc97c4598aa95ccSimo Sorce return false;
6acf7c92ab38ad388295b2d57cc97c4598aa95ccSimo Sorce /* all tests passed */
6acf7c92ab38ad388295b2d57cc97c4598aa95ccSimo Sorce return true;
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorce/* FIXME: This is a very simplistic, inefficient, memory allocator,
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorce * it will just free the oldest entries regardless of expiration if it
677a31351c80453d9ce006481364399a96312052René Genz * cycled the whole free bits map and found no empty slot */
6acf7c92ab38ad388295b2d57cc97c4598aa95ccSimo Sorcestatic errno_t sss_mc_find_free_slots(struct sss_mc_ctx *mcc,
da4c23b6670adb45f71cf51aaeca8df30c2144beSimo Sorce /* Try to find a free slot w/o removing anything first */
677a31351c80453d9ce006481364399a96312052René Genz /* FIXME: Is it really worth it? Maybe it is easier to
677a31351c80453d9ce006481364399a96312052René Genz * just recycle the next set of slots? */
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorce /* search for enough (num_slots) consecutive zero bits, indicating
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorce * consecutive empty slots */
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorce /* if all full in this byte skip directly to the next */
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorce /* at least one bit in this byte is marked as empty */
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorce if (!used) break;
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorce /* check if we have enough slots before hitting the table end */
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorce /* check if we have at least num_slots empty starting from the first
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorce * we found in the previous steps */
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorce /* ok found num_slots consecutive free bits */
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorce /* no free slots found, free occupied slots after next_slot */
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorce for (i = 0; i < num_slots; i++) {
6acf7c92ab38ad388295b2d57cc97c4598aa95ccSimo Sorce /* the first used slot should be a record header, however we
6acf7c92ab38ad388295b2d57cc97c4598aa95ccSimo Sorce * carefully check it is a valid header and hardfail if not */
da4c23b6670adb45f71cf51aaeca8df30c2144beSimo Sorce rec = MC_SLOT_TO_PTR(mcc->data_table, cur + i, struct sss_mc_rec);
677a31351c80453d9ce006481364399a96312052René Genz /* this is a fatal error, the caller should probably just
6acf7c92ab38ad388295b2d57cc97c4598aa95ccSimo Sorce * invalidate the whole cache */
6acf7c92ab38ad388295b2d57cc97c4598aa95ccSimo Sorce /* next loop skip the whole record */
6acf7c92ab38ad388295b2d57cc97c4598aa95ccSimo Sorce /* finally invalidate record completely */
441e6050f4b67134d15862e401b4c4e8546d7387Michal Zidekstatic errno_t sss_mc_get_strs_offset(struct sss_mc_ctx *mcc,
441e6050f4b67134d15862e401b4c4e8546d7387Michal Zidek *_offset = offsetof(struct sss_mc_pwd_data, strs);
441e6050f4b67134d15862e401b4c4e8546d7387Michal Zidek *_offset = offsetof(struct sss_mc_grp_data, strs);
225dc6914cdc8920b02a129b98ece1ed97b99c03Lukas Slebodnik *_offset = offsetof(struct sss_mc_initgr_data, gids);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov DEBUG(SSSDBG_FATAL_FAILURE, "Unknown memory cache type.\n");
441e6050f4b67134d15862e401b4c4e8546d7387Michal Zidekstatic errno_t sss_mc_get_strs_len(struct sss_mc_ctx *mcc,
441e6050f4b67134d15862e401b4c4e8546d7387Michal Zidek *_len = ((struct sss_mc_pwd_data *)&rec->data)->strs_len;
441e6050f4b67134d15862e401b4c4e8546d7387Michal Zidek *_len = ((struct sss_mc_grp_data *)&rec->data)->strs_len;
225dc6914cdc8920b02a129b98ece1ed97b99c03Lukas Slebodnik *_len = ((struct sss_mc_initgr_data *)&rec->data)->data_len;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov DEBUG(SSSDBG_FATAL_FAILURE, "Unknown memory cache type.\n");
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorcestatic struct sss_mc_rec *sss_mc_find_record(struct sss_mc_ctx *mcc,
13df7b9e400211c717284fb841c849ba034ed348Michal Zidek if (!MC_SLOT_WITHIN_BOUNDS(slot, mcc->dt_size)) {
441e6050f4b67134d15862e401b4c4e8546d7387Michal Zidek /* Get max address of data table. */
441e6050f4b67134d15862e401b4c4e8546d7387Michal Zidek ret = sss_mc_get_strs_offset(mcc, &strs_offset);
13df7b9e400211c717284fb841c849ba034ed348Michal Zidek if (!MC_SLOT_WITHIN_BOUNDS(slot, mcc->dt_size)) {
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov "Corrupted fastcache. Slot number too big.\n");
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorce rec = MC_SLOT_TO_PTR(mcc->data_table, slot, struct sss_mc_rec);
441e6050f4b67134d15862e401b4c4e8546d7387Michal Zidek ret = sss_mc_get_strs_len(mcc, rec, &strs_len);
4382047490dd4f80b407cc1e618da048f13e5f8fSumit Bose /* The string cannot be in current record */
d8057ec487e452038f0106042021fa612bbb8555Michal Zidek safealign_memcpy(&name_ptr, rec->data, sizeof(rel_ptr_t), NULL);
4382047490dd4f80b407cc1e618da048f13e5f8fSumit Bose /* name_ptr must point to some data in the strs/gids area of the data
677a31351c80453d9ce006481364399a96312052René Genz * payload. Since it is a pointer relative to rec->data it must be
677a31351c80453d9ce006481364399a96312052René Genz * larger/equal to strs_offset and must be smaller then strs_offset + strs_len.
4382047490dd4f80b407cc1e618da048f13e5f8fSumit Bose * Additionally the area must not end outside of the data table and
677a31351c80453d9ce006481364399a96312052René Genz * t_key must be a zero-terminated string. */
4382047490dd4f80b407cc1e618da048f13e5f8fSumit Bose || strs_len > max_addr - (uint8_t *)rec->data - strs_offset) {
4382047490dd4f80b407cc1e618da048f13e5f8fSumit Bose "Corrupted fastcache entry at slot %u. "
581de96fc30b7fe44070f17a8a73f3374d38d6ffLukas Slebodnik slot = sss_mc_next_slot_with_hash(rec, hash);
0e6c9d03cacf24de4265ee0f902c216ba5a131c9Simo Sorcestatic errno_t sss_mc_get_record(struct sss_mc_ctx **_mcc,
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorce /* slot size changed, invalidate record and fall through to get a
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorce * fully new record */
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorce /* we are going to use more space, find enough free slots */
6acf7c92ab38ad388295b2d57cc97c4598aa95ccSimo Sorce ret = sss_mc_find_free_slots(mcc, num_slots, &base_slot);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov "Fatal internal mmap cache error, invalidating cache!\n");
0e6c9d03cacf24de4265ee0f902c216ba5a131c9Simo Sorce (void)sss_mmap_cache_reinit(talloc_parent(mcc), -1, -1, _mcc);
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorce rec = MC_SLOT_TO_PTR(mcc->data_table, base_slot, struct sss_mc_rec);
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorce /* mark as not valid yet */
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorce /* and now mark slots as used */
24451a6231ea0b7fd0e98a9931e8254aa17bf4cfSimo Sorce for (i = 0; i < num_slots; i++) {
b294d4c50ec4431bc07ad7ec5a73e8af0e53c54fSimo Sorcestatic inline void sss_mmap_set_rec_header(struct sss_mc_ctx *mcc,
b294d4c50ec4431bc07ad7ec5a73e8af0e53c54fSimo Sorcestatic inline void sss_mmap_chain_in_rec(struct sss_mc_ctx *mcc,
b294d4c50ec4431bc07ad7ec5a73e8af0e53c54fSimo Sorce /* name first */
8088274b2389b76f4be581736e55f26a8322fad1Simo Sorce/***************************************************************************
8088274b2389b76f4be581736e55f26a8322fad1Simo Sorce * generic invalidation
8088274b2389b76f4be581736e55f26a8322fad1Simo Sorce ***************************************************************************/
8088274b2389b76f4be581736e55f26a8322fad1Simo Sorcestatic errno_t sss_mmap_cache_invalidate(struct sss_mc_ctx *mcc,
677a31351c80453d9ce006481364399a96312052René Genz /* cache not initialized? */
8088274b2389b76f4be581736e55f26a8322fad1Simo Sorce /* nothing to invalidate */
6cb1a6e7c7517ab4ccb8ad37ade86f95b5c16a01Simo Sorce/***************************************************************************
6cb1a6e7c7517ab4ccb8ad37ade86f95b5c16a01Simo Sorce * passwd map
6cb1a6e7c7517ab4ccb8ad37ade86f95b5c16a01Simo Sorce ***************************************************************************/
0e6c9d03cacf24de4265ee0f902c216ba5a131c9Simo Sorceerrno_t sss_mmap_cache_pw_store(struct sss_mc_ctx **_mcc,
677a31351c80453d9ce006481364399a96312052René Genz /* cache not initialized? */
6cb1a6e7c7517ab4ccb8ad37ade86f95b5c16a01Simo Sorce data_len = name->len + pw->len + gecos->len + homedir->len + shell->len;
6cb1a6e7c7517ab4ccb8ad37ade86f95b5c16a01Simo Sorce sizeof(struct sss_mc_pwd_data) +
0e6c9d03cacf24de4265ee0f902c216ba5a131c9Simo Sorce ret = sss_mc_get_record(_mcc, rec_len, name, &rec);
6cb1a6e7c7517ab4ccb8ad37ade86f95b5c16a01Simo Sorce /* header */
b294d4c50ec4431bc07ad7ec5a73e8af0e53c54fSimo Sorce sss_mmap_set_rec_header(mcc, rec, rec_len, mcc->valid_time_slot,
6cb1a6e7c7517ab4ccb8ad37ade86f95b5c16a01Simo Sorce /* passwd struct */
6cb1a6e7c7517ab4ccb8ad37ade86f95b5c16a01Simo Sorce memcpy(&data->strs[pos], gecos->str, gecos->len);
6cb1a6e7c7517ab4ccb8ad37ade86f95b5c16a01Simo Sorce memcpy(&data->strs[pos], homedir->str, homedir->len);
6cb1a6e7c7517ab4ccb8ad37ade86f95b5c16a01Simo Sorce memcpy(&data->strs[pos], shell->str, shell->len);
6cb1a6e7c7517ab4ccb8ad37ade86f95b5c16a01Simo Sorce /* finally chain the rec in the hash table */
8088274b2389b76f4be581736e55f26a8322fad1Simo Sorceerrno_t sss_mmap_cache_pw_invalidate(struct sss_mc_ctx *mcc,
8088274b2389b76f4be581736e55f26a8322fad1Simo Sorceerrno_t sss_mmap_cache_pw_invalidate_uid(struct sss_mc_ctx *mcc, uid_t uid)
677a31351c80453d9ce006481364399a96312052René Genz /* cache not initialized? */
8088274b2389b76f4be581736e55f26a8322fad1Simo Sorce uidstr = talloc_asprintf(NULL, "%ld", (long)uid);
8088274b2389b76f4be581736e55f26a8322fad1Simo Sorce hash = sss_mc_hash(mcc, uidstr, strlen(uidstr) + 1);
13df7b9e400211c717284fb841c849ba034ed348Michal Zidek if (!MC_SLOT_WITHIN_BOUNDS(slot, mcc->dt_size)) {
13df7b9e400211c717284fb841c849ba034ed348Michal Zidek if (!MC_SLOT_WITHIN_BOUNDS(slot, mcc->dt_size)) {
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov DEBUG(SSSDBG_FATAL_FAILURE, "Corrupted fastcache.\n");
8088274b2389b76f4be581736e55f26a8322fad1Simo Sorce rec = MC_SLOT_TO_PTR(mcc->data_table, slot, struct sss_mc_rec);
581de96fc30b7fe44070f17a8a73f3374d38d6ffLukas Slebodnik slot = sss_mc_next_slot_with_hash(rec, hash);
c3ef027218fe9a7d16a70ca9d2f53e3d995e369fSimo Sorce/***************************************************************************
c3ef027218fe9a7d16a70ca9d2f53e3d995e369fSimo Sorce ***************************************************************************/
0e6c9d03cacf24de4265ee0f902c216ba5a131c9Simo Sorceint sss_mmap_cache_gr_store(struct sss_mc_ctx **_mcc,
677a31351c80453d9ce006481364399a96312052René Genz /* cache not initialized? */
c3ef027218fe9a7d16a70ca9d2f53e3d995e369fSimo Sorce sizeof(struct sss_mc_grp_data) +
0e6c9d03cacf24de4265ee0f902c216ba5a131c9Simo Sorce ret = sss_mc_get_record(_mcc, rec_len, name, &rec);
c3ef027218fe9a7d16a70ca9d2f53e3d995e369fSimo Sorce /* header */
b294d4c50ec4431bc07ad7ec5a73e8af0e53c54fSimo Sorce sss_mmap_set_rec_header(mcc, rec, rec_len, mcc->valid_time_slot,
c3ef027218fe9a7d16a70ca9d2f53e3d995e369fSimo Sorce /* group struct */
c3ef027218fe9a7d16a70ca9d2f53e3d995e369fSimo Sorce /* finally chain the rec in the hash table */
8088274b2389b76f4be581736e55f26a8322fad1Simo Sorceerrno_t sss_mmap_cache_gr_invalidate(struct sss_mc_ctx *mcc,
8088274b2389b76f4be581736e55f26a8322fad1Simo Sorceerrno_t sss_mmap_cache_gr_invalidate_gid(struct sss_mc_ctx *mcc, gid_t gid)
677a31351c80453d9ce006481364399a96312052René Genz /* cache not initialized? */
8088274b2389b76f4be581736e55f26a8322fad1Simo Sorce gidstr = talloc_asprintf(NULL, "%ld", (long)gid);
8088274b2389b76f4be581736e55f26a8322fad1Simo Sorce hash = sss_mc_hash(mcc, gidstr, strlen(gidstr) + 1);
13df7b9e400211c717284fb841c849ba034ed348Michal Zidek if (!MC_SLOT_WITHIN_BOUNDS(slot, mcc->dt_size)) {
13df7b9e400211c717284fb841c849ba034ed348Michal Zidek if (!MC_SLOT_WITHIN_BOUNDS(slot, mcc->dt_size)) {
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov DEBUG(SSSDBG_FATAL_FAILURE, "Corrupted fastcache.\n");
8088274b2389b76f4be581736e55f26a8322fad1Simo Sorce rec = MC_SLOT_TO_PTR(mcc->data_table, slot, struct sss_mc_rec);
581de96fc30b7fe44070f17a8a73f3374d38d6ffLukas Slebodnik slot = sss_mc_next_slot_with_hash(rec, hash);
ebf6735dd4f71bf3dc9105e5d04d11e744c64a59Lukas Slebodnikerrno_t sss_mmap_cache_initgr_store(struct sss_mc_ctx **_mcc,
677a31351c80453d9ce006481364399a96312052René Genz /* cache not initialized? */
dda0258705de7255e6ec54b7f9adbde83a220996Lukas Slebodnik /* array of gids + name + unique_name */
dda0258705de7255e6ec54b7f9adbde83a220996Lukas Slebodnik data_len = num_groups * sizeof(uint32_t) + name->len + unique_name->len;
ebf6735dd4f71bf3dc9105e5d04d11e744c64a59Lukas Slebodnik rec_len = sizeof(struct sss_mc_rec) + sizeof(struct sss_mc_initgr_data)
dda0258705de7255e6ec54b7f9adbde83a220996Lukas Slebodnik /* use unique name for searching potential old records */
dda0258705de7255e6ec54b7f9adbde83a220996Lukas Slebodnik ret = sss_mc_get_record(_mcc, rec_len, unique_name, &rec);
ebf6735dd4f71bf3dc9105e5d04d11e744c64a59Lukas Slebodnik data = (struct sss_mc_initgr_data *)rec->data;
677a31351c80453d9ce006481364399a96312052René Genz /* We cannot use two keys for searching in initgroups cache.
ebf6735dd4f71bf3dc9105e5d04d11e744c64a59Lukas Slebodnik * Use the first key twice.
ebf6735dd4f71bf3dc9105e5d04d11e744c64a59Lukas Slebodnik sss_mmap_set_rec_header(mcc, rec, rec_len, mcc->valid_time_slot,
ebf6735dd4f71bf3dc9105e5d04d11e744c64a59Lukas Slebodnik /* initgroups struct */
dda0258705de7255e6ec54b7f9adbde83a220996Lukas Slebodnik data->strs_len = name->len + unique_name->len;
dda0258705de7255e6ec54b7f9adbde83a220996Lukas Slebodnik memcpy((char *)data->gids + pos, gids_buf, num_groups * sizeof(uint32_t));
dda0258705de7255e6ec54b7f9adbde83a220996Lukas Slebodnik memcpy((char *)data->gids + pos, unique_name->str, unique_name->len);
dda0258705de7255e6ec54b7f9adbde83a220996Lukas Slebodnik data->strs = data->unique_name = MC_PTR_DIFF((char *)data->gids + pos, data);
dda0258705de7255e6ec54b7f9adbde83a220996Lukas Slebodnik memcpy((char *)data->gids + pos, name->str, name->len);
dda0258705de7255e6ec54b7f9adbde83a220996Lukas Slebodnik data->name = MC_PTR_DIFF((char *)data->gids + pos, data);
ebf6735dd4f71bf3dc9105e5d04d11e744c64a59Lukas Slebodnik /* finally chain the rec in the hash table */
ebf6735dd4f71bf3dc9105e5d04d11e744c64a59Lukas Slebodnikerrno_t sss_mmap_cache_initgr_invalidate(struct sss_mc_ctx *mcc,
ebf6735dd4f71bf3dc9105e5d04d11e744c64a59Lukas Slebodnik return sss_mmap_cache_invalidate(mcc, name);
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce/***************************************************************************
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce * initialization
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce ***************************************************************************/
714ba5f50551a42df324714358dc379b351d4a53Michal Zidek/* Copy of sss_mc_set_recycled is present in the src/tools/tools_mc_util.c.
714ba5f50551a42df324714358dc379b351d4a53Michal Zidek * If you modify this function, you should modify the duplicated function
677a31351c80453d9ce006481364399a96312052René Genz /* What do we do now? */
8e44ddfccebe61728d8a2c1dafce36dfa944bc90Jakub Hrozek written = sss_atomic_write_s(fd, (uint8_t *)&w, sizeof(h.status));
9d7d4458d94d0aac0a7edf999368eb18f89cb76aJakub Hrozek /* Write error */
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce * When we (re)create a new file we must mark the current file as recycled
677a31351c80453d9ce006481364399a96312052René Genz * so active clients will abandon its use ASAP.
677a31351c80453d9ce006481364399a96312052René Genz * We unlink the current file and make a new one.
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorcestatic errno_t sss_mc_create_file(struct sss_mc_ctx *mc_ctx)
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov "Failed to lock file %s.\n", mc_ctx->file);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov DEBUG(SSSDBG_FATAL_FAILURE, "Failed to mark mmap file %s as"
33cbb789ff71be5dccbb4a0acd68814b0d53da34Michal Zidek " recycled: %d(%s)\n",
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov "Failed to open old memory cache file %s: %d(%s).\n",
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov DEBUG(SSSDBG_TRACE_FUNC, "Failed to rm mmap file %s: %d(%s)\n",
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce /* temporarily relax umask as we need the file to be readable
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce * by everyone for now */
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce mc_ctx->fd = open(mc_ctx->file, O_CREAT | O_EXCL | O_RDWR, 0644);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "Failed to open mmap file %s: %d(%s)\n",
33cbb789ff71be5dccbb4a0acd68814b0d53da34Michal Zidek ret = sss_br_lock_file(mc_ctx->fd, 0, 1, retries, t);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov "Failed to lock file %s.\n", mc_ctx->file);
8b7040df8bcfee8cb31903136562eea73232f3d0Jakub Hrozek /* Report on unlink failures but don't overwrite the errno
8b7040df8bcfee8cb31903136562eea73232f3d0Jakub Hrozek * from sss_br_lock_file
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov DEBUG(SSSDBG_TRACE_FUNC, "Failed to rm mmap file %s: %d(%s)\n",
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorcestatic void sss_mc_header_update(struct sss_mc_ctx *mc_ctx, int status)
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce /* update header using barriers */
9028706a00da1bc48547e74aa872c825ac15adb2Michal Zidek /* no reason to update anything else if the file is recycled or
9028706a00da1bc48547e74aa872c825ac15adb2Michal Zidek * right before reset */
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce h->hash_table = MC_PTR_DIFF(mc_ctx->hash_table, mc_ctx->mmap_base);
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce h->free_table = MC_PTR_DIFF(mc_ctx->free_table, mc_ctx->mmap_base);
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce h->data_table = MC_PTR_DIFF(mc_ctx->data_table, mc_ctx->mmap_base);
20c2bd06b530866a3c9670e6d0da266e7279db5eMichal Zidekstatic int mc_ctx_destructor(struct sss_mc_ctx *mc_ctx)
20c2bd06b530866a3c9670e6d0da266e7279db5eMichal Zidek /* Print debug message to logs if munmap() or close()
20c2bd06b530866a3c9670e6d0da266e7279db5eMichal Zidek * fail but always return 0 */
20c2bd06b530866a3c9670e6d0da266e7279db5eMichal Zidek ret = munmap(mc_ctx->mmap_base, mc_ctx->mmap_size);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov "Failed to unmap old memory cache file."
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov "Failed to close old memory cache file."
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorceerrno_t sss_mmap_cache_init(TALLOC_CTX *mem_ctx, const char *name,
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce mc_ctx = talloc_zero(mem_ctx, struct sss_mc_ctx);
20c2bd06b530866a3c9670e6d0da266e7279db5eMichal Zidek talloc_set_destructor(mc_ctx, mc_ctx_destructor);
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce /* elements must always be multiple of 8 to make things easier to handle,
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce * so we increase by the necessary amount if they are not a multiple */
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce /* We can use MC_ALIGN64 for this */
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce /* hash table is double the size because it will store both forward and
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce * reverse keys (name/uid, name/gid, ..) */
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce /* for now ALWAYS create a new file on restart */
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "Failed to resize file %s: %d(%s)\n",
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce mc_ctx->mmap_base = mmap(NULL, mc_ctx->mmap_size,
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "Failed to mmap file %s(%zu): %d(%s)\n",
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce mc_ctx->data_table = MC_PTR_ADD(mc_ctx->mmap_base, MC_HEADER_SIZE);
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce mc_ctx->free_table = MC_PTR_ADD(mc_ctx->data_table,
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce mc_ctx->hash_table = MC_PTR_ADD(mc_ctx->free_table,
6acf7c92ab38ad388295b2d57cc97c4598aa95ccSimo Sorce memset(mc_ctx->data_table, 0xff, mc_ctx->dt_size);
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce memset(mc_ctx->free_table, 0x00, mc_ctx->ft_size);
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce memset(mc_ctx->hash_table, 0xff, mc_ctx->ht_size);
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce /* generate a pseudo-random seed.
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce * Needed to fend off dictionary based collision attacks */
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce sss_mc_header_update(mc_ctx, SSS_MC_HEADER_ALIVE);
677a31351c80453d9ce006481364399a96312052René Genz /* Closing the file descriptor and unmapping the file
20c2bd06b530866a3c9670e6d0da266e7279db5eMichal Zidek * from memory is done in the mc_ctx_destructor. */
20c2bd06b530866a3c9670e6d0da266e7279db5eMichal Zidek if (mc_ctx && mc_ctx->file && mc_ctx->fd != -1) {
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov "Failed to rm mmap file %s: %d(%s)\n", mc_ctx->file,
99c99e557020775714f028b28a147edda290c783Michal Zidekerrno_t sss_mmap_cache_reinit(TALLOC_CTX *mem_ctx, size_t n_elem,
42604cc8d11743febf5aa892cb3a7d3c32bfed48Lukas Slebodnik "Unable to re-init uninitialized memory cache.\n");
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory.\n");
99c99e557020775714f028b28a147edda290c783Michal Zidek name = talloc_strdup(tmp_ctx, (*mc_ctx)->name);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory.\n");
0e6c9d03cacf24de4265ee0f902c216ba5a131c9Simo Sorce /* make sure we do not leave a potentially freed pointer around */
99c99e557020775714f028b28a147edda290c783Michal Zidek ret = sss_mmap_cache_init(mem_ctx, name, type, n_elem, timeout, mc_ctx);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "Failed to re-initialize mmap cache.\n");
9028706a00da1bc48547e74aa872c825ac15adb2Michal Zidek/* Erase all contents of the mmap cache. This will bring the cache
9028706a00da1bc48547e74aa872c825ac15adb2Michal Zidek * to the same state as if it was just initialized. */
9028706a00da1bc48547e74aa872c825ac15adb2Michal Zidekvoid sss_mmap_cache_reset(struct sss_mc_ctx *mc_ctx)
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov "Fastcache not initialized. Nothing to do.\n");
9028706a00da1bc48547e74aa872c825ac15adb2Michal Zidek sss_mc_header_update(mc_ctx, SSS_MC_HEADER_UNINIT);
677a31351c80453d9ce006481364399a96312052René Genz /* Reset the mmapped area */
9028706a00da1bc48547e74aa872c825ac15adb2Michal Zidek memset(mc_ctx->data_table, 0xff, mc_ctx->dt_size);
9028706a00da1bc48547e74aa872c825ac15adb2Michal Zidek memset(mc_ctx->free_table, 0x00, mc_ctx->ft_size);
9028706a00da1bc48547e74aa872c825ac15adb2Michal Zidek memset(mc_ctx->hash_table, 0xff, mc_ctx->ht_size);