Hi Andrew,

On 02/23/10 17:23, Yan Gao wrote:
> On 02/23/10 04:10, Andrew Beekhof wrote:
>> On Mon, Feb 22, 2010 at 8:58 AM, Yan Gao <y...@novell.com> wrote:
>>> Hi Andrew,
>>>
>>> On 02/08/10 17:48, Andrew Beekhof wrote:
>>>> On Thu, Feb 4, 2010 at 5:24 PM, Yan Gao <y...@novell.com> wrote:
>>>>>> And put exclusions for things like passwords before  the read for the 
>>>>>> whole cib?
>>>>> Yes. We should specify any "deny" and "write" objects before it.
>>>>
>>>> I like the syntax now, but my original concern (that all the
>>>> validation occurs in the client library) remains... so this still
>>>> isn't providing any real security.
>>> Right. If it's impossible for cib to run as root,
>>
>> If you need root for this, I think we can allow that change for 1.1.
>>
> Great! So PAM is still preferred. Anyway, I'll have a dig at different
> ways. I think we can make that change when the authentication is ready,
> and if it's necessary.
After investigating, I found that Unix domain sockets provide methods to
identify the user on the other side of a socket. That means we don't need
PAM to do authentication for local access, and the clients doesn't need
to prompt user to input and transfer username/password to the server.
And cib daemon still can run as "hacluster".

I've improved the ipcsocket library of cluster-glue to record user's identity
info for cib to use.

The behavior of remote access to the cib is still like before.

Attached the patch for cluster-glue and the updated patch for pacemaker. Looking
forward to your review and comments. Thanks!


BTW, a little revision of devel branch:

diff -r f78972892449 configure.ac
--- a/configure.ac      Wed Mar 17 16:03:23 2010 +0800
+++ b/configure.ac      Wed Mar 17 16:19:06 2010 +0800
@@ -431,7 +431,7 @@

 dnl Create symlinks to here from CRM_DAEMON_DIR when needed
 HB_DAEMON_DIR=`extract_header_define $GLUE_HEADER HA_LIBHBDIR`
-AC_DEFINE_UNQUOTED(HB_DAEMON_DIR,"HB_DAEMON_DIR", Location for Heartbeat 
expects Pacemaker daemons to be in)
+AC_DEFINE_UNQUOTED(HB_DAEMON_DIR,"$HB_DAEMON_DIR", Location for Heartbeat 
expects Pacemaker daemons to be in)
 AC_SUBST(HB_DAEMON_DIR)

 dnl Needed so that the AIS plugin can clear out the directory as Heartbeat does


Regards,
  Yan
-- 
Yan Gao <y...@novell.com>
Software Engineer
China Server Team, OPS Engineering, Novell, Inc.
# HG changeset patch
# User Yan Gao <y...@novell.com>
# Date 1268813003 -28800
# Node ID f78972892449bdd7d26f7404ea09b5c4db8cca29
# Parent  628b184a9047f47bfe2b50be157a1566ab03d9ad
Dev: cib: Implement multi-level ACLs for the CIB

diff -r 628b184a9047 -r f78972892449 cib/callbacks.c
--- a/cib/callbacks.c	Thu Mar 11 10:51:18 2010 +0100
+++ b/cib/callbacks.c	Wed Mar 17 16:03:23 2010 +0800
@@ -26,6 +26,7 @@
 #include <stdlib.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <pwd.h>
 
 #include <crm/crm.h>
 #include <crm/cib.h>
@@ -298,8 +299,20 @@
 		    }
 		}
 
+		if(cib_client->user == NULL) {
+		    struct passwd *pwent = NULL;
+
+		    pwent = getpwuid(channel->farside_uid);
+		    if (pwent == NULL) {
+			crm_perror(LOG_ERR, "Cannot get password entry of uid: %d", channel->farside_uid);
+		    } else {
+			cib_client->user = crm_strdup(pwent->pw_name);
+		    }
+		}
+
 		crm_xml_add(op_request, F_CIB_CLIENTID, cib_client->id);
 		crm_xml_add(op_request, F_CIB_CLIENTNAME, cib_client->name);
+		crm_xml_add(op_request, F_CIB_USER, cib_client->user);
 		/* crm_log_xml(LOG_MSG, "Client[inbound]", op_request); */
 
 		if(cib_client->callback_id == NULL) {
@@ -794,6 +807,7 @@
     xmlNode *output      = NULL;
     xmlNode *result_cib  = NULL;
     xmlNode *current_cib = NULL;
+    xmlNode *filtered_current_cib = NULL;
 	
     int call_type    = 0;
     int call_options = 0;
@@ -835,9 +849,20 @@
 	goto done;
 		
     } else if(cib_op_modifies(call_type) == FALSE) {
-	rc = cib_perform_op(op, call_options, cib_op_func(call_type), TRUE,
+	if (acl_filter_cib(request, current_cib, current_cib, &filtered_current_cib) == FALSE) {
+	    rc = cib_perform_op(op, call_options, cib_op_func(call_type), TRUE,
 			    section, request, input, FALSE, &config_changed,
 			    current_cib, &result_cib, NULL, &output);
+	} else {
+	    crm_debug("Pre-filtered the queried cib according to the ACLs");
+	    if (filtered_current_cib == NULL) {
+		rc = cib_permission_denied;
+	    } else {
+		rc = cib_perform_op(op, call_options, cib_op_func(call_type), TRUE,
+				section, request, input, FALSE, &config_changed,
+				filtered_current_cib, &result_cib, NULL, &output);
+	    }
+	}
 
 	CRM_CHECK(result_cib == NULL, free_xml(result_cib));
 	goto done;
@@ -874,6 +899,10 @@
 	    *cib_diff = diff_cib_object(current_cib, result_cib, FALSE);
 	    config_changed = cib_config_changed(*cib_diff);
 	}
+
+	if (acl_check_diff(request, current_cib, result_cib, *cib_diff) == FALSE) {
+	    rc = cib_permission_denied;
+	}
     }    
     
     if(rc == cib_ok) {
@@ -898,11 +927,22 @@
 	}
 
     } else if(rc == cib_dtd_validation) {
+	xmlNode *filtered_result_cib = NULL;
+
 	if(output != NULL) {
 	    crm_log_xml_info(output, "cib:output");
 	    free_xml(output);
 	} 
-	output = result_cib;
+
+	if (acl_filter_cib(request, current_cib, result_cib, &filtered_result_cib) == FALSE) {
+	    output = result_cib;
+	} else {
+	    crm_debug("Filtered the result cib for output according to the ACLs");
+	    output = filtered_result_cib;
+	    if (result_cib != NULL) {
+		free_xml(result_cib);
+	    }
+	}
 
     } else {
 	free_xml(result_cib);    
@@ -948,6 +988,10 @@
 	/* crm_log_xml_info(*reply, "cib:reply"); */
     }
 
+    if (filtered_current_cib != NULL) {
+	free_xml(filtered_current_cib);
+    }
+
     if(call_type >= 0) {
 	cib_op_cleanup(call_type, call_options, &input, &output);
     }
diff -r 628b184a9047 -r f78972892449 cib/callbacks.h
--- a/cib/callbacks.h	Thu Mar 11 10:51:18 2010 +0100
+++ b/cib/callbacks.h	Wed Mar 17 16:03:23 2010 +0800
@@ -34,6 +34,7 @@
 		char  *id;
 		char  *name;
 		char  *callback_id;
+		char  *user;
 
 		const char  *channel_name;
 
diff -r 628b184a9047 -r f78972892449 cib/remote.c
--- a/cib/remote.c	Thu Mar 11 10:51:18 2010 +0100
+++ b/cib/remote.c	Wed Mar 17 16:03:23 2010 +0800
@@ -289,6 +289,8 @@
 
 	CRM_CHECK(new_client->id == NULL, crm_free(new_client->id));
 	new_client->id = crm_strdup(uuid_str);
+
+	new_client->user = crm_strdup(user);
 	
 	new_client->callback_id = NULL;
 	if(ssock == remote_tls_fd) {
@@ -377,6 +379,7 @@
 	crm_xml_add(command, F_TYPE, T_CIB);
 	crm_xml_add(command, F_CIB_CLIENTID, client->id);
 	crm_xml_add(command, F_CIB_CLIENTNAME, client->name);
+	crm_xml_add(command, F_CIB_USER, client->user);
 	
 	if(crm_element_value(command, F_CIB_CALLID) == NULL) {
 	    cl_uuid_t call_id;
diff -r 628b184a9047 -r f78972892449 include/crm/cib.h
--- a/include/crm/cib.h	Thu Mar 11 10:51:18 2010 +0100
+++ b/include/crm/cib.h	Wed Mar 17 16:03:23 2010 +0800
@@ -120,6 +120,7 @@
 	cib_bad_config		= -51,
 	cib_invalid_argument	= -52,
 	cib_transform_failed    = -53,
+	cib_permission_denied	= -54,
 };
 
 enum cib_update_op {
@@ -182,6 +183,7 @@
 #define F_CIB_NOTIFY_TYPE	"cib_notify_type"
 #define F_CIB_NOTIFY_ACTIVATE	"cib_notify_activate"
 #define F_CIB_UPDATE_DIFF	"cib_update_diff"
+#define F_CIB_USER		"cib_user"
 
 #define T_CIB			"cib"
 #define T_CIB_NOTIFY		"cib_notify"
diff -r 628b184a9047 -r f78972892449 include/crm/msg_xml.h
--- a/include/crm/msg_xml.h	Thu Mar 11 10:51:18 2010 +0100
+++ b/include/crm/msg_xml.h	Wed Mar 17 16:03:23 2010 +0800
@@ -118,6 +118,7 @@
 #define XML_CIB_TAG_CRMCONFIG   	"crm_config"
 #define XML_CIB_TAG_OPCONFIG		"op_defaults"
 #define XML_CIB_TAG_RSCCONFIG   	"rsc_defaults"
+#define XML_CIB_TAG_ACLS   		"acls"
 
 #define XML_CIB_TAG_STATE         	"node_state"
 #define XML_CIB_TAG_NODE          	"node"
@@ -264,6 +265,17 @@
 #define XML_TAG_DIFF_ADDED		"diff-added"
 #define XML_TAG_DIFF_REMOVED		"diff-removed"
 
+#define XML_ACL_TAG_USER		"user"
+#define XML_ACL_TAG_ROLE		"role"
+#define XML_ACL_ATTR_ROLE		"role"
+#define XML_ACL_TAG_READ		"read"
+#define XML_ACL_TAG_WRITE		"write"
+#define XML_ACL_TAG_DENY		"deny"
+#define XML_ACL_ATTR_REF		"ref"
+#define XML_ACL_ATTR_TAG		"tag"
+#define XML_ACL_ATTR_XPATH		"xpath"
+#define XML_ACL_ATTR_ATTRIBUTE		"attribute"
+
 #include <crm/common/xml.h> 
 
 #define ID(x) crm_element_value(x, XML_ATTR_ID)
diff -r 628b184a9047 -r f78972892449 lib/cib/Makefile.am
--- a/lib/cib/Makefile.am	Thu Mar 11 10:51:18 2010 +0100
+++ b/lib/cib/Makefile.am	Wed Mar 17 16:03:23 2010 +0800
@@ -26,7 +26,7 @@
 ## SOURCES
 noinst_HEADERS		= cib_private.h
 libcib_la_SOURCES	= cib_ops.c cib_utils.c cib_client.c cib_native.c cib_attrs.c \
-			cib_version.c cib_file.c cib_remote.c
+			cib_version.c cib_file.c cib_remote.c cib_acl.c
 
 libcib_la_LDFLAGS	= -version-info 1:1:0 $(top_builddir)/lib/common/libcrmcommon.la $(CRYPTOLIB)
 libcib_la_CFLAGS	= -I$(top_srcdir)
diff -r 628b184a9047 -r f78972892449 lib/cib/cib_acl.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/cib/cib_acl.c	Wed Mar 17 16:03:23 2010 +0800
@@ -0,0 +1,735 @@
+/* 
+ * Copyright (C) 2009 Yan Gao <y...@novell.com>
+ * 
+ * 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.1 of the License, or (at your option) any later version.
+ * 
+ * This software 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.
+ * 
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <pwd.h>
+
+#include <crm/cib.h>
+#include <cib_private.h>
+
+typedef struct acl_obj_s
+{
+	const char *mode;
+	const char *tag;
+	const char *ref;
+	const char *xpath;
+	const char *attribute;
+} acl_obj_t;
+
+typedef struct xml_perm_s
+{
+	const char *mode;
+	GHashTable *attribute_perms;
+} xml_perm_t;
+
+static gboolean req_by_superuser(xmlNode *request);
+
+static gboolean unpack_user_acl(xmlNode *xml_acls, const char *user, GListPtr *user_acl);
+static gboolean user_match(const char *user, const char *uid);
+static gboolean unpack_acl(xmlNode *xml_acls, xmlNode *xml_acl, GListPtr *acl);
+static gboolean unpack_role_acl(xmlNode *xml_acls, const char *role, GListPtr *acl);
+static gboolean acl_append(xmlNode *acl_child, GListPtr *acl);
+static void free_acl(GListPtr acl);
+static gboolean parse_acl_xpath(xmlNode *xml, GListPtr acl, GListPtr *parsed_acl);
+
+static gboolean gen_xml_perms(xmlNode *xml, GListPtr acl, GHashTable **xml_perms);
+static int search_xml_children(GListPtr *children, xmlNode *root,
+                  const char *tag, const char *field, const char *value,
+                  gboolean search_matches);
+static int search_xpath_objects(GListPtr *objects, xmlNode *xml_obj, const char *xpath);
+static gboolean update_xml_perms(xmlNode *xml, acl_obj_t *acl_obj, GHashTable *xml_perms);
+static gboolean update_xml_children_perms(xmlNode *xml, const char *mode, GHashTable *xml_perms);
+static void free_xml_perm(gpointer xml_perm);
+
+static gboolean acl_filter_xml(xmlNode *xml, GHashTable *xml_perms);
+static gboolean acl_check_diff_xml(xmlNode *xml, GHashTable *xml_perms);
+
+
+/* rc = TRUE if orig_cib has been filtered*/
+/* That means *filtered_cib rather than orig_cib should be exploited afterwards*/
+gboolean
+acl_filter_cib(xmlNode *request, xmlNode *current_cib, xmlNode *orig_cib, xmlNode **filtered_cib)
+{
+	const char *user = NULL;
+	xmlNode *xml_acls = NULL;
+	xmlNode *tmp_cib = NULL;
+	GListPtr user_acl = NULL;
+	GHashTable *xml_perms = NULL;
+
+	*filtered_cib = NULL;
+
+	if (req_by_superuser(request)) {
+		return FALSE;
+	}
+
+	if (orig_cib == NULL) {
+		return FALSE;
+	}
+
+	if (current_cib == NULL) {
+		return TRUE;
+	}
+
+	user = crm_element_value(request, F_CIB_USER);
+	if (user == NULL) {
+		crm_warn("Cannot identify the client user");
+		return TRUE;
+	}
+
+	xml_acls = get_object_root(XML_CIB_TAG_ACLS, current_cib);
+	if (xml_acls == NULL) {
+		crm_warn("Ordinary users cannot access the CIB without any defined ACLs: '%s'", user);
+		return TRUE;
+	}
+
+	unpack_user_acl(xml_acls, user, &user_acl);
+
+	tmp_cib = copy_xml(orig_cib);
+
+	gen_xml_perms(tmp_cib, user_acl, &xml_perms);
+
+	if (acl_filter_xml(tmp_cib, xml_perms)) {
+		crm_debug("User '%s' doesn't have the permission for the whole CIB", user);
+		tmp_cib = NULL;
+	}
+
+	g_hash_table_destroy(xml_perms);
+	free_acl(user_acl);
+	
+	*filtered_cib = tmp_cib;
+	return TRUE;
+}
+
+/* rc = TRUE if the request passes the ACL check */
+/* rc = FALSE if the permission is denied */
+gboolean
+acl_check_diff(xmlNode *request, xmlNode *current_cib, xmlNode *result_cib, xmlNode *diff)
+{
+	const char *user = NULL;
+	xmlNode *xml_acls = NULL;
+	GListPtr user_acl = NULL;
+	int rc = FALSE;
+
+	if (req_by_superuser(request)) {
+		return TRUE;
+	}
+
+	if (diff == NULL) {
+		return TRUE;
+	}
+
+	if (current_cib == NULL) {
+		return FALSE;
+	}
+
+	user = crm_element_value(request, F_CIB_USER);
+	if (user == NULL) {
+		crm_warn("Cannot identify the client user");
+		return FALSE;
+	}
+
+	xml_acls = get_object_root(XML_CIB_TAG_ACLS, current_cib);
+	if (xml_acls == NULL) {
+		crm_warn("Ordinary users cannot access the CIB without any defined ACLs: '%s'", user);
+		return FALSE;
+	}
+
+	unpack_user_acl(xml_acls, user, &user_acl);
+
+	xml_child_iter(
+		diff, diff_child,
+		const char *tag = crm_element_name(diff_child);
+		GListPtr parsed_acl = NULL;
+
+		crm_debug("Preparing ACL checking on '%s'", tag);
+
+		if (crm_str_eq(tag, XML_TAG_DIFF_REMOVED, TRUE)) {
+			crm_debug("Parsing any xpaths under the ACL according to the current CIB");
+			parse_acl_xpath(current_cib, user_acl, &parsed_acl);
+		} else if (crm_str_eq(tag, XML_TAG_DIFF_ADDED, TRUE)) {
+			crm_debug("Parsing any xpaths under the ACL according to the result CIB");
+			parse_acl_xpath(result_cib, user_acl, &parsed_acl);
+		} else {
+			continue;
+		}
+
+		xml_child_iter(
+			diff_child, diff_cib,
+			GHashTable *xml_perms = NULL;
+
+			gen_xml_perms(diff_cib, parsed_acl, &xml_perms);
+			rc = acl_check_diff_xml(diff_cib, xml_perms);
+			g_hash_table_destroy(xml_perms);
+
+			if (rc == FALSE) {
+				crm_warn("User '%s' doesn't have the permission to modify the CIB", user);
+				goto done;
+			}
+			);
+		free_acl(parsed_acl);
+		);
+
+done:
+	free_acl(user_acl);
+	return rc;
+}
+
+static gboolean
+req_by_superuser(xmlNode *request)
+{
+	const char *user = crm_element_value(request, F_CIB_USER);
+	if (crm_str_eq(user, CRM_DAEMON_USER, TRUE)
+			|| crm_str_eq(user, "root", TRUE)) {
+		return TRUE;
+	}
+	return FALSE;
+}
+
+static gboolean
+unpack_user_acl(xmlNode *xml_acls, const char *user, GListPtr *user_acl)
+{
+	if (xml_acls == NULL) {
+		return FALSE;
+	}
+	
+	xml_child_iter(
+        	xml_acls, xml_acl,
+		const char *tag = crm_element_name(xml_acl);
+		const char *id = crm_element_value(xml_acl, XML_ATTR_ID);
+
+		if (crm_str_eq(tag, XML_ACL_TAG_USER, TRUE)) {
+			if (user_match(user, id)) {
+				crm_debug("Unpacking ACL of user: '%s'", id);
+				unpack_acl(xml_acls, xml_acl, user_acl);
+				return TRUE;
+			}
+		}
+		);
+	return FALSE;
+}
+
+static gboolean
+user_match(const char *user, const char *uid)
+{
+	struct passwd *pwent = NULL;
+	int user_uid_num = -1;
+	int uid_num = -1;
+
+	if (crm_str_eq(user, uid, TRUE)) {
+		return TRUE;
+	}
+
+	pwent = getpwnam(user);
+	if (pwent == NULL) {
+		crm_warn("No user named '%s' exists!", user);
+		return FALSE;
+	}
+	user_uid_num = pwent->pw_uid;
+
+	uid_num = crm_int_helper(uid, NULL);
+	if(errno == 0 && uid_num == user_uid_num) {
+		return TRUE;
+        }
+
+	return FALSE;
+}
+
+static gboolean
+unpack_acl(xmlNode *xml_acls, xmlNode *xml_acl, GListPtr *acl)
+{
+	const char *role = crm_element_value(xml_acl, XML_ACL_ATTR_ROLE);
+
+	if (role) {
+		unpack_role_acl(xml_acls, role, acl);
+	}
+
+	xml_child_iter(
+		xml_acl, acl_child,
+		const char *tag = crm_element_name(acl_child);
+
+		if (crm_str_eq(XML_ACL_TAG_READ, tag, TRUE)
+			|| crm_str_eq(XML_ACL_TAG_WRITE, tag, TRUE)
+			|| crm_str_eq(XML_ACL_TAG_DENY, tag, TRUE))
+				acl_append(acl_child, acl);
+		);
+	return TRUE;
+}
+
+static gboolean
+unpack_role_acl(xmlNode *xml_acls, const char *role, GListPtr *acl)
+{
+	xml_child_iter_filter(
+        	xml_acls, xml_acl, XML_ACL_TAG_ROLE,
+		const char *role_id = crm_element_value(xml_acl, XML_ATTR_ID);
+
+		if (role_id && crm_str_eq(role, role_id, TRUE)) {
+			crm_debug("Unpacking ACL of the referenced role: '%s'", role);
+			unpack_acl(xml_acls, xml_acl, acl);
+			return TRUE;
+		}
+		);
+	return FALSE;
+}
+
+static gboolean
+acl_append(xmlNode *acl_child, GListPtr *acl)
+{
+	acl_obj_t *acl_obj = NULL;
+
+	const char *tag = crm_element_value(acl_child, XML_ACL_ATTR_TAG);
+	const char *ref = crm_element_value(acl_child, XML_ACL_ATTR_REF);
+	const char *xpath = crm_element_value(acl_child, XML_ACL_ATTR_XPATH);
+
+	if (tag == NULL && ref == NULL && xpath == NULL) {
+		return FALSE;
+	}
+
+	crm_malloc0(acl_obj, sizeof(acl_obj_t));
+	if (acl_obj == NULL) {
+		return FALSE;
+	}
+
+	acl_obj->mode = crm_element_name(acl_child);
+	acl_obj->tag = tag;
+	acl_obj->ref = ref;
+	acl_obj->xpath = xpath;
+	acl_obj->attribute = crm_element_value(acl_child, XML_ACL_ATTR_ATTRIBUTE);
+
+	*acl = g_list_append(*acl, acl_obj);
+
+	crm_debug_3("ACL object appended: mode=%s, tag=%s, ref=%s, xpath=%s, attribute=%s",
+			acl_obj->mode, acl_obj->tag, acl_obj->ref, acl_obj->xpath, acl_obj->attribute);
+
+	return TRUE;
+}
+
+static void
+free_acl(GListPtr acl)
+{
+	GListPtr iterator = acl;
+	while(iterator != NULL) {
+		crm_free(iterator->data);
+		iterator = iterator->next;
+	}
+	if(acl != NULL) {
+		g_list_free(acl);
+	}
+}
+
+static gboolean
+parse_acl_xpath(xmlNode *xml, GListPtr acl, GListPtr *parsed_acl)
+{
+	GListPtr acl_iterator = acl;
+	acl_obj_t *new_acl_obj = NULL;
+	
+	*parsed_acl = NULL;
+
+	while (acl_iterator != NULL) {
+		acl_obj_t *acl_obj = acl_iterator->data;
+
+		if (acl_obj->tag || acl_obj->ref) {
+			crm_malloc0(new_acl_obj, sizeof(acl_obj_t));
+			if (new_acl_obj == NULL) {
+				return  FALSE;
+			}
+
+			memcpy(new_acl_obj, acl_obj, sizeof(acl_obj_t));
+
+			*parsed_acl = g_list_append(*parsed_acl, new_acl_obj);
+
+			crm_debug_3("Copied ACL object: mode=%s, tag=%s, ref=%s, xpath=%s, attribute=%s",
+					new_acl_obj->mode, new_acl_obj->tag, new_acl_obj->ref,
+					new_acl_obj->xpath, new_acl_obj->attribute);
+
+		} else if (acl_obj->xpath) {
+			GListPtr children = NULL;
+			GListPtr children_iterator = NULL;
+
+			search_xpath_objects(&children, xml, acl_obj->xpath);
+
+			children_iterator = children;
+			while (children_iterator != NULL) {
+				crm_malloc0(new_acl_obj, sizeof(acl_obj_t));
+				if (new_acl_obj == NULL) {
+					return  FALSE;
+				}
+
+				new_acl_obj->mode = acl_obj->mode;
+				new_acl_obj->tag = crm_element_name(children_iterator->data);
+				new_acl_obj->ref = crm_element_value(children_iterator->data, XML_ATTR_ID);
+				new_acl_obj->attribute = acl_obj->attribute;
+
+				*parsed_acl = g_list_append(*parsed_acl, new_acl_obj);
+
+				crm_debug_3("Parsed the ACL object with xpath '%s' to: mode=%s, tag=%s, ref=%s, xpath=%s, attribute=%s",
+						acl_obj->xpath, new_acl_obj->mode, new_acl_obj->tag,
+						new_acl_obj->ref, new_acl_obj->xpath, new_acl_obj->attribute);
+
+				children_iterator = children_iterator->next;
+			}
+			g_list_free(children);
+		}
+		acl_iterator = acl_iterator->next;
+	}
+
+	return TRUE;
+}
+
+static gboolean
+gen_xml_perms(xmlNode *xml, GListPtr acl, GHashTable **xml_perms)
+{
+	GListPtr acl_iterator = acl;
+
+	if (*xml_perms == NULL) {
+		*xml_perms = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, free_xml_perm);
+	}
+
+	while (acl_iterator != NULL) {
+		acl_obj_t *acl_obj = acl_iterator->data;
+		GListPtr children = NULL;
+		GListPtr children_iterator = NULL;
+
+		crm_debug("Generating permissions with ACL: mode=%s, tag=%s, ref=%s, xpath=%s, attribute=%s",
+				acl_obj->mode, acl_obj->tag, acl_obj->ref, acl_obj->xpath, acl_obj->attribute);
+		if (acl_obj->tag || acl_obj->ref) {
+			search_xml_children(&children, xml, acl_obj->tag, XML_ATTR_ID, acl_obj->ref, TRUE);
+
+		} else if (acl_obj->xpath) {
+			/* Never be here for a modification operation */
+			/* Already parse_acl_xpath() previously */
+			search_xpath_objects(&children, xml, acl_obj->xpath);
+		}
+
+		children_iterator = children;
+		while (children_iterator != NULL) {
+			update_xml_perms(children_iterator->data, acl_obj, *xml_perms);
+
+			children_iterator = children_iterator->next;
+		}
+		g_list_free(children);
+
+		acl_iterator = acl_iterator->next;
+	}
+	
+	return TRUE;
+}
+
+/* Borrowed from lib/common/xml.c: find_xml_children() */
+/* But adding the original xmlNode pointers into a GList */
+static int
+search_xml_children(GListPtr *children, xmlNode *root,
+		  const char *tag, const char *field, const char *value,
+		  gboolean search_matches)
+{
+	int match_found = 0;
+	
+	CRM_CHECK(root != NULL, return FALSE);
+	CRM_CHECK(children != NULL, return FALSE);
+	
+	if(tag != NULL && safe_str_neq(tag, crm_element_name(root))) {
+
+	} else if(value != NULL
+		  && safe_str_neq(value, crm_element_value(root, field))) {
+
+	} else {
+		*children = g_list_append(*children, root);
+		match_found = 1;
+	}
+
+	if(search_matches || match_found == 0) {
+		xml_child_iter(
+			root, child, 
+			match_found += search_xml_children(
+				children, child, tag, field, value,
+				search_matches);
+			);
+	}
+	
+	return match_found;
+}
+
+static int
+search_xpath_objects(GListPtr *objects, xmlNode *xml_obj, const char *xpath)
+{
+	int match_found = 0;
+	xmlXPathObjectPtr xpathObj = NULL;
+
+	if(xpath == NULL) {
+		return 0;
+	}
+
+	xpathObj = xpath_search(xml_obj, xpath);
+
+	if(xpathObj == NULL || xpathObj->nodesetval == NULL || xpathObj->nodesetval->nodeNr < 1) {
+		crm_debug("No match for %s in %s", xpath, xmlGetNodePath(xml_obj));
+
+	} else if(xpathObj->nodesetval->nodeNr > 0) {
+		int lpc = 0, max = xpathObj->nodesetval->nodeNr;
+
+		for(lpc = 0; lpc < max; lpc++) {
+			xmlNode *match = getXpathResult(xpathObj, lpc);
+			if (match == NULL) {
+				continue;
+			}
+
+			*objects = g_list_append(*objects, match);
+			match_found++;
+		}
+	}
+
+	if(xpathObj) {
+		xmlXPathFreeObject(xpathObj);
+	}
+	return match_found;
+}
+
+static gboolean
+update_xml_perms(xmlNode *xml, acl_obj_t *acl_obj, GHashTable *xml_perms)
+{
+	xml_perm_t *perm = NULL;
+
+	if (g_hash_table_lookup_extended(xml_perms, xml, NULL, (gpointer)&perm)) {
+		if (perm->mode != NULL) {
+			return FALSE;
+		}
+	} else {
+		crm_malloc0(perm, sizeof(xml_perm_t));
+		if (perm == NULL) {
+			return FALSE;
+		}
+		g_hash_table_insert(xml_perms, xml, perm);
+	}
+
+	if (acl_obj->attribute == NULL) {
+		perm->mode = acl_obj->mode;
+		crm_debug_3("Permission for element: element_mode=%s, tag=%s, id=%s",
+                                perm->mode, crm_element_name(xml), crm_element_value(xml, XML_ATTR_ID));
+
+		xml_child_iter(
+			xml, child,
+			update_xml_children_perms(child, perm->mode, xml_perms);
+			);
+
+	} else {
+		if (perm->attribute_perms == NULL
+				|| (g_hash_table_lookup_extended(perm->attribute_perms, 
+					acl_obj->attribute, NULL, NULL) == FALSE)) {
+
+			if (perm->attribute_perms == NULL) {
+				perm->attribute_perms = g_hash_table_new_full(
+						g_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str);
+			}
+
+			g_hash_table_insert(perm->attribute_perms,
+					crm_strdup(acl_obj->attribute), crm_strdup(acl_obj->mode));
+			crm_debug_3("Permission for attribute: attribute_mode=%s, tag=%s, id=%s attribute=%s",
+                                	acl_obj->mode, crm_element_name(xml),
+					crm_element_value(xml, XML_ATTR_ID), acl_obj->attribute);
+		}
+	}
+
+	return TRUE;
+}
+
+static gboolean
+update_xml_children_perms(xmlNode *xml, const char *mode, GHashTable *xml_perms)
+{
+	xml_perm_t *perm = NULL;
+
+	if (g_hash_table_lookup_extended(xml_perms, xml, NULL, (gpointer)&perm)) {
+		if (perm->mode != NULL) {
+			return FALSE;
+		}
+	} else {
+		crm_malloc0(perm, sizeof(xml_perm_t));
+		if (perm == NULL) {
+			return FALSE;
+		}
+		g_hash_table_insert(xml_perms, xml, perm);
+	}
+
+	perm->mode = mode;
+	crm_debug_4("Permission for child element: element_mode=%s, tag=%s, id=%s",
+			mode, crm_element_name(xml), crm_element_value(xml, XML_ATTR_ID));
+
+	xml_child_iter(
+		xml, child,
+		update_xml_children_perms(child, mode, xml_perms);
+		);
+
+	return TRUE;
+}
+
+static void
+free_xml_perm(gpointer xml_perm)
+{
+	xml_perm_t *perm = xml_perm;
+
+	if (perm == NULL) {
+		return;
+	}
+
+	if (perm->attribute_perms != NULL) {
+		g_hash_table_destroy(perm->attribute_perms);
+	}
+
+	crm_free(perm);
+}
+
+#define can_read(mode) (crm_str_eq(mode, XML_ACL_TAG_READ, TRUE) \
+			|| crm_str_eq(mode, XML_ACL_TAG_WRITE, TRUE))
+
+#define can_write(mode) crm_str_eq(mode, XML_ACL_TAG_WRITE, TRUE)
+
+/* rc = TRUE if the xml is filtered out*/
+static gboolean
+acl_filter_xml(xmlNode *xml, GHashTable *xml_perms)
+{
+	int children_counter = 0;
+	xml_perm_t *perm = NULL;
+	int allow_counter = 0;
+
+	xml_child_iter(
+		xml, child, 
+		if (acl_filter_xml(child, xml_perms) == FALSE) {
+			children_counter++;
+		}
+		);
+
+	g_hash_table_lookup_extended(xml_perms, xml, NULL, (gpointer)&perm);
+
+	if (perm == NULL) {
+		crm_debug_4("No ACL defined to read the element: tag=%s, id=%s",
+				crm_element_name(xml), crm_element_value(xml, XML_ATTR_ID));
+		goto end_filter;
+	}
+
+	if (perm->attribute_perms == NULL) {
+		if (can_read(perm->mode)) {
+			return FALSE;
+		} else {
+			crm_debug_4("No enough permission to read the element: element_mode=%s, tag=%s, id=%s",
+					 perm->mode, crm_element_name(xml), crm_element_value(xml, XML_ATTR_ID));
+			goto end_filter;
+		}
+	}
+
+	xml_prop_iter(xml, prop_name, prop_value,
+		gpointer mode = NULL;
+
+		if (g_hash_table_lookup_extended(perm->attribute_perms, prop_name, NULL, &mode)) {
+			if (can_read(mode)) {
+				allow_counter++;
+			} else {
+				xml_remove_prop(xml, prop_name);
+				crm_debug_4("Filtered out the attribute: attribute_mode=%s, tag=%s, id=%s, attribute=%s",
+						 (char *)mode, crm_element_name(xml), crm_element_value(xml, XML_ATTR_ID), prop_name);
+			}
+		} else {
+			if (can_read(perm->mode)) {
+				allow_counter++;
+			} else if (crm_str_eq(prop_name, XML_ATTR_ID, TRUE) == FALSE) {
+				xml_remove_prop(xml, prop_name);
+				crm_debug_4("Filtered out the attribute: element_mode=%s, tag=%s, id=%s, attribute=%s",
+						 perm->mode, crm_element_name(xml), crm_element_value(xml, XML_ATTR_ID), prop_name);
+			}
+		}
+		);
+
+	if (allow_counter) {
+		return FALSE;
+	}
+
+	if (can_read(perm->mode)) {
+		return FALSE;
+	}
+
+end_filter:
+	if (children_counter) {
+		crm_debug_4("Don't filter out the element (tag=%s, id=%s) because user can read its children",
+				crm_element_name(xml), crm_element_value(xml, XML_ATTR_ID));
+		return FALSE;
+	}
+
+	free_xml_from_parent(NULL, xml);
+	crm_debug_4("Filtered out the element: tag=%s, id=%s",
+			crm_element_name(xml), crm_element_value(xml, XML_ATTR_ID));
+	return TRUE;
+}
+
+static gboolean
+acl_check_diff_xml(xmlNode *xml, GHashTable *xml_perms)
+{
+	xml_perm_t *perm = NULL;
+
+	xml_child_iter(
+		xml, child, 
+		if (acl_check_diff_xml(child, xml_perms) == FALSE) {
+			return FALSE;
+		}
+		);
+
+	g_hash_table_lookup_extended(xml_perms, xml, NULL, (gpointer)&perm);
+
+	xml_prop_iter(xml, prop_name, prop_value,
+		gpointer mode = NULL;
+
+		if (crm_str_eq(crm_element_name(xml), XML_TAG_CIB, TRUE)) {
+			if (crm_str_eq(prop_name, XML_ATTR_GENERATION, TRUE)
+					|| crm_str_eq(prop_name, XML_ATTR_NUMUPDATES, TRUE)
+					|| crm_str_eq(prop_name, XML_ATTR_GENERATION_ADMIN, TRUE)) {
+				continue;
+			}
+		}
+
+		if (crm_str_eq(prop_name, XML_ATTR_ID, TRUE)) {
+			continue;
+		}
+
+		if (perm == NULL) {
+			crm_debug("No ACL defined to modify the element: tag=%s, id=%s, attribute=%s",
+					 crm_element_name(xml), crm_element_value(xml, XML_ATTR_ID), prop_name);
+			return FALSE;
+		}
+
+		if (perm->attribute_perms == NULL) {
+			if (can_write(perm->mode)) {
+				return TRUE;
+			} else {
+				crm_debug("No enough permission to modify the element: element_mode=%s, tag=%s, id=%s, attribute=%s",
+						 perm->mode, crm_element_name(xml), crm_element_value(xml, XML_ATTR_ID), prop_name);
+				return FALSE;
+			}
+		}
+
+		if (g_hash_table_lookup_extended(perm->attribute_perms, prop_name, NULL, &mode)) {
+			if (can_write(mode) == FALSE) {
+				crm_debug("No enough permission to modify the attribute: attribute_mode=%s, tag=%s, id=%s, attribute=%s",
+						 (char *)mode, crm_element_name(xml), crm_element_value(xml, XML_ATTR_ID), prop_name);
+				return FALSE;
+			}
+		} else if (can_write(perm->mode) == FALSE) {
+			crm_debug("No enough permission to modify the element and the attribute: element_mode=%s, tag=%s, id=%s, attribute=%s",
+					 perm->mode, crm_element_name(xml), crm_element_value(xml, XML_ATTR_ID), prop_name);
+			return FALSE;
+		}
+
+		);
+
+	return TRUE;
+}
+
diff -r 628b184a9047 -r f78972892449 lib/cib/cib_private.h
--- a/lib/cib/cib_private.h	Thu Mar 11 10:51:18 2010 +0100
+++ b/lib/cib/cib_private.h	Wed Mar 17 16:03:23 2010 +0800
@@ -71,5 +71,8 @@
     cib_t *cib, int call_id, int timeout, gboolean only_success, void *user_data,
     const char *callback_name, void (*callback)(xmlNode*, int, int, xmlNode*,void*));
 
+extern gboolean acl_filter_cib(xmlNode *request, xmlNode *current_cib, xmlNode *orig_cib, xmlNode **filtered_cib);
+extern gboolean acl_check_diff(xmlNode *request, xmlNode *current_cib, xmlNode *result_cib, xmlNode *diff);
+
 
 #endif
diff -r 628b184a9047 -r f78972892449 lib/cib/cib_utils.c
--- a/lib/cib/cib_utils.c	Thu Mar 11 10:51:18 2010 +0100
+++ b/lib/cib/cib_utils.c	Wed Mar 17 16:03:23 2010 +0800
@@ -56,6 +56,7 @@
     { XML_CIB_TAG_CONSTRAINTS,  "/cib/configuration", "//cib/configuration/constraints" },
     { XML_CIB_TAG_OPCONFIG,	"/cib/configuration", "//cib/configuration/op_defaults" },
     { XML_CIB_TAG_RSCCONFIG,	"/cib/configuration", "//cib/configuration/rsc_defaults" },
+    { XML_CIB_TAG_ACLS,		"/cib/configuration", "//cib/configuration/acls" },
     { XML_CIB_TAG_SECTION_ALL,  NULL,                 "//cib" },
 };
 
@@ -226,6 +227,9 @@
 		case cib_transform_failed:
 			error_msg = "Schema transform failed";
 			break;
+		case cib_permission_denied:
+			error_msg = "Permission Denied";
+			break;
 	}
 			
 	if(error_msg == NULL) {
diff -r 628b184a9047 -r f78972892449 xml/pacemaker-1.2.rng
--- a/xml/pacemaker-1.2.rng	Thu Mar 11 10:51:18 2010 +0100
+++ b/xml/pacemaker-1.2.rng	Wed Mar 17 16:03:23 2010 +0800
@@ -44,6 +44,9 @@
 	<element name="constraints">
 	  <externalRef href="constraints-1.2.rng"/>
 	</element>
+	<optional>
+	  <ref name="element-acls"/>
+	</optional>
       </interleave>
     </element>
     <element name="status">
@@ -123,4 +126,58 @@
     </zeroOrMore>
   </define>
 
+  <define name="element-acls">
+    <element name="acls">
+      <zeroOrMore>
+	<choice>
+	  <element name="user">
+	    <attribute name="id"><text/></attribute>
+	    <choice>
+	      <attribute name="role"><data type="IDREF"/></attribute>
+	      <zeroOrMore>
+		<ref name="element-acl"/>
+	      </zeroOrMore>
+	    </choice>
+	  </element>
+	  <element name="role">
+	    <attribute name="id"><data type="ID"/></attribute>
+	    <zeroOrMore>
+	      <ref name="element-acl"/>
+	    </zeroOrMore>
+	  </element>
+	</choice>
+      </zeroOrMore>
+    </element>
+  </define>
+
+  <define name="element-acl">
+    <choice>
+      <element name="read">
+	<ref name="attribute-acl"/>
+      </element>
+      <element name="write">
+	<ref name="attribute-acl"/>
+      </element>
+      <element name="deny">
+	<ref name="attribute-acl"/>
+      </element>
+    </choice>
+  </define>
+
+  <define name="attribute-acl">
+    <attribute name="id"><data type="ID"/></attribute>
+      <choice>
+	<attribute name="tag"><text/></attribute>
+	<attribute name="ref"><data type="IDREF"/></attribute>
+	<group>
+	  <attribute name="tag"><text/></attribute>
+	  <attribute name="ref"><data type="IDREF"/></attribute>
+	</group>
+	<attribute name="xpath"><text/></attribute>
+      </choice>
+      <optional>
+	<attribute name="attribute"><text/></attribute>
+      </optional>
+  </define>
+
 </grammar>
# HG changeset patch
# User Yan Gao <y...@novell.com>
# Date 1268809568 -28800
# Node ID 699b8e950cdfbf8bd3a0fea9a991474ada5c5970
# Parent  5e7284501da699c53b0154ec7169e61a178a3c3b
Dev: clplumbing: Add identity info of the user on the other side of socket

diff -r 5e7284501da6 -r 699b8e950cdf include/clplumbing/ipc.h
--- a/include/clplumbing/ipc.h	Mon Mar 15 16:03:30 2010 +0100
+++ b/include/clplumbing/ipc.h	Wed Mar 17 15:06:08 2010 +0800
@@ -132,6 +132,8 @@
 	int		ch_status;	/* identify the status of channel.*/
 	int		refcount;	/* reference count */
 	pid_t		farside_pid;	/* far side pid */
+	uid_t		farside_uid;	/* far side uid */
+	gid_t		farside_gid;	/* far side gid */
 	void*		ch_private;	/* channel private data. */
 					/* (may contain conn. info.) */
 	IPC_Ops*	ops;		/* IPC_Channel function table.*/
diff -r 5e7284501da6 -r 699b8e950cdf lib/clplumbing/ipcsocket.c
--- a/lib/clplumbing/ipcsocket.c	Mon Mar 15 16:03:30 2010 +0100
+++ b/lib/clplumbing/ipcsocket.c	Wed Mar 17 15:06:08 2010 +0800
@@ -2204,6 +2204,8 @@
   temp_ch->low_flow_mark = -1;
   temp_ch->conntype = conntype;
   temp_ch->refcount = 0;
+  temp_ch->farside_uid = -1;
+  temp_ch->farside_gid = -1;
 
   return temp_ch;
   
@@ -2341,14 +2343,20 @@
 	}
 	if (auth_info == NULL
 	||	(auth_info->uid == NULL && auth_info->gid == NULL)) {
-		return IPC_OK;    /* no restriction for authentication */
+		ret = IPC_OK;    /* no restriction for authentication */
 	  }
 
 	/* Get the credential information for our peer */
 	conn_info = (struct SOCKET_CH_PRIVATE *) ch->ch_private;
 	if (getsockopt(conn_info->s, SOL_SOCKET, SO_PEERCRED, &cred, &n) != 0
 	||	(size_t)n != sizeof(cred)) {
-		return IPC_FAIL;
+		return ret;
+	}
+
+	ch->farside_uid = cred.uid;
+	ch->farside_gid = cred.gid;
+	if (ret == IPC_OK) {
+		return ret;
 	}
 #if 0
 	cl_log(LOG_DEBUG, "SO_PEERCRED returned [%d, (%ld:%ld)]"
@@ -2419,13 +2427,19 @@
 
 	if (auth_info == NULL
 	||	(auth_info->uid == NULL && auth_info->gid == NULL)) {
-		return IPC_OK;    /* no restriction for authentication */
+		ret = IPC_OK;    /* no restriction for authentication */
 	}
 	conn_info = (struct SOCKET_CH_PRIVATE *) ch->ch_private;
 
 	if (getpeereid(conn_info->s, &euid, &egid) < 0) {
 		cl_perror("getpeereid() failure");
-		return IPC_FAIL;
+		return ret;
+	}
+
+	ch->farside_uid = euid;
+	ch->farside_gid = egid;
+	if (ret == IPC_OK) {
+		return ret;
 	}
 
 	/* Check credentials against authorization information */
@@ -2524,7 +2538,7 @@
 #endif
 
   struct SOCKET_CH_PRIVATE *conn_info;
-  int ret = IPC_OK;
+  int ret = IPC_FAIL;
   char         buf;
   
   /* Compute size without padding */
@@ -2543,7 +2557,7 @@
 
   if (auth_info == NULL
   ||	(auth_info->uid == NULL && auth_info->gid == NULL)) {
-    return IPC_OK;    /* no restriction for authentication */
+    ret = IPC_OK;    /* no restriction for authentication */
   }
   conn_info = (struct SOCKET_CH_PRIVATE *) ch->ch_private;
 
@@ -2566,12 +2580,19 @@
       || cmsg->cmsg_len < CMSGSIZE
       || cmsg->cmsg_type != SCM_CREDS) {
       cl_perror("can't get credential information from peer");
-      return IPC_FAIL;
+      return ret;
     }
 
   /* Avoid alignment issues - just copy it! */
   memcpy(&cred, CMSG_DATA(cmsg), sizeof(cred));
 
+  ch->farside_uid = cred.crEuid;
+  ch->farside_gid = cred.crEgid;
+  if (ret == IPC_OK) {
+      return ret;
+  }
+
+  ret = IPC_OK;
 
   if (	auth_info->uid
   &&	g_hash_table_lookup(auth_info->uid, &(cred.crEuid)) == NULL) {
@@ -2618,7 +2639,7 @@
 socket_verify_auth(struct IPC_CHANNEL* ch, struct IPC_AUTH * auth_info)
 {
 	int len = 0;
-	int ret = IPC_OK;
+	int ret = IPC_FAIL;
 	struct stat stat_buf;
 	struct sockaddr_un *peer_addr = NULL;
 	struct SOCKET_CH_PRIVATE *ch_private = NULL;	
@@ -2636,26 +2657,36 @@
 		
 	} else if (auth_info == NULL
 	    ||	(auth_info->uid == NULL && auth_info->gid == NULL)) {
-		return IPC_OK;    /* no restriction for authentication */
+		ret = IPC_OK;    /* no restriction for authentication */
 
-	} else if(ch_private == NULL) {
+	}
+
+	if(ch_private == NULL) {
 		cl_log(LOG_ERR, "No channel private data available");
-		return IPC_FAIL;
+		return ret;
 		
 	} else if(peer_addr == NULL) {	
 		cl_log(LOG_ERR, "No peer information available");
-		return IPC_FAIL;
+		return ret;
 	}
 	
 	len = SUN_LEN(peer_addr);
 
 	if(len < 1) {
 		cl_log(LOG_ERR, "No peer information available");
-		return IPC_FAIL;
+		return ret;
 	}
 	peer_addr->sun_path[len] = 0;
 	stat(peer_addr->sun_path, &stat_buf);
 
+	ch->farside_uid = stat_buf.st_uid;
+	ch->farside_gid = stat_buf.st_gid;
+	if (ret == IPC_OK) {
+		return ret;
+	}
+
+	ret = IPC_OK;
+
 	if ((auth_info->uid == NULL || g_hash_table_size(auth_info->uid) == 0)
 	    && auth_info->gid != NULL
 	    && g_hash_table_size(auth_info->gid) != 0) {
@@ -2704,6 +2735,9 @@
 
 	conn_info = (struct SOCKET_CH_PRIVATE *) ch->ch_private;
 
+	ch->farside_uid = conn_info->farside_uid;
+	ch->farside_gid = conn_info->farside_gid;
+
 	if (auth_info == NULL
 	  || (auth_info->uid == NULL && auth_info->gid == NULL)) {
 		return IPC_OK;	/* no restriction for authentication */
@@ -2751,12 +2785,18 @@
 
 	if (auth_info == NULL
 	  || (auth_info->uid == NULL && auth_info->gid == NULL)) {
-		return IPC_OK;	/* no restriction for authentication */
+		rc = IPC_OK;	/* no restriction for authentication */
 	}
 
 	if (getpeerucred(conn_info->s, &ucred) < 0) {
 		cl_perror("getpeereid() failure");
-		return IPC_FAIL;
+		return rc;
+	}
+
+	ch->farside_uid = ucred_geteuid(ucred);
+	ch->farside_gid = ucred_getegid(ucred);
+	if (rc == IPC_OK) {
+		return rc;
 	}
 
 	/* Check credentials against authorization information */
_______________________________________________
Pacemaker mailing list
Pacemaker@oss.clusterlabs.org
http://oss.clusterlabs.org/mailman/listinfo/pacemaker

Reply via email to