[SCM] Samba Shared Repository - branch master updated - tevent-0-9-8-621-g9e85192

Nadezhda Ivanova nivanova at samba.org
Mon Sep 21 18:33:24 MDT 2009


The branch, master has been updated
       via  9e85192e6415fbaacf394330f6e61759190485ad (commit)
       via  10c6f3f71a4fe3e36e2a0476dc0077187371fafb (commit)
       via  13b979b03d86f3ae43dc5fd539fa5d3f22f579a0 (commit)
       via  025590e7a4758e86e7942642971b92fc6bab7a8e (commit)
       via  6283f2caaa42c7238bdc9c2e8bc1246207645019 (commit)
      from  b850d7fb08b97fff8ce5ec2cbff2256aa390e440 (commit)

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 9e85192e6415fbaacf394330f6e61759190485ad
Merge: 10c6f3f71a4fe3e36e2a0476dc0077187371fafb b850d7fb08b97fff8ce5ec2cbff2256aa390e440
Author: Nadezhda Ivanova <nadezhda.ivanova at postpath.com>
Date:   Mon Sep 21 17:29:28 2009 -0700

    Merge branch 'master' of git://git.samba.org/samba

commit 10c6f3f71a4fe3e36e2a0476dc0077187371fafb
Author: Nadezhda Ivanova <nadezhda.ivanova at postpath.com>
Date:   Mon Sep 21 17:27:50 2009 -0700

    Initial Implementation of the DS objects access checks.
    
    Currently disabled. The search will be greatly modified,
    also the object tree stuff will be simplified.

commit 13b979b03d86f3ae43dc5fd539fa5d3f22f579a0
Merge: 025590e7a4758e86e7942642971b92fc6bab7a8e 1afc7c453c1d5f7e761e46cdc69900305a149820
Author: Nadezhda Ivanova <nadezhda.ivanova at postpath.com>
Date:   Mon Sep 21 14:26:15 2009 -0700

    Merge branch 'master' of git://git.samba.org/samba

commit 025590e7a4758e86e7942642971b92fc6bab7a8e
Merge: 6283f2caaa42c7238bdc9c2e8bc1246207645019 11bfbc516077d1cead94d0bc70ef24267b9014e7
Author: Nadezhda Ivanova <nadezhda.ivanova at postpath.com>
Date:   Sun Sep 20 17:43:46 2009 -0700

    Merge branch 'master' of git://git.samba.org/samba

commit 6283f2caaa42c7238bdc9c2e8bc1246207645019
Author: Nadezhda Ivanova <nadezhda.ivanova at postpath.com>
Date:   Sun Sep 20 13:50:34 2009 -0700

    Initial implementation of security descriptor creation in DS
    
    TODO's:
    ACE sorting and clarifying the inheritance of object specific ace's.

-----------------------------------------------------------------------

Summary of changes:
 libcli/security/security_descriptor.c             |   50 +
 libcli/security/security_descriptor.h             |    4 +
 source4/dsdb/samdb/ldb_modules/acl.c              | 1151 +++++++++++++++++++++
 source4/dsdb/samdb/ldb_modules/config.mk          |   12 +
 source4/dsdb/samdb/ldb_modules/kludge_acl.c       |   13 +
 source4/dsdb/schema/schema_query.c                |   12 +
 source4/lib/ldb/tests/python/sec_descriptor.py    |   13 +-
 source4/libcli/security/access_check.c            |  135 +++
 source4/libcli/security/config.mk                 |    3 +-
 source4/libcli/security/create_descriptor.c       |  352 +++++++-
 source4/libcli/security/object_tree.c             |  106 ++
 source4/libcli/security/security.h                |    9 +
 source4/scripting/python/samba/provision.py       |   49 +-
 source4/selftest/knownfail                        |    3 +-
 source4/setup/provision_configuration_basedn.ldif |    1 +
 source4/setup/provision_schema_basedn.ldif        |    1 +
 16 files changed, 1899 insertions(+), 15 deletions(-)
 create mode 100644 source4/dsdb/samdb/ldb_modules/acl.c
 create mode 100644 source4/libcli/security/object_tree.c


Changeset truncated at 500 lines:

diff --git a/libcli/security/security_descriptor.c b/libcli/security/security_descriptor.c
index dbe1160..b77a281 100644
--- a/libcli/security/security_descriptor.c
+++ b/libcli/security/security_descriptor.c
@@ -77,6 +77,56 @@ struct security_acl *security_acl_dup(TALLOC_CTX *mem_ctx,
 	
 }
 
+struct security_acl *security_acl_concatenate(TALLOC_CTX *mem_ctx,
+                                              const struct security_acl *acl1,
+                                              const struct security_acl *acl2)
+{
+        struct security_acl *nacl;
+        int i;
+
+        if (!acl1 && !acl2)
+                return NULL;
+
+        if (!acl1){
+                nacl = security_acl_dup(mem_ctx, acl2);
+                return nacl;
+        }
+
+        if (!acl2){
+                nacl = security_acl_dup(mem_ctx, acl1);
+                return nacl;
+        }
+
+        nacl = talloc (mem_ctx, struct security_acl);
+        if (nacl == NULL) {
+                return NULL;
+        }
+
+        nacl->revision = acl1->revision;
+        nacl->size = acl1->size + acl2->size;
+        nacl->num_aces = acl1->num_aces + acl2->num_aces;
+
+        if (nacl->num_aces == 0)
+                return nacl;
+
+        nacl->aces = (struct security_ace *)talloc_array (mem_ctx, struct security_ace, acl1->num_aces+acl2->num_aces);
+        if ((nacl->aces == NULL) && (nacl->num_aces > 0)) {
+                goto failed;
+        }
+
+        for (i = 0; i < acl1->num_aces; i++)
+                nacl->aces[i] = acl1->aces[i];
+        for (i = 0; i < acl2->num_aces; i++)
+                nacl->aces[i + acl1->num_aces] = acl2->aces[i];
+
+        return nacl;
+
+ failed:
+        talloc_free (nacl);
+        return NULL;
+
+}
+
 /* 
    talloc and copy a security descriptor
  */
diff --git a/libcli/security/security_descriptor.h b/libcli/security/security_descriptor.h
index a377ef5..bc5761a 100644
--- a/libcli/security/security_descriptor.h
+++ b/libcli/security/security_descriptor.h
@@ -64,4 +64,8 @@ struct security_ace *security_ace_create(TALLOC_CTX *mem_ctx,
 struct security_acl *security_acl_dup(TALLOC_CTX *mem_ctx,
 				      const struct security_acl *oacl);
 
+struct security_acl *security_acl_concatenate(TALLOC_CTX *mem_ctx,
+                                              const struct security_acl *acl1,
+                                              const struct security_acl *acl2);
+
 #endif /* __SECURITY_DESCRIPTOR_H__ */
diff --git a/source4/dsdb/samdb/ldb_modules/acl.c b/source4/dsdb/samdb/ldb_modules/acl.c
new file mode 100644
index 0000000..1b02abc
--- /dev/null
+++ b/source4/dsdb/samdb/ldb_modules/acl.c
@@ -0,0 +1,1151 @@
+/*
+   ldb database library
+
+   Copyright (C) Simo Sorce 2006-2008
+   Copyright (C) Nadezhda Ivanova 2009
+   Copyright (C) Anatoliy Atanasov  2009
+
+    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 3 of the License, or
+   (at your option) any later version.
+
+   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.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ *  Name: ldb
+ *
+ *  Component: ldb ACL module
+ *
+ *  Description: Module that performs authorisation access checks based on the
+ *               account's security context and the DACL of the object being polled.
+ *               Only DACL checks implemented at this point
+ *
+ *  Authors: Nadezhda Ivanova, Anatoliy Atanasov
+ */
+
+#include "includes.h"
+#include "ldb_module.h"
+#include "auth/auth.h"
+#include "libcli/security/security.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "dsdb/samdb/samdb.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "param/param.h"
+
+/* acl_search helper */
+struct acl_context {
+
+	struct ldb_module *module;
+	struct ldb_request *req;
+	struct ldb_request *down_req;
+
+	/*needed if we have to identify if this is SYSTEM_USER*/
+	enum security_user_level user_type;
+
+	uint32_t access_needed;
+	struct ldb_dn * dn_to_check;
+
+	/* set to true when we need to process the request as a SYSTEM_USER, regardless
+	 * of the user's actual rights - for example when we need to retrieve the
+	 * ntSecurityDescriptor */
+	bool ignore_security;
+	struct security_token *token;
+	/*needed to identify if we have requested these attributes*/
+	bool nTSecurityDescriptor;
+	bool objectClass;
+	int sec_result;
+};
+
+struct extended_access_check_attribute {
+	const char *oa_name;
+	const uint32_t requires_rights;
+};
+
+struct acl_private{
+	bool perform_check;
+};
+
+static int acl_search_callback(struct ldb_request *req, struct ldb_reply *ares);
+
+/*FIXME: Perhaps this should go in the .idl file*/
+#define SEC_GENERIC_ACCESS_NEVER_GRANTED ( 0xFFFFFFFF )
+
+/*Contains a part of the attributes - the ones that have predefined required rights*/
+static const struct extended_access_check_attribute extended_access_checks_table[] =
+{
+	{
+		.oa_name = "nTSecurityDescriptor",
+		.requires_rights = SEC_FLAG_SYSTEM_SECURITY & SEC_STD_READ_CONTROL,
+	},
+	{
+                .oa_name = "pekList",
+                .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
+        },
+	{
+                .oa_name = "currentValue",
+                .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
+	},
+	{
+                .oa_name = "dBCSPwd",
+                .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
+	},
+	{
+                .oa_name = "unicodePwd",
+                .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
+	},
+	{
+                .oa_name = "ntPwdHistory",
+                .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
+	},
+	{
+                .oa_name = "priorValue",
+                .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
+	},
+	{
+                .oa_name = "supplementalCredentials",
+                .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
+	},
+	{
+                .oa_name = "trustAuthIncoming",
+                .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
+	},
+	{
+                .oa_name = "trustAuthOutgoing",
+                .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
+	},
+	{
+                .oa_name = "ImPwdHistory",
+                .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
+	},
+	{
+                .oa_name = "initialAuthIncoming",
+                .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
+	},
+	{
+                .oa_name = "initialAuthOutgoing",
+                .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
+	},
+	{
+                .oa_name = "msDS-ExecuteScriptPassword",
+                .requires_rights = SEC_GENERIC_ACCESS_NEVER_GRANTED,
+	},
+};
+
+static NTSTATUS extended_access_check(const char *attribute_name, const int access_rights, uint32_t searchFlags)
+{
+	int i = 0;
+	if (access_rights == SEC_GENERIC_ACCESS_NEVER_GRANTED) {
+		return NT_STATUS_ACCESS_DENIED;
+	}
+
+	/*Check if the attribute is in the table first*/
+	for ( i = 0; extended_access_checks_table[i].oa_name; i++ ) {
+		if (ldb_attr_cmp(extended_access_checks_table[i].oa_name, attribute_name) == 0) {
+			if ((access_rights & extended_access_checks_table[i].requires_rights) == access_rights) {
+				return NT_STATUS_OK;
+			} else {
+				return NT_STATUS_ACCESS_DENIED;
+			}
+		}
+	}
+
+	/*Check for attribute whose attributeSchema has 0x80 set in searchFlags*/
+	if ((searchFlags & SEARCH_FLAG_CONFIDENTIAL) == SEARCH_FLAG_CONFIDENTIAL) {
+		if (((SEC_ADS_READ_PROP & SEC_ADS_CONTROL_ACCESS) & access_rights) == access_rights) {
+			return NT_STATUS_OK;
+		} else {
+			return NT_STATUS_ACCESS_DENIED;
+		}
+	}
+
+	/*Check attributes with *special* behaviour*/
+	if (ldb_attr_cmp("msDS-QuotaEffective", attribute_name) == 0 || ldb_attr_cmp("msDS-QuotaUsed", attribute_name) == 0){
+		/*Rights required:
+		 *
+		 *(RIGHT_DS_READ_PROPERTY on the Quotas container or
+		 *((the client is querying the quota for the security principal it is authenticated as) and
+		 *(DS-Query-Self-Quota control access right on the Quotas container))
+		 */
+	}
+
+        if (ldb_attr_cmp("userPassword", attribute_name) == 0) {
+		/*When the dSHeuristics.fUserPwdSupport flag is false, the requester must be granted RIGHT_DS_READ_PROPERTY.
+		 *When the dSHeuristics.fUserPwdSupport flag is true, access is never granted.
+		 */
+	}
+
+	if (ldb_attr_cmp("sDRightsEffective", attribute_name) == 0) {
+		/*FIXME:3.1.1.4.5.4 in MS-ADTS*/
+	}
+
+	if (ldb_attr_cmp("allowedChildClassesEffective", attribute_name) == 0) {
+		/*FIXME:3.1.1.4.5.5 in MS-ADTS*/
+        }
+
+	if (ldb_attr_cmp("allowedAttributesEffective", attribute_name) == 0) {
+		/*FIXME:3.1.1.4.5.7 in MS-ADTS*/
+        }
+
+	if (ldb_attr_cmp("msDS-Approx-Immed-Subordinates", attribute_name) == 0) {
+		/*FIXME:3.1.1.4.5.15 in MS-ADTS*/
+        }
+
+	if (ldb_attr_cmp("msDS-QuotaEffective", attribute_name) == 0) {
+		/*FIXME:3.1.1.4.5.22 in MS-ADTS*/
+        }
+
+	if (ldb_attr_cmp("msDS-ReplAttributeMetaData", attribute_name) == 0 || ldb_attr_cmp("msDS-ReplAttributeMetaData", attribute_name) == 0) {
+		/*The security context of the requester must be granted the following rights on the replPropertyMetaData attribute:
+		 *(RIGHT_DS_READ_PROPERTY)or (DS-Replication-Manage-Topology by ON!nTSecurityDescriptor)
+		 */
+        }
+
+	if (ldb_attr_cmp("msDS-NCReplInboundNeighbors", attribute_name) == 0) {
+		/*The security context of the requester must be granted the following rights on repsFrom:
+		 *(RIGHT_DS_READ_PROPERTY) or (DS-Replication-Manage-Topology) or (DS-Replication-Monitor-Topology)
+		 */
+        }
+
+	if (ldb_attr_cmp("msDS-NCReplOutboundNeighbors", attribute_name) == 0) {
+		/*The security context of the requester must be granted the following rights on repsTo:
+		 *(RIGHT_DS_READ_PROPERTY) or (DS-Replication-Manage-Topology) or (DS-Replication-Monitor-Topology)
+		 */
+        }
+
+	if (ldb_attr_cmp("msDS-NCReplCursors", attribute_name) == 0) {
+		/*The security context of the requester must be granted the following rights on replUpToDateVector: (RIGHT_DS_READ_PROPERTY)
+		 *or (DS-Replication-Manage-Topology) or (DS-Replication-Monitor-Topology)
+		 */
+        }
+
+	if (ldb_attr_cmp("msDS-IsUserCachableAtRodc", attribute_name) == 0) {
+		/*The security context of the requester must be granted
+		 *the DS-Replication-Secrets-Synchronize control access right on the root of the default NC.
+		 */
+        }
+
+	return NT_STATUS_OK;
+}
+
+/* Builds an object tree for object specific access checks */
+static struct object_tree * build_object_tree_form_attr_list(TALLOC_CTX *mem_ctx,   /* Todo this context or separate? */
+							     struct ldb_context *ldb,
+							     const char ** attr_names,
+							     int num_attrs,
+							     const char * object_class,
+							     uint32_t init_access)
+{
+	const struct dsdb_schema *schema = dsdb_get_schema(ldb);
+	const struct GUID *oc_guid = class_schemaid_guid_by_lDAPDisplayName(schema, object_class);
+	struct object_tree *tree;
+	int i;
+
+	if (!oc_guid)
+		return NULL;
+
+	tree = insert_in_object_tree(mem_ctx, oc_guid, NULL, init_access, NULL);
+	if (attr_names){
+		for (i=0; i < num_attrs; i++){
+			const struct dsdb_attribute *attribute = dsdb_attribute_by_lDAPDisplayName(schema,attr_names[i]);
+			if (attribute)
+				insert_in_object_tree(mem_ctx,
+						      &attribute->schemaIDGUID,
+						      &attribute->attributeSecurityGUID,
+						      init_access,
+						      tree);
+		}
+	}
+	return tree;
+}
+
+bool is_root_base_dn(struct ldb_context *ldb, struct ldb_dn *dn_to_check)
+{
+	int result;
+	struct ldb_dn *root_base_dn = ldb_get_root_basedn(ldb);
+	result = ldb_dn_compare(root_base_dn,dn_to_check);
+	return (result==0);
+}
+
+static int acl_op_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+	struct acl_context *ac;
+
+	ac = talloc_get_type(req->context, struct acl_context);
+
+	if (!ares) {
+		return ldb_module_done(ac->req, NULL, NULL,
+					LDB_ERR_OPERATIONS_ERROR);
+	}
+	if (ares->error != LDB_SUCCESS) {
+		return ldb_module_done(ac->req, ares->controls,
+					ares->response, ares->error);
+	}
+
+	if (ares->type != LDB_REPLY_DONE) {
+		talloc_free(ares);
+		return ldb_module_done(ac->req, NULL, NULL,
+					LDB_ERR_OPERATIONS_ERROR);
+	}
+
+	return ldb_module_done(ac->req, ares->controls,
+				ares->response, ares->error);
+}
+
+
+static int acl_access_check_add(struct ldb_reply *ares,
+				struct acl_context *ac,
+				struct security_descriptor *sd)
+{
+	uint32_t access_granted = 0;
+	NTSTATUS status;
+	struct ldb_dn *parent;
+	struct ldb_dn *grandparent;
+	struct object_tree *tree = NULL;
+
+	parent = ldb_dn_get_parent(ac->req, ac->req->op.add.message->dn);
+	grandparent = ldb_dn_get_parent(ac->req, parent);
+	if (ldb_dn_compare(ares->message->dn, grandparent) == 0)
+		status = sec_access_check_ds(sd, ac->token,
+					     SEC_ADS_LIST,
+					     &access_granted,
+					     NULL);
+	else if (ldb_dn_compare(ares->message->dn, parent) == 0){
+		struct ldb_message_element *oc_el;
+		struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
+		const struct dsdb_schema *schema = dsdb_get_schema(ldb);
+		int i;
+
+		oc_el = ldb_msg_find_element(ares->message, "objectClass");
+		if (!oc_el || oc_el->num_values == 0)
+			return LDB_SUCCESS;
+		for (i = 0; i < oc_el->num_values; i++){
+			const struct GUID *guid = class_schemaid_guid_by_lDAPDisplayName(schema,
+											  oc_el->values[i].data);
+			ac->sec_result = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
+			tree = insert_in_object_tree(ac->req, guid, NULL, SEC_ADS_CREATE_CHILD,
+						     tree);
+			status = sec_access_check_ds(sd, ac->token, SEC_ADS_CREATE_CHILD,&access_granted, tree);
+			if (NT_STATUS_IS_OK(status))
+				ac->sec_result = LDB_SUCCESS;
+		}
+	}
+	else
+		return LDB_SUCCESS;
+
+	return ac->sec_result;
+}
+
+static int acl_access_check_modify(struct ldb_reply *ares, struct acl_context *ac,
+				   struct security_descriptor *sd)
+{
+	uint32_t access_granted = 0;
+	NTSTATUS status;
+	struct ldb_dn *parent;
+	struct object_tree *tree = NULL;
+
+	parent = ldb_dn_get_parent(ac->req, ac->req->op.add.message->dn);
+	if (ldb_dn_compare(ares->message->dn, parent) == 0)
+		status = sec_access_check_ds(sd, ac->token, SEC_ADS_LIST,&access_granted, NULL);
+	else if (ldb_dn_compare(ares->message->dn, ac->req->op.add.message->dn) == 0){
+		struct ldb_message_element *oc_el;
+		struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
+		const struct dsdb_schema *schema = dsdb_get_schema(ldb);
+		int i;
+		struct GUID *guid;
+		oc_el = ldb_msg_find_element(ares->message, "objectClass");
+		if (!oc_el || oc_el->num_values == 0)
+			return LDB_SUCCESS;
+
+		guid = class_schemaid_guid_by_lDAPDisplayName(schema,
+							      oc_el->values[oc_el->num_values-1].data);
+		tree = insert_in_object_tree(ac->req, guid, NULL, SEC_ADS_WRITE_PROP,
+						     tree);
+		for (i=0; i < ac->req->op.mod.message->num_elements; i++){
+			const struct dsdb_attribute *attr = dsdb_attribute_by_lDAPDisplayName(schema,
+											      ac->req->op.mod.message->elements[i].name);
+			if (!attr)
+				return LDB_ERR_OPERATIONS_ERROR; /* What should we actually return here? */
+			insert_in_object_tree(ac, &attr->schemaIDGUID,
+					      &attr->attributeSecurityGUID, ac->access_needed, tree);
+		}
+		status = sec_access_check_ds(sd, ac->token, SEC_ADS_WRITE_PROP ,&access_granted, tree);
+		if (!NT_STATUS_IS_OK(status))
+			ac->sec_result = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
+	}
+	else
+		return LDB_SUCCESS;
+	return ac->sec_result;
+}
+/*TODO*/
+static int acl_access_check_rename(struct ldb_reply *ares, struct acl_context *ac,
+				   struct security_descriptor *sd)
+{
+	return ac->sec_result;
+}
+
+static int acl_access_check_delete(struct ldb_reply *ares, struct acl_context *ac,
+				   struct security_descriptor *sd)
+{
+	uint32_t access_granted = 0;
+	NTSTATUS status;
+	struct ldb_dn *parent;
+	struct object_tree *tree = NULL;
+
+	parent = ldb_dn_get_parent(ac->req, ac->req->op.del.dn);
+	if (ldb_dn_compare(ares->message->dn, parent) == 0){
+		status = sec_access_check_ds(sd, ac->token, SEC_ADS_LIST,&access_granted, NULL);
+		if (!NT_STATUS_IS_OK(status)){
+			ac->sec_result = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
+			return ac->sec_result;
+		}
+		status = sec_access_check_ds(sd, ac->token, SEC_ADS_DELETE_CHILD,&access_granted, NULL);
+		if (NT_STATUS_IS_OK(status)){
+			ac->sec_result = LDB_SUCCESS;
+			return ac->sec_result;
+		}
+	}
+	else if (ldb_dn_compare(ares->message->dn, ac->req->op.del.dn) == 0){
+		status = sec_access_check_ds(sd, ac->token, SEC_STD_DELETE, &access_granted, NULL);
+		if (!NT_STATUS_IS_OK(status))
+			ac->sec_result = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
+	}
+	return ac->sec_result;


-- 
Samba Shared Repository


More information about the samba-cvs mailing list