nsssrv_mmap_cache.c revision 270fcd0ad214d490b6b8e278cdbafda1fb7f9d8f
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose NSS Responder - Mmap Cache
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose Copyright (C) Simo Sorce <ssorce@redhat.com> 2011
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose This program is free software; you can redistribute it and/or modify
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose it under the terms of the GNU General Public License as published by
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose the Free Software Foundation; either version 3 of the License, or
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose (at your option) any later version.
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose This program is distributed in the hope that it will be useful,
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose but WITHOUT ANY WARRANTY; without even the implied warranty of
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose GNU General Public License for more details.
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose You should have received a copy of the GNU General Public License
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose along with this program. If not, see <http://www.gnu.org/licenses/>.
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose/* arbitrary (avg of my /etc/passwd) */
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose/* short group name and no gids (private user group */
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose#define MC_NEXT_BARRIER(val) ((((val) + 1) & 0x00ffffff) | 0xf0000000)
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose#define MC_RAISE_BARRIER(m) do { \
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose#define MC_LOWER_BARRIER(m) do { \
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose uint32_t seed; /* pseudo-random seed to avoid collision attacks */
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose time_t valid_time_slot; /* maximum time the entry is valid in seconds */
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose uint32_t *hash_table; /* hash table address (in mmap) */
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose uint32_t next_slot; /* the next slot after last allocation */
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose uint8_t *data_table; /* data table address (in mmap) */
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose if (*b & c) used = true; \
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose else used = false; \
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bosestatic uint32_t sss_mc_hash(struct sss_mc_ctx *mcc,
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose return murmurhash3(key, len, mcc->seed) % MC_HT_ELEMS(mcc->ht_size);
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bosestatic void sss_mc_add_rec_to_chain(struct sss_mc_ctx *mcc,
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose /* no previous record/collision, just add to hash table */
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose mcc->hash_table[hash] = MC_PTR_TO_SLOT(mcc->data_table, rec);
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose cur = MC_SLOT_TO_PTR(mcc->data_table, slot, struct sss_mc_rec);
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose /* rec already stored in hash chain */
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose /* end of chain, append our record here */
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose /* changing a single uint32_t is atomic, so there is no
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose * need to use barriers in this case */
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose cur->next = MC_PTR_TO_SLOT(mcc->data_table, rec);
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bosestatic void sss_mc_rm_rec_from_chain(struct sss_mc_ctx *mcc,
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose cur = MC_SLOT_TO_PTR(mcc->data_table, slot, struct sss_mc_rec);
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose cur = MC_SLOT_TO_PTR(mcc->data_table, slot, struct sss_mc_rec);
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose /* changing a single uint32_t is atomic, so there is no
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose * need to use barriers in this case */
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bosestatic void sss_mc_invalidate_rec(struct sss_mc_ctx *mcc,
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose /* record already invalid */
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose /* hash chain 1 */
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose /* hash chain 2 */
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose memset(rec->data, 'X', rec->len - sizeof(struct sss_mc_rec));
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose/* FIXME: This is a very simplistic, inefficient, memory allocator,
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose * it will just free the oldest entries regardless of expiration if it
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose * cycled the whole freebits map and found no empty slot */
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bosestatic int sss_mc_find_free_slots(struct sss_mc_ctx *mcc, int num_slots)
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose /* Try to find a free slot w/o removing a nything first */
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose /* FIXME: is it really worth it ? May be it is easier to
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose * just recycle the next set of slots ? */
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose /* search for enough (num_slots) consecutive zero bits, indicating
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose * consecutive empty slots */
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose /* if all full in this byte skip directly to the next */
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose /* at least one bit in this byte is marked as empty */
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose if (!used) break;
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose /* check if we have enough slots before hitting the table end */
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose /* check if we have at least num_slots empty starting from the first
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose * we found in the previous steps */
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose /* ok found num_slots consecutive free bits */
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose /* no free slots found, free occupied slots after next_slot */
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose for (i = 0; i < num_slots; i++) {
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose if (!used) continue;
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose rec = MC_SLOT_TO_PTR(mcc->data_table, cur + i, struct sss_mc_rec);
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose for (t = i + MC_SIZE_TO_SLOTS(rec->len); i < t; i++) {
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bosestatic struct sss_mc_rec *sss_mc_find_record(struct sss_mc_ctx *mcc,
167b05b28d6b969230973646bee2f1c1f49205d2Sumit Bose rec = MC_SLOT_TO_PTR(mcc->data_table, slot, struct sss_mc_rec);
int old_slots;
int num_slots;
if (old_rec) {
return old_rec;
for (i = 0; i < old_slots; i++) {
for (i = 0; i < num_slots; i++) {
return rec;
return EINVAL;
return ENOENT;
return EOK;
int ret;
return EINVAL;
return EINVAL;
sizeof(struct sss_mc_pwd_data) +
return ENOMEM;
pos = 0;
return EOK;
char *uidstr;
return EINVAL;
if (!uidstr) {
return ENOMEM;
goto done;
goto done;
done:
return ret;
int ret;
return EINVAL;
return EINVAL;
sizeof(struct sss_mc_grp_data) +
return ENOMEM;
pos = 0;
return EOK;
char *gidstr;
return EINVAL;
if (!gidstr) {
return ENOMEM;
goto done;
goto done;
done:
return ret;
struct sss_mc_header h;
int ret;
return errno;
errno = 0;
return errno;
return EIO;
return EOK;
int ofd;
if (ret) {
errno = 0;
errno = 0;
return ret;
errno = 0;
return ret;
return ret;
struct sss_mc_header *h;
MC_RAISE_BARRIER(h);
h->reserved = 0;
MC_LOWER_BARRIER(h);
unsigned int rseed;
int payload;
int ret;
switch (type) {
case SSS_MC_PASSWD:
case SSS_MC_GROUP:
return EINVAL;
if (!mc_ctx) {
return ENOMEM;
goto done;
goto done;
if (ret) {
goto done;
goto done;
goto done;
done:
if (ret) {
return ret;
char *name;
return EINVAL;
return ENOMEM;
goto done;
if (ret != 0) {
goto done;
done:
return ret;