diff options
author | Robin Hack <rhack@redhat.com> | 2013-10-31 08:32:36 +0100 |
---|---|---|
committer | Robin Hack <rhack@redhat.com> | 2013-10-31 13:40:40 +0100 |
commit | aac4d3a0d1dc878c1a8c11fd55e47613ec7e9050 (patch) | |
tree | 105af161789aa04f2e6b1369f766f1fbfd48e737 /src/account | |
parent | ecab16f131a16f4c01e596f86611881d1a95638f (diff) | |
download | openlmi-providers-aac4d3a0d1dc878c1a8c11fd55e47613ec7e9050.tar.gz openlmi-providers-aac4d3a0d1dc878c1a8c11fd55e47613ec7e9050.tar.xz openlmi-providers-aac4d3a0d1dc878c1a8c11fd55e47613ec7e9050.zip |
Account: Added 3 changes as one.
1) Account: Use new atomic libuser api.
2) Account: Added author and license to lock.c and lock.h.
3) Account: Added group locking to LMI_AccountProvider.
Diffstat (limited to 'src/account')
-rw-r--r-- | src/account/LMI_AccountProvider.c | 104 | ||||
-rw-r--r-- | src/account/lock.c | 209 | ||||
-rw-r--r-- | src/account/lock.h | 36 |
3 files changed, 243 insertions, 106 deletions
diff --git a/src/account/LMI_AccountProvider.c b/src/account/LMI_AccountProvider.c index cde4792..a8227ea 100644 --- a/src/account/LMI_AccountProvider.c +++ b/src/account/LMI_AccountProvider.c @@ -30,8 +30,14 @@ #include <utmp.h> +// Disable GLib deprecation warnings - GValueArray is deprecated but we +// need it because libuser uses it +#define GLIB_DISABLE_DEPRECATION_WARNINGS + #include <glib.h> +#undef GLIB_DISABLE_DEPRECATION_WARNINGS + #include <libuser/entity.h> #include <libuser/user.h> @@ -61,7 +67,7 @@ static const CMPIBroker* _cb = NULL; static void LMI_AccountInitialize(const CMPIContext *ctx) { lmi_init(provider_name, _cb, ctx, provider_config_defaults); - if (init_lock_pool() == 0) { + if (init_lock_pools() == 0) { error("Unable to initialize lock pool."); exit (1); } @@ -72,7 +78,7 @@ static CMPIStatus LMI_AccountCleanup( const CMPIContext* cc, CMPIBoolean term) { - destroy_lock_pool(); + destroy_lock_pools(); CMReturn(CMPI_RC_OK); } @@ -269,6 +275,7 @@ static CMPIStatus LMI_AccountModifyInstance( struct lu_ent *lue = NULL; struct lu_error *error = NULL; GValue val; + guint i = 0; long last_change; date_time_prop expiration, warning, inactive_password, inactive_account; @@ -285,14 +292,16 @@ static CMPIStatus LMI_AccountModifyInstance( char userlock[USERNAME_LEN_MAX] = {0}; /* -1 for NULL char */ strncpy(userlock, la.Name.chars, sizeof(userlock) - 1); - if (get_lock(userlock) == 0) { + lmi_debug("Getting lock for user: %s", userlock); + if (get_user_lock(userlock) == 0) { KReturn2(_cb, ERR_FAILED, "Unable to obtain lock."); } luc = lu_start(NULL, lu_user, NULL, NULL, lu_prompt_console_quiet, NULL, &error); if (!luc) { - release_lock (userlock); + const int ret = release_user_lock (userlock); + lmi_debug("Releasing lock for user: %s. Result: %d", userlock, ret); KReturn2(_cb, ERR_FAILED, "Unable to initialize libuser: %s\n", lu_strerror(error)); } @@ -306,6 +315,23 @@ static CMPIStatus LMI_AccountModifyInstance( goto fail; } + /* get list of groups and lock them. userlock variable is our stored username */ + GValueArray *groups = lu_groups_enumerate_by_user (luc, userlock, &error); + if (groups == NULL) + { + rc = CMPI_RC_ERR_NOT_FOUND; + asprintf(&errmsg, "Get groups for user %s failed with: %s", + userlock, lu_strerror(error)); + goto fail; + } + + for (i = 0; i < groups->n_values; ++i) { + GValue *group_val = g_value_array_get_nth (groups, i); + const gchar *const group_str = g_value_get_string(group_val); + const int ret = get_group_lock ((const char *const) group_str); + lmi_debug("Getting lock for group: %s. Result: %d", group_str, ret); + } + data = ci->ft->getProperty(ci, "UserPassword", NULL); ar = data.value.array; if (ar && (arsize = ar->ft->getSize(ar, NULL) > 0)) @@ -382,7 +408,16 @@ static CMPIStatus LMI_AccountModifyInstance( last_change = aux_lu_get_long(lue, LU_SHADOWLASTCHANGE); #define FAIL(msg) \ - release_lock (userlock); \ + for (i = 0; (groups != NULL) && (i < groups->n_values); ++i) { \ + GValue *group_val = g_value_array_get_nth (groups, i); \ + const gchar *const group_str = g_value_get_string(group_val); \ + const int ret = release_group_lock ((const char *const) group_str); \ + lmi_debug("Releasing lock for group: %s. Result: %d", group_str, ret); \ + } \ + g_value_array_free (groups); \ + groups = NULL; \ + const int ret = release_user_lock (userlock); \ + lmi_debug("Releasing lock for user: %s. Result: %d", userlock, ret); \ lu_end(luc); \ lu_ent_free(lue); \ KReturn2(_cb, ERR_FAILED, msg); @@ -473,7 +508,16 @@ static CMPIStatus LMI_AccountModifyInstance( } fail: - release_lock (userlock); + for (i = 0; (groups != NULL) && (i < groups->n_values); ++i) { + GValue *group_val = g_value_array_get_nth (groups, i); + const gchar *const group_str = g_value_get_string(group_val); + const int ret = release_group_lock ((const char *const) group_str); + lmi_debug("Releasing lock for group: %s. Result: %d", group_str, ret); + } + g_value_array_free (groups); + groups = NULL; + const int ret = release_user_lock (userlock); + lmi_debug("Releasing lock for user: %s. Result: %d", userlock, ret); lu_ent_free(lue); lu_end(luc); @@ -504,7 +548,6 @@ static CMPIrc delete_user( char *errormsg) { CMPIrc rc = CMPI_RC_OK; - const char *home = NULL; struct lu_context *luc = NULL; struct lu_error *error = NULL; struct lu_ent *lue = NULL; @@ -514,14 +557,16 @@ static CMPIrc delete_user( char userlock[USERNAME_LEN_MAX] = {0}; /* -1 for NULL char */ strncpy(userlock, username, sizeof(userlock) - 1); - if (get_lock(userlock) == 0) { + lmi_debug("Getting lock for user: %s. Result: %d", userlock); + if (get_user_lock(userlock) == 0) { asprintf(&errormsg, "Unable to obtain lock."); return CMPI_RC_ERR_FAILED; } luc = lu_start(NULL, 0, NULL, NULL, lu_prompt_console_quiet, NULL, &error); if (!luc) { - release_lock(userlock); + const int ret = release_user_lock(userlock); + lmi_debug("Releasing lock for user: %s. Result: %d", userlock, ret); asprintf(&errormsg, "Unable to initialize libuser: %s\n", lu_strerror(error)); return CMPI_RC_ERR_FAILED; } @@ -535,27 +580,28 @@ static CMPIrc delete_user( goto clean; } + /* Be really safe here, it can delete ANY directory */ + /* Actually, if user have / set as home directory + and removing is forced... */ if (deletehome) { - home = aux_lu_get_str(lue, LU_HOMEDIRECTORY); - /* Be really safe here, it can delete ANY directory */ - /* Delete home dir only if the directory is owned by the user */ - struct stat buf; - if (stat(home, &buf)) { - asprintf(&errormsg, "User's homedir %s could not be deleted: %s\n", - home, strerror(errno)); + gboolean ret = FALSE; + if (force) { + /* Force remove home dir even if the user is NOT owner */ + ret = lu_homedir_remove_for_user(lue, &error); + } else { + /* Delete home dir only if the directory is owned by the user */ + ret = lu_homedir_remove_for_user_if_owned (lue, &error); + } + + if (!ret) { + const char *const home = lu_ent_get_first_string(lue, LU_HOMEDIRECTORY); + /* If null is returned then asprintf handle it. */ + asprintf(&errormsg, + "User's homedir %s could not be deleted: %s\n", home, + lu_strerror(error)); rc = CANNOT_DELETE_HOME; goto clean; } - /* Remove home dir if the user is owner or force is set */ - if (buf.st_uid == aux_lu_get_long(lue, LU_UIDNUMBER) || force) { - if (!lu_homedir_remove(home, &error)) { - asprintf(&errormsg, - "User's homedir %s could not be deleted: %s\n", home, - lu_strerror(error)); - rc = CANNOT_DELETE_HOME; - goto clean; - } - } } if (!lu_user_delete(luc, lue, &error)) { @@ -600,7 +646,11 @@ static CMPIrc delete_user( } clean: - release_lock(userlock); + /* Because C specification... */ + { + const int ret = release_user_lock(userlock); + lmi_debug("Releasing lock for user: %s. Result: %d", userlock, ret); + } lu_ent_free(lue); lu_ent_free(lueg); lu_end(luc); diff --git a/src/account/lock.c b/src/account/lock.c index a12880b..40e3d99 100644 --- a/src/account/lock.c +++ b/src/account/lock.c @@ -1,3 +1,22 @@ +/* + * Copyright (C) 2012-2013 Red Hat, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Robin Hack <rhack@redhat.com> + */ #include <string.h> #include <stdlib.h> #include <assert.h> @@ -7,55 +26,67 @@ #include "lock.h" -#define LOCK_CSEC() do { pthread_mutex_lock (&pool->csec); } while (0) -#define UNLOCK_CSEC() do { pthread_mutex_unlock (&pool->csec); } while (0) -#define RETURN_UNLOCK_CSEC(code) do { UNLOCK_CSEC(); return (code); } while (0) +static lock_pools_t pools; -static lock_pool_t *pool = NULL; +/* Critical sections lock */ +static inline void LOCK_CSEC_POOLS (void) { pthread_mutex_lock (&pools.csec); } +static inline void UNLOCK_CSEC_POOLS (void) { pthread_mutex_unlock (&pools.csec); } +static inline void LOCK_CSEC_USER (void) { pthread_mutex_lock (&pools.user_pool.csec); } +static inline void UNLOCK_CSEC_USER (void) { pthread_mutex_unlock (&pools.user_pool.csec); } +static inline void LOCK_CSEC_GROUP (void) { pthread_mutex_lock (&pools.group_pool.csec); } +static inline void UNLOCK_CSEC_GROUP (void) { pthread_mutex_unlock (&pools.group_pool.csec); } -static pthread_once_t pool_is_initialized = PTHREAD_ONCE_INIT; + +static pthread_once_t pools_are_initialized = PTHREAD_ONCE_INIT; static unsigned int ref_count = 0; /* Callbacks */ -static void new_pool (void); -static void free_lock (gpointer lock); -/**/ - -/* Internal functions */ -static int search_key (const char *const username, lock_t **lck) __attribute__((nonnull)); +static void new_pools (void); static void free_lock (gpointer lock) __attribute__((nonnull)); -static int add_key (const char *const username); -int init_lock_pool (void) +/* Internal functions */ +static int search_key (lock_pool_t *const pool, const char *const key, lock_t **lck) __attribute__((nonnull)); +static int add_key (lock_pool_t *const pool, const char *const key) __attribute__((nonnull)); +static int release_lock (lock_pool_t *const pool, const char *const key) __attribute__((nonnull)); +static int get_lock (lock_pool_t *const pool, const char *const key) __attribute__((nonnull)); + + +int init_lock_pools (void) { - pthread_once (&pool_is_initialized, new_pool); - if ( pool == NULL ) { return 0; } + pthread_once (&pools_are_initialized, new_pools); + if ( pools.initialized == 0 ) { return 0; } - LOCK_CSEC (); + LOCK_CSEC_POOLS (); ++ref_count; - if (ref_count >= UINT_MAX) { RETURN_UNLOCK_CSEC (0); } - - UNLOCK_CSEC (); + if (ref_count >= UINT_MAX) { UNLOCK_CSEC_POOLS(); return 0; } + UNLOCK_CSEC_POOLS (); return 1; } -static void new_pool (void) +static void new_pools (void) { - pool = calloc (1, sizeof (lock_pool_t)); - if ( pool == NULL ) { + memset (&pools, 0, sizeof (lock_pools_t)); + pools.user_pool.hash_table = g_hash_table_new_full (&g_str_hash, &g_str_equal, NULL, &free_lock); + if ( pools.user_pool.hash_table == NULL ) { + /* paranoia? */ + memset (&pools, 0, sizeof (lock_pools_t)); return; } - pool->hash_table = g_hash_table_new_full (&g_str_hash, &g_str_equal, NULL, &free_lock); - if ( pool->hash_table == NULL ) { - free (pool); - pool = NULL; + pools.group_pool.hash_table = g_hash_table_new_full (&g_str_hash, &g_str_equal, NULL, &free_lock); + if ( pools.group_pool.hash_table == NULL ) { + g_hash_table_destroy (pools.user_pool.hash_table); + memset (&pools, 0, sizeof (lock_pools_t)); return; } - pthread_mutex_init (&pool->csec, NULL); + pthread_mutex_init (&pools.user_pool.csec, NULL); + pthread_mutex_init (&pools.group_pool.csec, NULL); + pthread_mutex_init (&pools.csec, NULL); + + pools.initialized = 1; } static void free_lock (gpointer lock) @@ -68,115 +99,143 @@ static void free_lock (gpointer lock) free (lock); } -void destroy_lock_pool (void) +void destroy_lock_pools (void) { - assert (pool != NULL); + assert (pools.initialized == 1); - LOCK_CSEC (); + LOCK_CSEC_POOLS (); --ref_count; - if ( ref_count > 0 ) { UNLOCK_CSEC(); return; } + if ( ref_count > 0 ) { UNLOCK_CSEC_POOLS(); return; } - assert (pool->hash_table != NULL); + assert (pools.user_pool.hash_table != NULL); + assert (pools.group_pool.hash_table != NULL); /* Remove all pairs. Memory is deallocated by free_lock callback. */ - g_hash_table_destroy (pool->hash_table); + g_hash_table_destroy (pools.user_pool.hash_table); + g_hash_table_destroy (pools.group_pool.hash_table); + + /* What if mutex is locked? */ + pthread_mutex_destroy (&pools.user_pool.csec); + pthread_mutex_destroy (&pools.group_pool.csec); - UNLOCK_CSEC (); + UNLOCK_CSEC_POOLS (); - pthread_mutex_destroy (&pool->csec); - free ((void *) pool); + pthread_mutex_destroy (&pools.csec); - /* Initializae lock pool. */ - pool = NULL; - pool_is_initialized = PTHREAD_ONCE_INIT; + memset (&pools, 0, sizeof (lock_pools_t)); + + pools_are_initialized = PTHREAD_ONCE_INIT; } /* search for keys */ -static int search_key (const char *const username, lock_t **lck) +static int search_key (lock_pool_t *const pool, const char *const username, lock_t **lck) { assert (pool != NULL); *lck = (lock_t *) g_hash_table_lookup (pool->hash_table, username); - - if ( *lck != NULL ) { - return 1; - } + if ( *lck != NULL ) { return 1; } return 0; } -static int add_key (const char *const username) +static int add_key (lock_pool_t *const pool, const char *const key) { assert (pool != NULL); lock_t *const new_lock = calloc (1, sizeof (lock_t)); - if ( new_lock == NULL ) { - return 0; - } + if ( new_lock == NULL ) { return 0; } pthread_mutex_init (&new_lock->mutex, NULL); pthread_mutex_lock (&new_lock->mutex); new_lock->instances = 1; /* -1 for null char */ - strncpy (new_lock->id, username, sizeof (new_lock->id) - 1); + strncpy (new_lock->id, key, sizeof (new_lock->id) - 1); g_hash_table_insert (pool->hash_table, (gpointer) new_lock->id, new_lock); return 1; } -int get_lock (const char *const username) +int get_user_lock (const char *const username) +{ + assert (pools.initialized == 1); + + LOCK_CSEC_USER (); + lock_pool_t *const pool = &pools.user_pool; + const int ret = get_lock (pool, username); + UNLOCK_CSEC_USER (); + return ret; +} + +int get_group_lock (const char *const groupname) +{ + assert (pools.initialized == 1); + + LOCK_CSEC_GROUP (); + lock_pool_t *const pool = &pools.group_pool; + const int ret = get_lock (pool, groupname); + UNLOCK_CSEC_GROUP (); + return ret; +} + +static int get_lock (lock_pool_t *const pool, const char *const key) { assert (pool != NULL); - LOCK_CSEC (); - /* - * Global critical section - */ lock_t *lck = NULL; - int ret = search_key (username, &lck); + int ret = search_key (pool, key, &lck); if ( ret == 1 ) { assert (lck != NULL); pthread_mutex_t *const mutex = &lck->mutex; - if ( lck->instances >= UINT_MAX ) { - RETURN_UNLOCK_CSEC (0); - } + if ( lck->instances >= UINT_MAX ) { return 0; } ++lck->instances; - /* Unlock global critical section */ - UNLOCK_CSEC (); - - /* lock */ + /* This will raise warning in covscan. + But I just want return locked mutex. */ pthread_mutex_lock (mutex); return 1; } /* no keys found - add new key to list */ - ret = add_key (username); - RETURN_UNLOCK_CSEC (ret); + return (add_key (pool, key)); } -int release_lock (const char *const username) +int release_user_lock (const char *const username) { - /* Critical section */ - assert (pool != NULL); - LOCK_CSEC (); + assert (pools.initialized == 1); + LOCK_CSEC_USER (); + lock_pool_t *const pool = &pools.user_pool; + const int ret = release_lock (pool, username); + UNLOCK_CSEC_USER (); + return ret; +} - lock_t *lck = NULL; - int ret = search_key (username, &lck); +int release_group_lock (const char *const groupname) +{ + assert (pools.initialized == 1); + LOCK_CSEC_GROUP (); + lock_pool_t *const pool = &pools.group_pool; + const int ret = release_lock (pool, groupname); + UNLOCK_CSEC_GROUP (); + return ret; +} - /* Also exit of critical section */ - if ( ret == 0 ) { RETURN_UNLOCK_CSEC (ret); } +static int release_lock (lock_pool_t *const pool, const char *const key) +{ + assert (pool != NULL); + lock_t *lck = NULL; + int ret = search_key (pool, key, &lck); + if ( ret == 0 ) { return ret; } assert (lck != NULL); --lck->instances; if ( lck->instances > 0 ) { pthread_mutex_unlock (&lck->mutex); - RETURN_UNLOCK_CSEC (ret); + return ret; } - g_hash_table_remove (pool->hash_table, (gpointer) username); + g_hash_table_remove (pool->hash_table, (gpointer) key); - RETURN_UNLOCK_CSEC (ret); + return ret; } diff --git a/src/account/lock.h b/src/account/lock.h index 84b9b0d..036d4ab 100644 --- a/src/account/lock.h +++ b/src/account/lock.h @@ -1,3 +1,22 @@ +/* + * Copyright (C) 2012-2013 Red Hat, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Robin Hack <rhack@redhat.com> + */ #ifndef _LOCK_H #define _LOCK_H @@ -18,10 +37,19 @@ typedef struct lock_pool { pthread_mutex_t csec; } lock_pool_t; -int init_lock_pool (void) __attribute__((warn_unused_result)); +typedef struct lock_pools { + lock_pool_t user_pool; + lock_pool_t group_pool; + int initialized; + pthread_mutex_t csec; +} lock_pools_t; + +int init_lock_pools (void) __attribute__((warn_unused_result)); +void destroy_lock_pools (void); -void destroy_lock_pool (void); -int get_lock (const char *const username) __attribute__((nonnull)); -int release_lock (const char *const username) __attribute__((nonnull)); +int get_user_lock (const char *const username) __attribute__((nonnull)); +int get_group_lock (const char *const groupname) __attribute__((nonnull)); +int release_user_lock (const char *const username) __attribute__((nonnull)); +int release_group_lock (const char *const username) __attribute__((nonnull)); #endif /* _LOCK_H */ |