/** * @file gnome-cmd-owner.h * @copyright (C) 2001-2006 Marcus Bjurman\n * @copyright (C) 2007-2012 Piotr Eljasiak\n * @copyright (C) 2013-2023 Uwe Scholz\n * * @copyright This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * @copyright This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * @copyright You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include #include class GnomeCmdOwner { GThread *thread {nullptr}; gboolean stop_thread {FALSE}; char *buff; size_t buffsize; uid_t user_id; gid_t group_id; GList *group_names {nullptr}; public: template class HashTable { GHashTable *id_table; GHashTable *name_table; GList *entries; struct Entry { ID id; char *name; T data; }; Entry *lookup(ID id) { return static_cast (g_hash_table_lookup (id_table, &id)); } Entry *lookup(const gchar *name) { return static_cast (g_hash_table_lookup (name_table, name)); } Entry *add(ID id, const gchar *name); public: HashTable(); ~HashTable(); guint size() { return g_hash_table_size (id_table); } gboolean empty() { return size()==0; } const gchar *operator [] (ID id); ID operator [] (const gchar *name); GList *get_names(); friend class GnomeCmdOwner; }; struct user_t { char *real_name; gid_t gid; gboolean zombie; // the uid of this user doesn't match any user in the system }; struct group_t { gboolean zombie; // the gid of this group doesn't match any group in the system }; typedef HashTable GnomeCmdUsers; typedef HashTable GnomeCmdGroups; private: GnomeCmdUsers::Entry *new_entry(const struct passwd *pw); GnomeCmdGroups::Entry *new_entry(const struct group *grp); static gpointer perform_load_operation (GnomeCmdOwner *self); public: GnomeCmdUsers users; GnomeCmdGroups groups; GnomeCmdOwner(); ~GnomeCmdOwner(); uid_t uid() const { return user_id; } gid_t gid() const { return group_id; } gboolean is_root() { return uid()==0; } GList *get_group_names() { return group_names; } const char *get_name_by_uid(uid_t uid); const char *get_name_by_gid(gid_t gid); void load_async(); }; template inline GnomeCmdOwner::HashTable::HashTable() { entries = nullptr; id_table = g_hash_table_new (g_int_hash, g_int_equal); name_table = g_hash_table_new (g_str_hash, g_str_equal); } template GnomeCmdOwner::HashTable::~HashTable() { g_hash_table_destroy (id_table); g_hash_table_destroy (name_table); if (entries) { for (GList *i = entries; i; i = g_list_next (i)) { auto e = static_cast (i->data); g_free (e->name); } g_list_foreach (entries, (GFunc) g_free, nullptr); g_list_free (entries); } } template inline typename GnomeCmdOwner::HashTable::Entry *GnomeCmdOwner::HashTable::add(ID id, const gchar *name) { Entry *e = g_new0 (Entry, 1); e->id = id; e->name = g_strdup (name); entries = g_list_prepend (entries, e); g_hash_table_insert (id_table, &e->id, e); g_hash_table_insert (name_table, e->name, e); return e; } template inline const gchar *GnomeCmdOwner::HashTable::operator [] (ID id) { Entry *entry = lookup(id); return entry ? entry->name : nullptr; } template inline ID GnomeCmdOwner::HashTable::operator [] (const gchar *name) { Entry *entry = lookup(name); return entry ? entry->id : -1; } template inline GList *GnomeCmdOwner::HashTable::get_names() { return g_hash_table_get_keys (name_table); // FIXME: sort ? } inline GnomeCmdOwner::GnomeCmdUsers::Entry *GnomeCmdOwner::new_entry(const struct passwd *pw) { g_return_val_if_fail (pw != nullptr, nullptr); GnomeCmdUsers::Entry *entry = users.add(pw->pw_uid, pw->pw_name); entry->data.gid = pw->pw_gid; // entry->data.real_name = g_strdup (pw->pw_gecos); // not used at the moment // entry->data.zombie = FALSE; return entry; } inline GnomeCmdOwner::GnomeCmdGroups::Entry *GnomeCmdOwner::new_entry(const struct group *grp) { g_return_val_if_fail (grp != nullptr, nullptr); GnomeCmdGroups::Entry *entry = groups.add(grp->gr_gid, grp->gr_name); // entry->data.zombie = FALSE; return entry; } inline GnomeCmdOwner::~GnomeCmdOwner() { stop_thread = TRUE; if (thread) g_thread_join (thread); g_free (buff); g_list_free (group_names); } inline const char *GnomeCmdOwner::get_name_by_uid(uid_t id) { GnomeCmdUsers::Entry *entry = users.lookup(id); if (entry) return entry->name; struct passwd pwd, *result = nullptr; getpwuid_r(id, &pwd, buff, buffsize, &result); if (!result) // zombie { char s[32]; snprintf (s, sizeof(s), "%u", id); entry = users.add(id, s); entry->data.zombie = TRUE; return entry->name; } entry = new_entry(result); if (!groups.lookup(entry->data.gid)) get_name_by_gid(entry->data.gid); return entry->name; } inline const char *GnomeCmdOwner::get_name_by_gid(gid_t id) { GnomeCmdGroups::Entry *entry = groups.lookup(id); if (entry) return entry->name; struct group grp, *result = nullptr; getgrgid_r(id, &grp, buff, buffsize, &result); if (!result) // zombie { char s[32]; snprintf (s, sizeof(s), "%u", id); entry = groups.add(id, s); entry->data.zombie = TRUE; return entry->name; } entry = new_entry(result); return entry->name; } extern GnomeCmdOwner gcmd_owner;