summaryrefslogtreecommitdiffstats
path: root/src/account
diff options
context:
space:
mode:
authorRobin Hack <rhack@redhat.com>2013-10-31 08:32:36 +0100
committerRobin Hack <rhack@redhat.com>2013-10-31 13:40:40 +0100
commitaac4d3a0d1dc878c1a8c11fd55e47613ec7e9050 (patch)
tree105af161789aa04f2e6b1369f766f1fbfd48e737 /src/account
parentecab16f131a16f4c01e596f86611881d1a95638f (diff)
downloadopenlmi-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.c104
-rw-r--r--src/account/lock.c209
-rw-r--r--src/account/lock.h36
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 */