/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright 2020 Nexenta by DDN, Inc. All rights reserved. */ /* * Windows to Solaris Identity Mapping * This module provides the libidmap idmap_cache. */ #include #include #include #include #include #include #include #include #include #include "idmap_cache.h" /* * Internal definitions and functions */ #define CACHE_UID_TRIGGER_SIZE 4096 #define CACHE_GID_TRIGGER_SIZE 2048 #define CACHE_UID_GID_TRIGGER_SIZE \ (CACHE_UID_TRIGGER_SIZE + CACHE_GID_TRIGGER_SIZE) #define UNDEF_UID ((uid_t)-1) #define UNDEF_GID ((gid_t)-1) #define UNDEF_ISUSER (-1) #define CACHE_PURGE_INTERVAL (60 * 3) #define CACHE_TTL (60 * 10) #define list_insert(head, ele)\ do {\ (ele)->flink = (head)->flink;\ (head)->flink = (ele);\ (ele)->blink = (ele)->flink->blink;\ (ele)->flink->blink = (ele);\ } while (0) #define list_remove(ele)\ do {\ (ele)->flink->blink = (ele)->blink;\ (ele)->blink->flink = (ele)->flink;\ } while (0) #define list_move(head, ele) \ do {\ if ((head)->flink != (ele)) {\ list_remove(ele);\ list_insert(head, ele);\ }\ } while (0) typedef struct sid2uid_gid { avl_node_t avl_link; struct sid2uid_gid *flink; struct sid2uid_gid *blink; const char *sid_prefix; idmap_rid_t rid; uid_t uid; time_t uid_ttl; gid_t gid; time_t gid_ttl; int is_user; } sid2uid_gid_t; typedef struct pid2sid_winname { avl_node_t avl_link; struct pid2sid_winname *flink; struct pid2sid_winname *blink; uid_t pid; const char *sid_prefix; idmap_rid_t rid; time_t sid_ttl; const char *winname; const char *windomain; time_t winname_ttl; } pid2sid_winname_t; typedef struct winname2uid_gid { avl_node_t avl_link; struct winname2uid_gid *flink; struct winname2uid_gid *blink; const char *winname; const char *windomain; uid_t uid; time_t uid_ttl; gid_t gid; time_t gid_ttl; } winname2uid_gid_t; typedef struct sid2uid_gid_cache { avl_tree_t tree; pthread_mutex_t mutex; sid2uid_gid_t head; sid2uid_gid_t *prev; time_t purge_time; int uid_num; int gid_num; int pid_num; } sid2uid_gid_cache_t; typedef struct pid2sid_winname_cache { avl_tree_t tree; pthread_mutex_t mutex; pid2sid_winname_t head; pid2sid_winname_t *prev; time_t purge_time; int sid_num; int winname_num; } pid2sid_winname_cache_t; typedef struct winname2uid_gid_cache { avl_tree_t tree; pthread_mutex_t mutex; winname2uid_gid_t head; winname2uid_gid_t *prev; time_t purge_time; int uid_num; int gid_num; } winname2uid_gid_cache_t; typedef struct idmap_cache { sid2uid_gid_cache_t sid2uid_gid; pid2sid_winname_cache_t uid2sid_winname; pid2sid_winname_cache_t gid2sid_winname; winname2uid_gid_cache_t winname2uid_gid; } idmap_cache_t; typedef int (*avl_comp_fn)(const void*, const void*); static void idmap_purge_sid2uid_gid_cache(sid2uid_gid_cache_t *cache, size_t limit); static void idmap_purge_pid2sid_winname_cache(pid2sid_winname_cache_t *cache, size_t limit); static void idmap_purge_winname2uid_gid_cache(winname2uid_gid_cache_t *avl, size_t limit); /* * Global structures */ static idmap_cache_t idmap_cache; static int idmap_compare_sid(const sid2uid_gid_t *entry1, const sid2uid_gid_t *entry2) { int64_t comp = ((int64_t)entry2->rid) - ((int64_t)entry1->rid); if (comp == 0) comp = strcmp(entry2->sid_prefix, entry1->sid_prefix); if (comp < 0) comp = -1; else if (comp > 0) comp = 1; return ((int)comp); } static int idmap_compare_pid(const pid2sid_winname_t *entry1, const pid2sid_winname_t *entry2) { if (entry2->pid > entry1->pid) return (1); if (entry2->pid < entry1->pid) return (-1); return (0); } static int idmap_compare_winname(const winname2uid_gid_t *entry1, const winname2uid_gid_t *entry2) { int comp; comp = strcasecmp(entry2->winname, entry1->winname); if (comp == 0) { if (entry2->windomain == NULL && entry1->windomain == NULL) return (0); if (entry1->windomain == NULL) return (1); if (entry2->windomain == NULL) return (-1); comp = strcasecmp(entry2->windomain, entry1->windomain); } if (comp < 0) comp = -1; else if (comp > 0) comp = 1; return (comp); } /* * Routine to update item * * Returns: 0 Success * -1 Error */ static int update_str(const char **item, const char *str) { char *tmp; if (*item != NULL && str != NULL) { if (strcmp(*item, str) != 0) { if ((tmp = strdup(str)) == NULL) return (-1); free((char *)*item); *item = tmp; } } else if (str != NULL) { /* *item is NULL */ if ((*item = strdup(str)) == NULL) return (-1); } else if (*item != NULL) { /* str is NULL */ free((char *)*item); *item = NULL; } return (0); } /* * The Cache is initialized on loading libidmap.so */ #pragma init(idmap_cache_create) void idmap_cache_create(void) { avl_create(&idmap_cache.sid2uid_gid.tree, (avl_comp_fn)idmap_compare_sid, sizeof (sid2uid_gid_t), offsetof(sid2uid_gid_t, avl_link)); (void) pthread_mutex_init(&idmap_cache.sid2uid_gid.mutex, NULL); idmap_cache.sid2uid_gid.head.flink = &idmap_cache.sid2uid_gid.head; idmap_cache.sid2uid_gid.head.blink = &idmap_cache.sid2uid_gid.head; idmap_cache.sid2uid_gid.prev = NULL; idmap_cache.sid2uid_gid.purge_time = 0; idmap_cache.sid2uid_gid.uid_num = 0; idmap_cache.sid2uid_gid.gid_num = 0; idmap_cache.sid2uid_gid.pid_num = 0; avl_create(&idmap_cache.uid2sid_winname.tree, (avl_comp_fn)idmap_compare_pid, sizeof (pid2sid_winname_t), offsetof(pid2sid_winname_t, avl_link)); (void) pthread_mutex_init(&idmap_cache.uid2sid_winname.mutex, NULL); idmap_cache.uid2sid_winname.head.flink = &idmap_cache.uid2sid_winname.head; idmap_cache.uid2sid_winname.head.blink = &idmap_cache.uid2sid_winname.head; idmap_cache.uid2sid_winname.prev = NULL; idmap_cache.uid2sid_winname.purge_time = 0; idmap_cache.uid2sid_winname.sid_num = 0; idmap_cache.uid2sid_winname.winname_num = 0; avl_create(&idmap_cache.gid2sid_winname.tree, (avl_comp_fn)idmap_compare_pid, sizeof (pid2sid_winname_t), offsetof(pid2sid_winname_t, avl_link)); (void) pthread_mutex_init(&idmap_cache.gid2sid_winname.mutex, NULL); idmap_cache.gid2sid_winname.head.flink = &idmap_cache.gid2sid_winname.head; idmap_cache.gid2sid_winname.head.blink = &idmap_cache.gid2sid_winname.head; idmap_cache.gid2sid_winname.prev = NULL; idmap_cache.gid2sid_winname.purge_time = 0; idmap_cache.gid2sid_winname.sid_num = 0; idmap_cache.gid2sid_winname.winname_num = 0; avl_create(&idmap_cache.winname2uid_gid.tree, (avl_comp_fn)idmap_compare_winname, sizeof (winname2uid_gid_t), offsetof(winname2uid_gid_t, avl_link)); (void) pthread_mutex_init(&idmap_cache.winname2uid_gid.mutex, NULL); idmap_cache.winname2uid_gid.head.flink = &idmap_cache.winname2uid_gid.head; idmap_cache.winname2uid_gid.head.blink = &idmap_cache.winname2uid_gid.head; idmap_cache.winname2uid_gid.prev = NULL; idmap_cache.winname2uid_gid.purge_time = 0; idmap_cache.winname2uid_gid.uid_num = 0; idmap_cache.winname2uid_gid.gid_num = 0; } void idmap_cache_purge(void) { sid2uid_gid_t *sid2uid_gid; pid2sid_winname_t *uid2sid_winname; pid2sid_winname_t *gid2sid_winname; winname2uid_gid_t *winname2uid_gid; void *cookie; (void) pthread_mutex_lock(&idmap_cache.sid2uid_gid.mutex); cookie = NULL; while ((sid2uid_gid = avl_destroy_nodes( &idmap_cache.sid2uid_gid.tree, &cookie)) != NULL) { free((char *)sid2uid_gid->sid_prefix); free(sid2uid_gid); } avl_destroy(&idmap_cache.sid2uid_gid.tree); avl_create(&idmap_cache.sid2uid_gid.tree, (avl_comp_fn)idmap_compare_sid, sizeof (sid2uid_gid_t), offsetof(sid2uid_gid_t, avl_link)); idmap_cache.sid2uid_gid.head.flink = &idmap_cache.sid2uid_gid.head; idmap_cache.sid2uid_gid.head.blink = &idmap_cache.sid2uid_gid.head; idmap_cache.sid2uid_gid.prev = NULL; idmap_cache.sid2uid_gid.purge_time = 0; idmap_cache.sid2uid_gid.uid_num = 0; idmap_cache.sid2uid_gid.gid_num = 0; idmap_cache.sid2uid_gid.pid_num = 0; (void) pthread_mutex_unlock(&idmap_cache.sid2uid_gid.mutex); (void) pthread_mutex_lock(&idmap_cache.uid2sid_winname.mutex); cookie = NULL; while ((uid2sid_winname = avl_destroy_nodes( &idmap_cache.uid2sid_winname.tree, &cookie)) != NULL) { free((char *)uid2sid_winname->sid_prefix); free((char *)uid2sid_winname->winname); if (uid2sid_winname->windomain != NULL) free((char *)uid2sid_winname->windomain); free(uid2sid_winname); } avl_destroy(&idmap_cache.uid2sid_winname.tree); avl_create(&idmap_cache.uid2sid_winname.tree, (avl_comp_fn)idmap_compare_pid, sizeof (pid2sid_winname_t), offsetof(pid2sid_winname_t, avl_link)); idmap_cache.uid2sid_winname.head.flink = &idmap_cache.uid2sid_winname.head; idmap_cache.uid2sid_winname.head.blink = &idmap_cache.uid2sid_winname.head; idmap_cache.uid2sid_winname.prev = NULL; idmap_cache.uid2sid_winname.purge_time = 0; idmap_cache.uid2sid_winname.sid_num = 0; idmap_cache.uid2sid_winname.winname_num = 0; (void) pthread_mutex_unlock(&idmap_cache.uid2sid_winname.mutex); (void) pthread_mutex_lock(&idmap_cache.gid2sid_winname.mutex); cookie = NULL; while ((gid2sid_winname = avl_destroy_nodes( &idmap_cache.gid2sid_winname.tree, &cookie)) != NULL) { free((char *)gid2sid_winname->sid_prefix); free((char *)gid2sid_winname->winname); if (gid2sid_winname->windomain != NULL) free((char *)gid2sid_winname->windomain); free(gid2sid_winname); } avl_destroy(&idmap_cache.gid2sid_winname.tree); avl_create(&idmap_cache.gid2sid_winname.tree, (avl_comp_fn)idmap_compare_pid, sizeof (pid2sid_winname_t), offsetof(pid2sid_winname_t, avl_link)); idmap_cache.gid2sid_winname.head.flink = &idmap_cache.gid2sid_winname.head; idmap_cache.gid2sid_winname.head.blink = &idmap_cache.gid2sid_winname.head; idmap_cache.gid2sid_winname.prev = NULL; idmap_cache.gid2sid_winname.purge_time = 0; idmap_cache.gid2sid_winname.sid_num = 0; idmap_cache.gid2sid_winname.winname_num = 0; (void) pthread_mutex_unlock(&idmap_cache.gid2sid_winname.mutex); (void) pthread_mutex_lock(&idmap_cache.winname2uid_gid.mutex); cookie = NULL; while ((winname2uid_gid = avl_destroy_nodes( &idmap_cache.winname2uid_gid.tree, &cookie)) != NULL) { free((char *)winname2uid_gid->winname); if (winname2uid_gid->windomain) free((char *)winname2uid_gid->windomain); free(winname2uid_gid); } avl_destroy(&idmap_cache.winname2uid_gid.tree); avl_create(&idmap_cache.winname2uid_gid.tree, (avl_comp_fn)idmap_compare_winname, sizeof (winname2uid_gid_t), offsetof(winname2uid_gid_t, avl_link)); idmap_cache.winname2uid_gid.head.flink = &idmap_cache.winname2uid_gid.head; idmap_cache.winname2uid_gid.head.blink = &idmap_cache.winname2uid_gid.head; idmap_cache.winname2uid_gid.prev = NULL; idmap_cache.winname2uid_gid.purge_time = 0; idmap_cache.winname2uid_gid.uid_num = 0; idmap_cache.winname2uid_gid.gid_num = 0; (void) pthread_mutex_unlock(&idmap_cache.winname2uid_gid.mutex); } void idmap_cache_get_data(size_t *uidbysid, size_t *gidbysid, size_t *pidbysid, size_t *sidbyuid, size_t *sidbygid, size_t *winnamebyuid, size_t *winnamebygid, size_t *uidbywinname, size_t *gidbywinname) { (void) pthread_mutex_lock(&idmap_cache.sid2uid_gid.mutex); *uidbysid = idmap_cache.sid2uid_gid.uid_num; *gidbysid = idmap_cache.sid2uid_gid.gid_num; *pidbysid = idmap_cache.sid2uid_gid.pid_num; (void) pthread_mutex_unlock(&idmap_cache.sid2uid_gid.mutex); (void) pthread_mutex_lock(&idmap_cache.uid2sid_winname.mutex); *sidbyuid = idmap_cache.uid2sid_winname.sid_num; *winnamebyuid = idmap_cache.uid2sid_winname.winname_num; (void) pthread_mutex_unlock(&idmap_cache.uid2sid_winname.mutex); (void) pthread_mutex_lock(&idmap_cache.gid2sid_winname.mutex); *sidbygid = idmap_cache.gid2sid_winname.sid_num; *winnamebygid = idmap_cache.gid2sid_winname.winname_num; (void) pthread_mutex_unlock(&idmap_cache.gid2sid_winname.mutex); (void) pthread_mutex_lock(&idmap_cache.winname2uid_gid.mutex); *uidbywinname = idmap_cache.winname2uid_gid.uid_num; *gidbywinname = idmap_cache.winname2uid_gid.gid_num; (void) pthread_mutex_unlock(&idmap_cache.winname2uid_gid.mutex); } idmap_stat idmap_cache_lookup_uidbysid(const char *sid_prefix, idmap_rid_t rid, uid_t *uid) { sid2uid_gid_t entry; sid2uid_gid_t *result; avl_index_t where; int status = IDMAP_ERR_NOMAPPING; time_t now = time(NULL); entry.sid_prefix = sid_prefix; entry.rid = rid; (void) pthread_mutex_lock(&idmap_cache.sid2uid_gid.mutex); result = avl_find(&idmap_cache.sid2uid_gid.tree, &entry, &where); if (result != NULL) { list_move(&idmap_cache.sid2uid_gid.head, result); if (result->uid != UNDEF_UID && result->uid_ttl > now) { *uid = result->uid; status = IDMAP_SUCCESS; } } (void) pthread_mutex_unlock(&idmap_cache.sid2uid_gid.mutex); return (status); } idmap_stat idmap_cache_lookup_gidbysid(const char *sid_prefix, idmap_rid_t rid, gid_t *gid) { sid2uid_gid_t entry; sid2uid_gid_t *result; avl_index_t where; int status = IDMAP_ERR_NOMAPPING; time_t now = time(NULL); entry.sid_prefix = sid_prefix; entry.rid = rid; (void) pthread_mutex_lock(&idmap_cache.sid2uid_gid.mutex); result = avl_find(&idmap_cache.sid2uid_gid.tree, &entry, &where); if (result != NULL) { list_move(&idmap_cache.sid2uid_gid.head, result); if (result->gid != UNDEF_GID && result->gid_ttl > now) { *gid = result->gid; status = IDMAP_SUCCESS; } } (void) pthread_mutex_unlock(&idmap_cache.sid2uid_gid.mutex); return (status); } idmap_stat idmap_cache_lookup_pidbysid(const char *sid_prefix, idmap_rid_t rid, uid_t *pid, int *is_user) { sid2uid_gid_t entry; sid2uid_gid_t *result; avl_index_t where; int status = IDMAP_ERR_NOMAPPING; time_t now = time(NULL); entry.sid_prefix = sid_prefix; entry.rid = rid; (void) pthread_mutex_lock(&idmap_cache.sid2uid_gid.mutex); result = avl_find(&idmap_cache.sid2uid_gid.tree, &entry, &where); if (result != NULL) { list_move(&idmap_cache.sid2uid_gid.head, result); if (result->is_user != UNDEF_ISUSER) { *is_user = result->is_user; if (result->is_user && result->uid_ttl > now) { *pid = result->uid; status = IDMAP_SUCCESS; } else if (!result->is_user && result->gid_ttl > now) { *pid = result->gid; status = IDMAP_SUCCESS; } } } (void) pthread_mutex_unlock(&idmap_cache.sid2uid_gid.mutex); return (status); } idmap_stat idmap_cache_lookup_sidbyuid(char **sid_prefix, idmap_rid_t *rid, uid_t uid) { pid2sid_winname_t entry; pid2sid_winname_t *result; avl_index_t where; int status = IDMAP_ERR_NOMAPPING; time_t now = time(NULL); entry.pid = uid; (void) pthread_mutex_lock(&idmap_cache.uid2sid_winname.mutex); result = avl_find(&idmap_cache.uid2sid_winname.tree, &entry, &where); if (result != NULL) { list_move(&idmap_cache.uid2sid_winname.head, result); if (result->sid_ttl > now) { *rid = result->rid; *sid_prefix = strdup(result->sid_prefix); if (*sid_prefix != NULL) status = IDMAP_SUCCESS; else status = IDMAP_ERR_MEMORY; } } (void) pthread_mutex_unlock(&idmap_cache.uid2sid_winname.mutex); return (status); } idmap_stat idmap_cache_lookup_sidbygid(char **sid_prefix, idmap_rid_t *rid, gid_t gid) { pid2sid_winname_t entry; pid2sid_winname_t *result; avl_index_t where; int status = IDMAP_ERR_NOMAPPING; time_t now = time(NULL); entry.pid = gid; (void) pthread_mutex_lock(&idmap_cache.gid2sid_winname.mutex); result = avl_find(&idmap_cache.gid2sid_winname.tree, &entry, &where); if (result != NULL) { list_move(&idmap_cache.gid2sid_winname.head, result); if (result->sid_ttl > now) { *rid = result->rid; *sid_prefix = strdup(result->sid_prefix); if (*sid_prefix != NULL) status = IDMAP_SUCCESS; else status = IDMAP_ERR_MEMORY; } } (void) pthread_mutex_unlock(&idmap_cache.gid2sid_winname.mutex); return (status); } idmap_stat idmap_cache_lookup_winnamebyuid(char **name, char **domain, uid_t uid) { pid2sid_winname_t entry; pid2sid_winname_t *result; avl_index_t where; int status = IDMAP_ERR_NOMAPPING; time_t now = time(NULL); entry.pid = uid; (void) pthread_mutex_lock(&idmap_cache.uid2sid_winname.mutex); result = avl_find(&idmap_cache.uid2sid_winname.tree, &entry, &where); if (result != NULL) { list_move(&idmap_cache.uid2sid_winname.head, result); if (result->winname_ttl > now) { *name = strdup(result->winname); if (*name != NULL) { if (domain != NULL) { if (result->windomain != NULL) { *domain = strdup(result->windomain); if (*domain != NULL) status = IDMAP_SUCCESS; else status = IDMAP_ERR_MEMORY; } else { *domain = NULL; status = IDMAP_SUCCESS; } } else status = IDMAP_SUCCESS; } else status = IDMAP_ERR_MEMORY; } } (void) pthread_mutex_unlock(&idmap_cache.uid2sid_winname.mutex); return (status); } idmap_stat idmap_cache_lookup_winnamebygid(char **name, char **domain, gid_t gid) { pid2sid_winname_t entry; pid2sid_winname_t *result; avl_index_t where; int status = IDMAP_ERR_NOMAPPING; time_t now = time(NULL); entry.pid = gid; (void) pthread_mutex_lock(&idmap_cache.gid2sid_winname.mutex); result = avl_find(&idmap_cache.gid2sid_winname.tree, &entry, &where); if (result != NULL) { list_move(&idmap_cache.gid2sid_winname.head, result); if (result->winname_ttl > now) { *name = strdup(result->winname); if (*name != NULL) { if (domain != NULL) { if (result->windomain != NULL) { *domain = strdup(result->windomain); if (*domain != NULL) status = IDMAP_SUCCESS; else status = IDMAP_ERR_MEMORY; } else { *domain = NULL; status = IDMAP_SUCCESS; } } else status = IDMAP_SUCCESS; } else status = IDMAP_ERR_MEMORY; } } (void) pthread_mutex_unlock(&idmap_cache.gid2sid_winname.mutex); return (status); } idmap_stat idmap_cache_lookup_uidbywinname(const char *name, const char *domain, uid_t *uid) { winname2uid_gid_t entry; winname2uid_gid_t *result; avl_index_t where; int status = IDMAP_ERR_NOMAPPING; time_t now = time(NULL); entry.winname = name; entry.windomain = domain; (void) pthread_mutex_lock(&idmap_cache.winname2uid_gid.mutex); result = avl_find(&idmap_cache.winname2uid_gid.tree, &entry, &where); if (result != NULL) { list_move(&idmap_cache.winname2uid_gid.head, result); if (result->uid != UNDEF_UID && result->uid_ttl > now) { *uid = result->uid; status = IDMAP_SUCCESS; } } (void) pthread_mutex_unlock(&idmap_cache.winname2uid_gid.mutex); return (status); } idmap_stat idmap_cache_lookup_gidbywinname(const char *name, const char *domain, gid_t *gid) { winname2uid_gid_t entry; winname2uid_gid_t *result; avl_index_t where; int status = IDMAP_ERR_NOMAPPING; time_t now = time(NULL); entry.winname = name; entry.windomain = domain; (void) pthread_mutex_lock(&idmap_cache.winname2uid_gid.mutex); result = avl_find(&idmap_cache.winname2uid_gid.tree, &entry, &where); if (result != NULL) { list_move(&idmap_cache.winname2uid_gid.head, result); if (result->gid != UNDEF_GID && result->gid_ttl > now) { *gid = result->gid; status = IDMAP_SUCCESS; } } (void) pthread_mutex_unlock(&idmap_cache.winname2uid_gid.mutex); return (status); } void idmap_cache_add_sid2uid(const char *sid_prefix, idmap_rid_t rid, uid_t uid, int direction) { avl_index_t where; time_t ttl = CACHE_TTL + time(NULL); if (direction == IDMAP_DIRECTION_BI || direction == IDMAP_DIRECTION_W2U) { sid2uid_gid_t find; sid2uid_gid_t *result; sid2uid_gid_t *new; find.sid_prefix = sid_prefix; find.rid = rid; (void) pthread_mutex_lock(&idmap_cache.sid2uid_gid.mutex); result = avl_find(&idmap_cache.sid2uid_gid.tree, &find, &where); if (result) { if (result->uid_ttl == 0) idmap_cache.sid2uid_gid.uid_num++; result->uid = uid; result->uid_ttl = ttl; } else { new = malloc(sizeof (sid2uid_gid_t)); if (new == NULL) goto exit_sid2uid_gid; new->sid_prefix = strdup(sid_prefix); if (new->sid_prefix == NULL) { free(new); goto exit_sid2uid_gid; } new->rid = rid; new->uid = uid; new->uid_ttl = ttl; new->gid = UNDEF_GID; new->gid_ttl = 0; new->is_user = UNDEF_ISUSER; /* Unknown */ idmap_cache.sid2uid_gid.uid_num++; list_insert(&idmap_cache.sid2uid_gid.head, new); avl_insert(&idmap_cache.sid2uid_gid.tree, new, where); } if ((avl_numnodes(&idmap_cache.sid2uid_gid.tree) > CACHE_UID_GID_TRIGGER_SIZE) && (idmap_cache.sid2uid_gid.purge_time + CACHE_PURGE_INTERVAL < time(NULL))) idmap_purge_sid2uid_gid_cache(&idmap_cache.sid2uid_gid, CACHE_UID_GID_TRIGGER_SIZE); exit_sid2uid_gid: (void) pthread_mutex_unlock(&idmap_cache.sid2uid_gid.mutex); } if (direction == IDMAP_DIRECTION_BI || direction == IDMAP_DIRECTION_U2W) { pid2sid_winname_t find; pid2sid_winname_t *result; pid2sid_winname_t *new; find.pid = uid; (void) pthread_mutex_lock(&idmap_cache.uid2sid_winname.mutex); result = avl_find(&idmap_cache.uid2sid_winname.tree, &find, &where); if (result) { if (update_str(&result->sid_prefix, sid_prefix) != 0) goto exit_pid2sid_winname; if (result->sid_ttl == 0) idmap_cache.uid2sid_winname.sid_num++; result->rid = rid; result->sid_ttl = ttl; } else { new = malloc(sizeof (pid2sid_winname_t)); if (new == NULL) goto exit_pid2sid_winname; new->pid = uid; new->sid_prefix = strdup(sid_prefix); if (new->sid_prefix == NULL) { free(new); goto exit_pid2sid_winname; } new->rid = rid; new->sid_ttl = ttl; new->winname = NULL; new->windomain = NULL; new->winname_ttl = 0; idmap_cache.uid2sid_winname.sid_num ++; list_insert(&idmap_cache.uid2sid_winname.head, new); avl_insert(&idmap_cache.uid2sid_winname.tree, new, where); } if ((avl_numnodes(&idmap_cache.uid2sid_winname.tree) > CACHE_UID_TRIGGER_SIZE) && (idmap_cache.uid2sid_winname.purge_time + CACHE_PURGE_INTERVAL < time(NULL))) idmap_purge_pid2sid_winname_cache( &idmap_cache.uid2sid_winname, CACHE_UID_TRIGGER_SIZE); exit_pid2sid_winname: (void) pthread_mutex_unlock(&idmap_cache.uid2sid_winname.mutex); } } void idmap_cache_add_sid2gid(const char *sid_prefix, idmap_rid_t rid, gid_t gid, int direction) { avl_index_t where; time_t ttl = CACHE_TTL + time(NULL); if (direction == IDMAP_DIRECTION_BI || direction == IDMAP_DIRECTION_W2U) { sid2uid_gid_t find; sid2uid_gid_t *result; sid2uid_gid_t *new; find.sid_prefix = sid_prefix; find.rid = rid; (void) pthread_mutex_lock(&idmap_cache.sid2uid_gid.mutex); result = avl_find(&idmap_cache.sid2uid_gid.tree, &find, &where); if (result) { if (result->gid_ttl == 0) idmap_cache.sid2uid_gid.gid_num++; result->gid = gid; result->gid_ttl = ttl; } else { new = malloc(sizeof (sid2uid_gid_t)); if (new == NULL) goto exit_sid2uid_gid; new->sid_prefix = strdup(sid_prefix); if (new->sid_prefix == NULL) { free(new); goto exit_sid2uid_gid; } new->rid = rid; new->uid = UNDEF_UID; new->uid_ttl = 0; new->gid = gid; new->gid_ttl = ttl; new->is_user = UNDEF_ISUSER; /* Unknown */ idmap_cache.sid2uid_gid.gid_num++; list_insert(&idmap_cache.sid2uid_gid.head, new); avl_insert(&idmap_cache.sid2uid_gid.tree, new, where); } if ((avl_numnodes(&idmap_cache.sid2uid_gid.tree) > CACHE_UID_GID_TRIGGER_SIZE) && (idmap_cache.sid2uid_gid.purge_time + CACHE_PURGE_INTERVAL < time(NULL))) idmap_purge_sid2uid_gid_cache(&idmap_cache.sid2uid_gid, CACHE_UID_GID_TRIGGER_SIZE); exit_sid2uid_gid: (void) pthread_mutex_unlock(&idmap_cache.sid2uid_gid.mutex); } if (direction == IDMAP_DIRECTION_BI || direction == IDMAP_DIRECTION_U2W) { pid2sid_winname_t find; pid2sid_winname_t *result; pid2sid_winname_t *new; find.pid = gid; (void) pthread_mutex_lock(&idmap_cache.gid2sid_winname.mutex); result = avl_find(&idmap_cache.gid2sid_winname.tree, &find, &where); if (result) { if (update_str(&result->sid_prefix, sid_prefix) != 0) goto exit_gid2sid_winname; if (result->sid_ttl == 0) idmap_cache.gid2sid_winname.sid_num++; result->rid = rid; result->sid_ttl = ttl; } else { new = malloc(sizeof (pid2sid_winname_t)); if (new == NULL) goto exit_gid2sid_winname; new->sid_prefix = strdup(sid_prefix); if (new->sid_prefix == NULL) { free(new); goto exit_gid2sid_winname; } new->rid = rid; new->pid = gid; new->sid_ttl = ttl; new->winname = NULL; new->windomain = NULL; new->winname_ttl = 0; idmap_cache.gid2sid_winname.sid_num++; list_insert(&idmap_cache.gid2sid_winname.head, new); avl_insert(&idmap_cache.gid2sid_winname.tree, new, where); } if ((avl_numnodes(&idmap_cache.gid2sid_winname.tree) > CACHE_GID_TRIGGER_SIZE) && (idmap_cache.gid2sid_winname.purge_time + CACHE_PURGE_INTERVAL < time(NULL))) idmap_purge_pid2sid_winname_cache( &idmap_cache.gid2sid_winname, CACHE_GID_TRIGGER_SIZE); exit_gid2sid_winname: (void) pthread_mutex_unlock(&idmap_cache.gid2sid_winname.mutex); } } void idmap_cache_add_sid2pid(const char *sid_prefix, idmap_rid_t rid, uid_t pid, int is_user, int direction) { avl_index_t where; time_t ttl = CACHE_TTL + time(NULL); if (direction == IDMAP_DIRECTION_BI || direction == IDMAP_DIRECTION_W2U) { sid2uid_gid_t find; sid2uid_gid_t *result; sid2uid_gid_t *new; find.sid_prefix = sid_prefix; find.rid = rid; (void) pthread_mutex_lock(&idmap_cache.sid2uid_gid.mutex); result = avl_find(&idmap_cache.sid2uid_gid.tree, &find, &where); if (result) { if (result->is_user == UNDEF_ISUSER) idmap_cache.sid2uid_gid.pid_num++; result->is_user = is_user; if (is_user) { if (result->uid_ttl == 0) idmap_cache.sid2uid_gid.uid_num++; result->uid = pid; result->uid_ttl = ttl; } else { if (result->gid_ttl == 0) idmap_cache.sid2uid_gid.gid_num++; result->gid = pid; result->gid_ttl = ttl; } } else { new = malloc(sizeof (sid2uid_gid_t)); if (new == NULL) goto exit_sid2uid_gid; new->sid_prefix = strdup(sid_prefix); if (new->sid_prefix == NULL) { free(new); goto exit_sid2uid_gid; } new->rid = rid; new->is_user = is_user; if (is_user) { new->uid = pid; new->uid_ttl = ttl; new->gid = UNDEF_GID; new->gid_ttl = 0; idmap_cache.sid2uid_gid.uid_num++; } else { new->uid = UNDEF_UID; new->uid_ttl = 0; new->gid = pid; new->gid_ttl = ttl; idmap_cache.sid2uid_gid.gid_num++; } idmap_cache.sid2uid_gid.pid_num++; list_insert(&idmap_cache.sid2uid_gid.head, new); avl_insert(&idmap_cache.sid2uid_gid.tree, new, where); } if ((avl_numnodes(&idmap_cache.sid2uid_gid.tree) > CACHE_UID_GID_TRIGGER_SIZE) && (idmap_cache.sid2uid_gid.purge_time + CACHE_PURGE_INTERVAL < time(NULL))) idmap_purge_sid2uid_gid_cache(&idmap_cache.sid2uid_gid, CACHE_UID_GID_TRIGGER_SIZE); exit_sid2uid_gid: (void) pthread_mutex_unlock(&idmap_cache.sid2uid_gid.mutex); } if (direction == IDMAP_DIRECTION_BI || direction == IDMAP_DIRECTION_U2W) { pid2sid_winname_t find; pid2sid_winname_t *result; pid2sid_winname_t *new; find.pid = pid; if (is_user) { (void) pthread_mutex_lock( &idmap_cache.uid2sid_winname.mutex); result = avl_find(&idmap_cache.uid2sid_winname.tree, &find, &where); if (result) { if (update_str(&result->sid_prefix, sid_prefix) != 0) goto exit_uid2sid_winname; if (result->sid_ttl == 0) idmap_cache.uid2sid_winname.sid_num++; result->rid = rid; result->sid_ttl = ttl; } else { new = malloc(sizeof (pid2sid_winname_t)); if (new == NULL) goto exit_uid2sid_winname; new->sid_prefix = strdup(sid_prefix); if (new->sid_prefix == NULL) { free(new); goto exit_uid2sid_winname; } new->rid = rid; new->pid = pid; new->sid_ttl = ttl; new->winname = NULL; new->windomain = NULL; new->winname_ttl = 0; idmap_cache.uid2sid_winname.sid_num++; list_insert(&idmap_cache.uid2sid_winname.head, new); avl_insert(&idmap_cache.uid2sid_winname.tree, new, where); } if ((avl_numnodes(&idmap_cache.uid2sid_winname.tree) > CACHE_UID_TRIGGER_SIZE) && (idmap_cache.uid2sid_winname.purge_time + CACHE_PURGE_INTERVAL < time(NULL))) idmap_purge_pid2sid_winname_cache( &idmap_cache.uid2sid_winname, CACHE_UID_TRIGGER_SIZE); exit_uid2sid_winname: (void) pthread_mutex_unlock( &idmap_cache.uid2sid_winname.mutex); } else { (void) pthread_mutex_lock( &idmap_cache.gid2sid_winname.mutex); result = avl_find(&idmap_cache.gid2sid_winname.tree, &find, &where); if (result) { if (update_str(&result->sid_prefix, sid_prefix) != 0) goto exit_gid2sid_winname; if (result->sid_ttl == 0) idmap_cache.gid2sid_winname.sid_num++; result->rid = rid; result->sid_ttl = ttl; } else { new = malloc(sizeof (pid2sid_winname_t)); if (new == NULL) goto exit_gid2sid_winname; new->sid_prefix = strdup(sid_prefix); if (new->sid_prefix == NULL) { free(new); goto exit_gid2sid_winname; } new->rid = rid; new->pid = pid; new->sid_ttl = ttl; new->winname = NULL; new->windomain = NULL; new->winname_ttl = 0; idmap_cache.gid2sid_winname.sid_num++; list_insert(&idmap_cache.gid2sid_winname.head, new); avl_insert(&idmap_cache.gid2sid_winname.tree, new, where); } if ((avl_numnodes(&idmap_cache.gid2sid_winname.tree) > CACHE_GID_TRIGGER_SIZE) && (idmap_cache.gid2sid_winname.purge_time + CACHE_PURGE_INTERVAL < time(NULL))) idmap_purge_pid2sid_winname_cache( &idmap_cache.gid2sid_winname, CACHE_GID_TRIGGER_SIZE); exit_gid2sid_winname: (void) pthread_mutex_unlock( &idmap_cache.gid2sid_winname.mutex); } } } void idmap_cache_add_winname2uid(const char *name, const char *domain, uid_t uid, int direction) { avl_index_t where; time_t ttl = CACHE_TTL + time(NULL); if (direction == IDMAP_DIRECTION_BI || direction == IDMAP_DIRECTION_W2U) { winname2uid_gid_t find; winname2uid_gid_t *result; winname2uid_gid_t *new; find.winname = name; find.windomain = domain; (void) pthread_mutex_lock(&idmap_cache.winname2uid_gid.mutex); result = avl_find(&idmap_cache.winname2uid_gid.tree, &find, &where); if (result) { if (result->uid_ttl == 0) idmap_cache.winname2uid_gid.uid_num++; result->uid = uid; result->uid_ttl = ttl; } else { new = malloc(sizeof (winname2uid_gid_t)); if (new == NULL) goto exit_winname2uid_gid; new->winname = strdup(name); if (new->winname == NULL) { free(new); goto exit_winname2uid_gid; } if (domain != NULL) { new->windomain = strdup(domain); if (new->winname == NULL) { free((char *)new->winname); free(new); goto exit_winname2uid_gid; } } else new->windomain = NULL; new->uid = uid; new->uid_ttl = ttl; new->gid = UNDEF_GID; new->gid_ttl = 0; idmap_cache.winname2uid_gid.uid_num++; list_insert(&idmap_cache.winname2uid_gid.head, new); avl_insert(&idmap_cache.winname2uid_gid.tree, new, where); } if ((avl_numnodes(&idmap_cache.winname2uid_gid.tree) > CACHE_UID_GID_TRIGGER_SIZE) && (idmap_cache.winname2uid_gid.purge_time + CACHE_PURGE_INTERVAL < time(NULL))) idmap_purge_winname2uid_gid_cache( &idmap_cache.winname2uid_gid, CACHE_UID_GID_TRIGGER_SIZE); exit_winname2uid_gid: (void) pthread_mutex_unlock(&idmap_cache.winname2uid_gid.mutex); } if (direction == IDMAP_DIRECTION_BI || direction == IDMAP_DIRECTION_U2W) { pid2sid_winname_t find; pid2sid_winname_t *result; pid2sid_winname_t *new; find.pid = uid; (void) pthread_mutex_lock(&idmap_cache.uid2sid_winname.mutex); result = avl_find(&idmap_cache.uid2sid_winname.tree, &find, &where); if (result) { if (update_str(&result->winname, name) != 0) goto exit_uid2sid_winname; if (update_str(&result->windomain, domain) != 0) goto exit_uid2sid_winname; if (result->winname_ttl == 0) idmap_cache.uid2sid_winname.winname_num++; result->winname_ttl = ttl; } else { new = malloc(sizeof (pid2sid_winname_t)); if (new == NULL) goto exit_uid2sid_winname; new->pid = uid; new->winname = strdup(name); if (new->winname == NULL) { free(new); goto exit_uid2sid_winname; } if (domain != NULL) { new->windomain = strdup(domain); if (new->windomain == NULL) { free((char *)new->winname); free(new); goto exit_uid2sid_winname; } } else new->windomain = NULL; new->winname_ttl = ttl; new->sid_prefix = NULL; new->rid = 0; new->sid_ttl = 0; idmap_cache.uid2sid_winname.winname_num ++; list_insert(&idmap_cache.uid2sid_winname.head, new); avl_insert(&idmap_cache.uid2sid_winname.tree, new, where); } if ((avl_numnodes(&idmap_cache.uid2sid_winname.tree) > CACHE_UID_TRIGGER_SIZE) && (idmap_cache.uid2sid_winname.purge_time + CACHE_PURGE_INTERVAL < time(NULL))) idmap_purge_pid2sid_winname_cache( &idmap_cache.uid2sid_winname, CACHE_UID_TRIGGER_SIZE); exit_uid2sid_winname: (void) pthread_mutex_unlock(&idmap_cache.uid2sid_winname.mutex); } } void idmap_cache_add_winname2gid(const char *name, const char *domain, gid_t gid, int direction) { avl_index_t where; time_t ttl = CACHE_TTL + time(NULL); if (direction == IDMAP_DIRECTION_BI || direction == IDMAP_DIRECTION_W2U) { winname2uid_gid_t find; winname2uid_gid_t *result; winname2uid_gid_t *new; find.winname = name; find.windomain = domain; (void) pthread_mutex_lock(&idmap_cache.winname2uid_gid.mutex); result = avl_find(&idmap_cache.winname2uid_gid.tree, &find, &where); if (result) { if (result->uid_ttl == 0) idmap_cache.winname2uid_gid.gid_num++; result->gid = gid; result->gid_ttl = ttl; } else { new = malloc(sizeof (winname2uid_gid_t)); if (new == NULL) goto exit_winname2uid_gid; new->winname = strdup(name); if (new->winname == NULL) { free(new); goto exit_winname2uid_gid; } if (domain != NULL) { new->windomain = strdup(domain); if (new->windomain == NULL) { free((char *)new->winname); free(new); goto exit_winname2uid_gid; } } else new->windomain = NULL; new->uid = UNDEF_UID; new->uid_ttl = 0; new->gid = gid; new->gid_ttl = ttl; idmap_cache.winname2uid_gid.gid_num++; list_insert(&idmap_cache.winname2uid_gid.head, new); avl_insert(&idmap_cache.winname2uid_gid.tree, new, where); } if ((avl_numnodes(&idmap_cache.winname2uid_gid.tree) > CACHE_UID_GID_TRIGGER_SIZE) && (idmap_cache.winname2uid_gid.purge_time + CACHE_PURGE_INTERVAL < time(NULL))) idmap_purge_winname2uid_gid_cache( &idmap_cache.winname2uid_gid, CACHE_UID_GID_TRIGGER_SIZE); exit_winname2uid_gid: (void) pthread_mutex_unlock(&idmap_cache.winname2uid_gid.mutex); } if (direction == IDMAP_DIRECTION_BI || direction == IDMAP_DIRECTION_U2W) { pid2sid_winname_t find; pid2sid_winname_t *result; pid2sid_winname_t *new; find.pid = gid; (void) pthread_mutex_lock(&idmap_cache.gid2sid_winname.mutex); result = avl_find(&idmap_cache.gid2sid_winname.tree, &find, &where); if (result) { if (update_str(&result->winname, name) != 0) goto exit_gid2sid_winname; if (update_str(&result->windomain, domain) != 0) goto exit_gid2sid_winname; if (result->winname_ttl == 0) idmap_cache.gid2sid_winname.winname_num++; result->winname_ttl = ttl; } else { new = malloc(sizeof (pid2sid_winname_t)); if (new == NULL) goto exit_gid2sid_winname; new->pid = gid; new->winname = strdup(name); if (new->winname == NULL) { free(new); goto exit_gid2sid_winname; } if (domain != NULL) { new->windomain = strdup(domain); if (new->windomain == NULL) { free((char *)new->winname); free(new); goto exit_gid2sid_winname; } } else new->windomain = NULL; new->winname_ttl = ttl; new->sid_prefix = NULL; new->rid = 0; new->sid_ttl = 0; idmap_cache.gid2sid_winname.winname_num ++; list_insert(&idmap_cache.gid2sid_winname.head, new); avl_insert(&idmap_cache.gid2sid_winname.tree, new, where); } if ((avl_numnodes(&idmap_cache.gid2sid_winname.tree) > CACHE_UID_TRIGGER_SIZE) && (idmap_cache.gid2sid_winname.purge_time + CACHE_PURGE_INTERVAL < time(NULL))) idmap_purge_pid2sid_winname_cache( &idmap_cache.gid2sid_winname, CACHE_UID_TRIGGER_SIZE); exit_gid2sid_winname: (void) pthread_mutex_unlock(&idmap_cache.gid2sid_winname.mutex); } } static void idmap_purge_sid2uid_gid_cache(sid2uid_gid_cache_t *cache, size_t limit) { time_t now = time(NULL); sid2uid_gid_t *item; while (avl_numnodes(&cache->tree) > limit) { /* Remove least recently used */ item = cache->head.blink; list_remove(item); avl_remove(&cache->tree, item); if (item->uid_ttl != 0) cache->uid_num--; if (item->gid_ttl != 0) cache->gid_num--; if (item->is_user != UNDEF_ISUSER) cache->pid_num--; if (item->sid_prefix) free((char *)item->sid_prefix); free(item); } cache->purge_time = now; } static void idmap_purge_winname2uid_gid_cache(winname2uid_gid_cache_t *cache, size_t limit) { time_t now = time(NULL); winname2uid_gid_t *item; while (avl_numnodes(&cache->tree) > limit) { /* Remove least recently used */ item = cache->head.blink; list_remove(item); avl_remove(&cache->tree, item); if (item->uid_ttl != 0) cache->uid_num--; if (item->gid_ttl != 0) cache->gid_num--; if (item->winname) free((char *)item->winname); if (item->windomain) free((char *)item->windomain); free(item); } cache->purge_time = now; } static void idmap_purge_pid2sid_winname_cache(pid2sid_winname_cache_t *cache, size_t limit) { time_t now = time(NULL); pid2sid_winname_t *item; while (avl_numnodes(&cache->tree) > limit) { /* Remove least recently used */ item = cache->head.blink; list_remove(item); avl_remove(&cache->tree, item); if (item->winname_ttl != 0) cache->winname_num--; if (item->sid_ttl != 0) cache->sid_num--; if (item->winname) free((char *)item->winname); if (item->windomain) free((char *)item->windomain); if (item->sid_prefix) free((char *)item->sid_prefix); free(item); } cache->purge_time = now; }