summaryrefslogtreecommitdiffstats
path: root/lib/libaccess/acltools.cpp
diff options
context:
space:
mode:
authorcvsadm <cvsadm>2005-01-21 00:44:34 +0000
committercvsadm <cvsadm>2005-01-21 00:44:34 +0000
commitb2093e3016027d6b5cf06b3f91f30769bfc099e2 (patch)
treecf58939393a9032182c4fbc4441164a9456e82f8 /lib/libaccess/acltools.cpp
downloadds-b2093e3016027d6b5cf06b3f91f30769bfc099e2.tar.gz
ds-b2093e3016027d6b5cf06b3f91f30769bfc099e2.tar.xz
ds-b2093e3016027d6b5cf06b3f91f30769bfc099e2.zip
Moving NSCP Directory Server from DirectoryBranch to TRUNK, initial drop. (foxworth)ldapserver7x
Diffstat (limited to 'lib/libaccess/acltools.cpp')
-rw-r--r--lib/libaccess/acltools.cpp3457
1 files changed, 3457 insertions, 0 deletions
diff --git a/lib/libaccess/acltools.cpp b/lib/libaccess/acltools.cpp
new file mode 100644
index 00000000..1283147e
--- /dev/null
+++ b/lib/libaccess/acltools.cpp
@@ -0,0 +1,3457 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Tools to build and maintain access control lists.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#define ALLOCATE_ATTR_TABLE 1 /* Include the table of PList names */
+
+#include <netsite.h>
+#include <base/plist.h>
+#include <base/util.h>
+#include <base/crit.h>
+#include <base/file.h>
+#include <libaccess/acl.h>
+#include "aclpriv.h"
+#include <libaccess/aclproto.h>
+#include <libaccess/aclerror.h>
+#include <libaccess/symbols.h>
+#include <libaccess/aclstruct.h>
+#include <libaccess/las.h>
+
+#include "aclscan.h"
+#include "parse.h"
+#include "oneeval.h"
+
+#include <libaccess/authdb.h>
+
+static CRITICAL acl_parse_crit = NULL;
+
+/*
+ * Allocate a new ACL handle
+ *
+ * This function creates a new ACL structure that will be used for
+ * access control information.
+ *
+ * Input:
+ * tag Specifies an identifier name for the new ACL, or
+ * it may be NULL when no name is required.
+ * Returns:
+ * A new ACL structure.
+ */
+
+NSAPI_PUBLIC ACLHandle_t *
+ACL_AclNew(NSErr_t *errp, char *tag )
+{
+ACLHandle_t *handle;
+
+ handle = ( ACLHandle_t * ) PERM_CALLOC ( 1 * sizeof (ACLHandle_t) );
+ if ( handle && tag ) {
+ handle->tag = PERM_STRDUP( tag );
+ if ( handle->tag == NULL ) {
+ PERM_FREE(handle);
+ return(NULL);
+ }
+ }
+ return(handle);
+}
+
+/*
+ * Appends to a specified ACL
+ *
+ * This function appends a specified ACL to the end of a given ACL list.
+ *
+ * Input:
+ * errp The error stack
+ * flags should always be zero now
+ * acl_list target ACL list
+ * acl new acl
+ * Returns:
+ * < 0 failure
+ * > 0 The number of acl's in the current list
+ */
+
+NSAPI_PUBLIC int
+ACL_ExprAppend( NSErr_t *errp, ACLHandle_t *acl,
+ ACLExprHandle_t *expr )
+{
+
+ if ( acl == NULL || expr == NULL )
+ return(ACLERRUNDEF);
+
+ expr->acl_tag = acl->tag;
+
+ if ( expr->expr_type == ACL_EXPR_TYPE_AUTH ||
+ expr->expr_type == ACL_EXPR_TYPE_RESPONSE ) {
+ expr->expr_number = -1; // expr number isn't valid
+ } else {
+ acl->expr_count++;
+ expr->expr_number = acl->expr_count;
+ }
+
+ if ( acl->expr_list_head == NULL ) {
+ acl->expr_list_head = expr;
+ acl->expr_list_tail = expr;
+ } else {
+ acl->expr_list_tail->expr_next = expr;
+ acl->expr_list_tail = expr;
+ }
+
+ return(acl->expr_count);
+}
+
+/*
+ * Add authentication information to an ACL
+ *
+ * This function adds authentication data to an expr, based on
+ * the information provided by the parameters.
+ *
+ * Input:
+ * expr an authenticate expression to add database
+ * and method information to. ie, auth_info
+ * auth_info authentication information, eg database,
+ * method, etc.
+ * Returns:
+ * 0 success
+ * < 0 failure
+ */
+
+NSAPI_PUBLIC int
+ACL_ExprAddAuthInfo( ACLExprHandle_t *expr, PList_t auth_info )
+{
+ if ( expr == NULL || auth_info == NULL )
+ return(ACLERRUNDEF);
+
+ expr->expr_auth = auth_info;
+
+ return(0);
+}
+
+/*
+ * Add authorization information to an ACL
+ *
+ * This function adds an authorization to a given ACL, based on the information
+ * provided by the parameters.
+ *
+ * Input:
+ * errp The error stack
+ * access_rights strings which identify the access rights to be
+ * controlled by the generated expr.
+ * flags processing flags
+ * allow non-zero to allow the indicated rights, or zero to
+ * deny them.
+ * attr_expr handle for an attribute expression, which may be
+ * obtained by calling ACL_ExprNew()
+ * Returns:
+ * 0 success
+ * < 0 failure
+ */
+
+NSAPI_PUBLIC int
+ACL_AddPermInfo( NSErr_t *errp, ACLHandle_t *acl,
+ char **access_rights,
+ PFlags_t flags,
+ int allow,
+ ACLExprHandle_t *expr,
+ char *tag )
+{
+ if ( acl == NULL || expr == NULL )
+ return(ACLERRUNDEF);
+
+ expr->expr_flags = flags;
+ expr->expr_argv = (char **) access_rights;
+ expr->expr_tag = PERM_STRDUP( tag );
+ if ( expr->expr_tag == NULL )
+ return(ACLERRNOMEM);
+ return(ACL_ExprAppend( errp, acl, expr ));
+}
+
+/*
+ * Add rights information to an expression
+ *
+ * This function adds a right to an authorization, based on the information
+ * provided by the parameters.
+ *
+ * Input:
+ * errp The error stack
+ * access_right strings which identify the access rights to be
+ * controlled by the generated expr.
+ * expr handle for an attribute expression, which may be
+ * obtained by calling ACL_ExprNew()
+ * Returns:
+ * 0 success
+ * < 0 failure
+ */
+
+NSAPI_PUBLIC int
+ACL_ExprAddArg( NSErr_t *errp,
+ ACLExprHandle_t *expr,
+ char *arg )
+{
+
+ if ( expr == NULL )
+ return(ACLERRUNDEF);
+
+ if (expr->expr_argv == NULL)
+ expr->expr_argv = (char **) PERM_MALLOC( 2 * sizeof(char *) );
+ else
+ expr->expr_argv = (char **) PERM_REALLOC( expr->expr_argv,
+ (expr->expr_argc+2)
+ * sizeof(char *) );
+
+ if (expr->expr_argv == NULL)
+ return(ACLERRNOMEM);
+
+ expr->expr_argv[expr->expr_argc] = PERM_STRDUP( arg );
+ if (expr->expr_argv[expr->expr_argc] == NULL)
+ return(ACLERRNOMEM);
+ expr->expr_argc++;
+ expr->expr_argv[expr->expr_argc] = NULL;
+
+ return(0);
+
+}
+
+
+NSAPI_PUBLIC int
+ACL_ExprSetDenyWith( NSErr_t *errp, ACLExprHandle_t *expr, char *deny_type, char *deny_response)
+{
+int rv;
+
+ if ( expr->expr_argc == 0 ) {
+ if ( (rv = ACL_ExprAddArg(errp, expr, deny_type)) < 0 )
+ return(rv);
+ if ( (rv = ACL_ExprAddArg(errp, expr, deny_response)) < 0 )
+ return(rv);
+ } else if ( expr->expr_argc == 2 ) {
+ if ( deny_type ) {
+ if ( expr->expr_argv[0] )
+ PERM_FREE(expr->expr_argv[0]);
+ expr->expr_argv[0] = PERM_STRDUP(deny_type);
+ if ( expr->expr_argv[0] == NULL )
+ return(ACLERRNOMEM);
+ }
+ if ( deny_response ) {
+ if ( expr->expr_argv[1] )
+ PERM_FREE(expr->expr_argv[1]);
+ expr->expr_argv[1] = PERM_STRDUP(deny_response);
+ if ( expr->expr_argv[0] == NULL )
+ return(ACLERRNOMEM);
+ }
+ } else {
+ return(ACLERRINTERNAL);
+ }
+ return(0);
+}
+
+NSAPI_PUBLIC int
+ACL_ExprGetDenyWith( NSErr_t *errp, ACLExprHandle_t *expr, char **deny_type,
+char **deny_response)
+{
+ if ( expr->expr_argc == 2 ) {
+ *deny_type = expr->expr_argv[0];
+ *deny_response = expr->expr_argv[1];
+ return(0);
+ } else {
+ return(ACLERRUNDEF);
+ }
+}
+
+/*
+ * Function to set the authorization statement processing flags.
+ *
+ * Input:
+ * errp The error reporting stack
+ * expr The authoization statement
+ * flags The flags to set
+ * Returns:
+ * 0 success
+ * < 0 failure
+ */
+
+NSAPI_PUBLIC int
+ACL_ExprSetPFlags( NSErr_t *errp,
+ ACLExprHandle_t *expr,
+ PFlags_t flags )
+{
+ if ( expr == NULL )
+ return(ACLERRUNDEF);
+
+ expr->expr_flags |= flags;
+ return(0);
+}
+
+/*
+ * Function to clear the authorization statement processing flags.
+ *
+ * Input:
+ * errp The error reporting stack
+ * expr The authoization statement
+ * Returns:
+ * 0 success
+ * < 0 failure
+ */
+
+NSAPI_PUBLIC int
+ACL_ExprClearPFlags( NSErr_t *errp,
+ ACLExprHandle_t *expr )
+{
+ if ( expr == NULL )
+ return(ACLERRUNDEF);
+
+ expr->expr_flags = 0;
+ return(0);
+}
+
+/*
+ * Allocate a new expression handle.
+ *
+ * Returns:
+ * NULL If handle could not be allocated.
+ * pointer New handle.
+ */
+
+NSAPI_PUBLIC ACLExprHandle_t *
+ACL_ExprNew( const ACLExprType_t expr_type )
+{
+ACLExprHandle_t *expr_handle;
+
+ expr_handle = ( ACLExprHandle_t * ) PERM_CALLOC ( sizeof(ACLExprHandle_t) );
+ if ( expr_handle ) {
+ expr_handle->expr_arry = ( ACLExprEntry_t * )
+ PERM_CALLOC( ACL_TERM_BSIZE * sizeof(ACLExprEntry_t) ) ;
+ expr_handle->expr_arry_size = ACL_TERM_BSIZE;
+ expr_handle->expr_type = expr_type;
+
+ expr_handle->expr_raw = ( ACLExprRaw_t * )
+ PERM_CALLOC( ACL_TERM_BSIZE * sizeof(ACLExprRaw_t) ) ;
+ expr_handle->expr_raw_size = ACL_TERM_BSIZE;
+
+ }
+ return(expr_handle);
+}
+
+
+/*
+ * LOCAL FUNCTION
+ *
+ * displays the ASCII equivalent index value.
+ */
+
+static char *
+acl_index_string ( int value, char *buffer )
+{
+
+ if ( value == ACL_TRUE_IDX ) {
+ strcpy( buffer, "TRUE" );
+ return( buffer );
+ }
+
+ if ( value == ACL_FALSE_IDX ) {
+ strcpy( buffer, "FALSE" );
+ return( buffer );
+ }
+
+ sprintf( buffer, "goto %d", value );
+ return( buffer );
+}
+
+
+/*
+ * LOCAL FUNCTION
+ *
+ * displays ASCII equivalent of CmpOp_t
+ */
+
+static char *
+acl_comp_string( CmpOp_t cmp )
+{
+ switch (cmp) {
+ case CMP_OP_EQ:
+ return("=");
+ case CMP_OP_NE:
+ return("!=");
+ case CMP_OP_GT:
+ return(">");
+ case CMP_OP_LT:
+ return("<");
+ case CMP_OP_GE:
+ return(">=");
+ case CMP_OP_LE:
+ return("<=");
+ default:
+ return("unknown op");
+ }
+}
+
+/*
+ * Add a term to the specified attribute expression.
+ *
+ * Input:
+ * errp Error stack
+ * acl_expr Target expression handle
+ * attr_name Term Attribute name
+ * cmp Comparison operator
+ * attr_pattern Pattern for comparison
+ * Ouput:
+ * acl_expr New term added
+ * Returns:
+ * 0 Success
+ * < 0 Error
+ */
+
+NSAPI_PUBLIC int
+ACL_ExprTerm( NSErr_t *errp, ACLExprHandle_t *acl_expr,
+ char *attr_name,
+ CmpOp_t cmp,
+ char *attr_pattern )
+{
+ACLExprEntry_t *expr;
+ACLExprRaw_t *raw_expr;
+
+ if ( acl_expr == NULL || acl_expr->expr_arry == NULL )
+ return(ACLERRUNDEF);
+
+ if ( acl_expr->expr_term_index >= acl_expr->expr_arry_size ) {
+ acl_expr->expr_arry = ( ACLExprEntry_t *)
+ PERM_REALLOC ( acl_expr->expr_arry,
+ (acl_expr->expr_arry_size + ACL_TERM_BSIZE)
+ * sizeof(ACLExprEntry_t));
+ if ( acl_expr->expr_arry == NULL )
+ return(ACLERRNOMEM);
+ acl_expr->expr_arry_size += ACL_TERM_BSIZE;
+ }
+
+ expr = &acl_expr->expr_arry[acl_expr->expr_term_index];
+ acl_expr->expr_term_index++;
+
+ expr->attr_name = PERM_STRDUP(attr_name);
+ if ( expr->attr_name == NULL )
+ return(ACLERRNOMEM);
+ expr->comparator = cmp;
+ expr->attr_pattern = PERM_STRDUP(attr_pattern);
+ if ( expr->attr_pattern == NULL )
+ return(ACLERRNOMEM);
+ expr->true_idx = ACL_TRUE_IDX;
+ expr->false_idx = ACL_FALSE_IDX;
+ expr->start_flag = 1;
+ expr->las_cookie = 0;
+ expr->las_eval_func = 0;
+
+ if ( acl_expr->expr_raw_index >= acl_expr->expr_raw_size ) {
+ acl_expr->expr_raw = ( ACLExprRaw_t *)
+ PERM_REALLOC ( acl_expr->expr_raw,
+ (acl_expr->expr_raw_size + ACL_TERM_BSIZE)
+ * sizeof(ACLExprRaw_t));
+ if ( acl_expr->expr_raw == NULL )
+ return(ACLERRNOMEM);
+ acl_expr->expr_raw_size += ACL_TERM_BSIZE;
+ }
+
+ raw_expr = &acl_expr->expr_raw[acl_expr->expr_raw_index];
+ acl_expr->expr_raw_index++;
+
+ raw_expr->attr_name = expr->attr_name;
+ raw_expr->comparator = cmp;
+ raw_expr->attr_pattern = expr->attr_pattern;
+ raw_expr->logical = (ACLExprOp_t)0;
+
+#ifdef DEBUG_LEVEL_2
+ printf ( "%d: %s %s %s, t=%d, f=%d\n",
+ acl_expr->expr_term_index - 1,
+ expr->attr_name,
+ acl_comp_string( expr->comparator ),
+ expr->attr_pattern,
+ expr->true_idx,
+ expr->false_idx );
+#endif
+
+ return(0);
+}
+
+/*
+ * Negate the previous term or subexpression.
+ *
+ * Input:
+ * errp The error stack
+ * acl_expr The expression to negate
+ * Ouput
+ * acl_expr The negated expression
+ * Returns:
+ * 0 Success
+ * < 0 Failure
+ */
+
+NSAPI_PUBLIC int
+ACL_ExprNot( NSErr_t *errp, ACLExprHandle_t *acl_expr )
+{
+int idx;
+int ii;
+int expr_one = 0;
+ACLExprRaw_t *raw_expr;
+
+ if ( acl_expr == NULL )
+ return(ACLERRUNDEF);
+
+
+ if ( acl_expr->expr_raw_index >= acl_expr->expr_raw_size ) {
+ acl_expr->expr_raw = ( ACLExprRaw_t *)
+ PERM_REALLOC ( acl_expr->expr_raw,
+ (acl_expr->expr_raw_size + ACL_TERM_BSIZE)
+ * sizeof(ACLExprRaw_t));
+ if ( acl_expr->expr_raw == NULL )
+ return(ACLERRNOMEM);
+ acl_expr->expr_raw_size += ACL_TERM_BSIZE;
+ }
+
+ raw_expr = &acl_expr->expr_raw[acl_expr->expr_raw_index];
+ acl_expr->expr_raw_index++;
+
+ raw_expr->logical = ACL_EXPR_OP_NOT;
+ raw_expr->attr_name = NULL;
+
+ /* Find the last expression */
+ idx = acl_expr->expr_term_index - 1;
+ for ( ii = idx; ii >= 0; ii-- ) {
+ if ( acl_expr->expr_arry[ii].start_flag ) {
+ expr_one = ii;
+ break;
+ }
+ }
+
+#ifdef DEBUG_LEVEL_2
+ printf("not, start index=%d\n", expr_one);
+#endif
+
+
+ /*
+ * The intent here is negate the last expression by
+ * modifying the true and false links.
+ */
+
+ for ( ii = expr_one; ii < acl_expr->expr_term_index; ii++ ) {
+ if ( acl_expr->expr_arry[ii].true_idx == ACL_TRUE_IDX )
+ acl_expr->expr_arry[ii].true_idx = ACL_FALSE_IDX;
+ else if ( acl_expr->expr_arry[ii].true_idx == ACL_FALSE_IDX )
+ acl_expr->expr_arry[ii].true_idx = ACL_TRUE_IDX;
+
+ if ( acl_expr->expr_arry[ii].false_idx == ACL_TRUE_IDX )
+ acl_expr->expr_arry[ii].false_idx = ACL_FALSE_IDX;
+ else if ( acl_expr->expr_arry[ii].false_idx == ACL_FALSE_IDX )
+ acl_expr->expr_arry[ii].false_idx = ACL_TRUE_IDX;
+
+ }
+
+ return(0) ;
+}
+
+/*
+ * Logical 'and' the previous two terms or subexpressions.
+ *
+ * Input:
+ * errp The error stack
+ * acl_expr The terms or subexpressions
+ * Output:
+ * acl_expr The expression after logical 'and'
+ */
+
+NSAPI_PUBLIC int
+ACL_ExprAnd( NSErr_t *errp, ACLExprHandle_t *acl_expr )
+{
+int idx;
+int ii;
+int expr_one = ACL_FALSE_IDX;
+int expr_two = ACL_FALSE_IDX;
+ACLExprRaw_t *raw_expr;
+
+ if ( acl_expr == NULL )
+ return(ACLERRUNDEF);
+
+ if ( acl_expr->expr_raw_index >= acl_expr->expr_raw_size ) {
+ acl_expr->expr_raw = ( ACLExprRaw_t *)
+ PERM_REALLOC ( acl_expr->expr_raw,
+ (acl_expr->expr_raw_size + ACL_TERM_BSIZE)
+ * sizeof(ACLExprRaw_t) );
+ if ( acl_expr->expr_raw == NULL )
+ return(ACLERRNOMEM);
+ acl_expr->expr_raw_size += ACL_TERM_BSIZE;
+ }
+
+ raw_expr = &acl_expr->expr_raw[acl_expr->expr_raw_index];
+ acl_expr->expr_raw_index++;
+
+ raw_expr->logical = ACL_EXPR_OP_AND;
+ raw_expr->attr_name = NULL;
+
+ /* Find the last two expressions */
+ idx = acl_expr->expr_term_index - 1;
+ for ( ii = idx; ii >= 0; ii-- ) {
+ if ( acl_expr->expr_arry[ii].start_flag ) {
+ if ( expr_two == ACL_FALSE_IDX )
+ expr_two = ii;
+ else if ( expr_one == ACL_FALSE_IDX ) {
+ expr_one = ii;
+ break;
+ }
+ }
+ }
+
+#ifdef DEBUG_LEVEL_2
+ printf("and, index=%d, first expr=%d, second expr=%d\n", idx, expr_one, expr_two);
+#endif
+
+ for ( ii = expr_one; ii < expr_two; ii++) {
+ if ( acl_expr->expr_arry[ii].true_idx == ACL_TRUE_IDX )
+ acl_expr->expr_arry[ii].true_idx = expr_two;
+ if ( acl_expr->expr_arry[ii].false_idx == ACL_TRUE_IDX )
+ acl_expr->expr_arry[ii].false_idx = expr_two;
+ }
+
+ acl_expr->expr_arry[expr_two].start_flag = 0;
+ return(0);
+}
+
+/*
+ * Logical 'or' the previous two terms or subexpressions.
+ *
+ * Input:
+ * errp The error stack
+ * acl_expr The terms or subexpressions
+ * Output:
+ * acl_expr The expression after logical 'or'
+ */
+
+NSAPI_PUBLIC int
+ACL_ExprOr( NSErr_t *errp, ACLExprHandle_t *acl_expr )
+{
+int idx;
+int ii;
+int expr_one = ACL_FALSE_IDX;
+int expr_two = ACL_FALSE_IDX;
+ACLExprRaw_t *raw_expr;
+
+ if ( acl_expr == NULL )
+ return(ACLERRUNDEF);
+
+ if ( acl_expr->expr_raw_index >= acl_expr->expr_raw_size ) {
+ acl_expr->expr_raw = ( ACLExprRaw_t *)
+ PERM_REALLOC ( acl_expr->expr_raw,
+ (acl_expr->expr_raw_size + ACL_TERM_BSIZE)
+ * sizeof(ACLExprRaw_t) );
+ if ( acl_expr->expr_raw == NULL )
+ return(ACLERRNOMEM);
+ acl_expr->expr_raw_size += ACL_TERM_BSIZE;
+ }
+
+ raw_expr = &acl_expr->expr_raw[acl_expr->expr_raw_index];
+ acl_expr->expr_raw_index++;
+
+ raw_expr->logical = ACL_EXPR_OP_OR;
+ raw_expr->attr_name = NULL;
+
+ /* Find the last two expressions */
+ idx = acl_expr->expr_term_index - 1;
+ for ( ii = idx; ii >= 0; ii-- ) {
+ if ( acl_expr->expr_arry[ii].start_flag ) {
+ if ( expr_two == ACL_FALSE_IDX )
+ expr_two = ii;
+ else if ( expr_one == ACL_FALSE_IDX ) {
+ expr_one = ii;
+ break;
+ }
+ }
+ }
+
+#ifdef DEBUG_LEVEL_2
+ printf("or, index=%d, first expr=%d, second expr=%d\n", idx, expr_one, expr_two);
+#endif
+
+ for ( ii = expr_one; ii < expr_two; ii++) {
+ if ( acl_expr->expr_arry[ii].true_idx == ACL_FALSE_IDX )
+ acl_expr->expr_arry[ii].true_idx = expr_two;
+ if ( acl_expr->expr_arry[ii].false_idx == ACL_FALSE_IDX )
+ acl_expr->expr_arry[ii].false_idx = expr_two;
+ }
+ acl_expr->expr_arry[expr_two].start_flag = 0;
+
+ return(0);
+}
+
+/*
+ * INTERNAL FUNCTION (GLOBAL)
+ *
+ * Write an expression array to standard output. This
+ * is only useful debugging.
+ */
+
+int
+ACL_ExprDisplay( ACLExprHandle_t *acl_expr )
+{
+int ii;
+char buffer[256];
+
+ if ( acl_expr == NULL )
+ return(0);
+
+ for ( ii = 0; ii < acl_expr->expr_term_index; ii++ ) {
+ printf ("%d: if ( %s %s %s ) ",
+ ii,
+ acl_expr->expr_arry[ii].attr_name,
+ acl_comp_string( acl_expr->expr_arry[ii].comparator ),
+ acl_expr->expr_arry[ii].attr_pattern );
+
+ printf("%s ", acl_index_string(acl_expr->expr_arry[ii].true_idx, buffer));
+ printf("else %s\n",
+ acl_index_string(acl_expr->expr_arry[ii].false_idx, buffer) );
+ }
+
+ return(0);
+}
+
+/*
+ * Creates a handle for a new list of ACLs
+ *
+ * This function creates a new list of ACLs. The list is initially empty
+ * and can be added to by ACL_ListAppend(). A resource manager would use
+ * these functions to build up a list of all the ACLs applicable to a
+ * particular resource access.
+ *
+ * Input:
+ * Returns:
+ * NULL failure, otherwise returns a new
+ * ACLListHandle
+ */
+
+NSAPI_PUBLIC ACLListHandle_t *
+ACL_ListNew(NSErr_t *errp)
+{
+ACLListHandle_t *handle;
+
+ handle = ( ACLListHandle_t * ) PERM_CALLOC ( sizeof(ACLListHandle_t) );
+ handle->ref_count = 1;
+ return(handle);
+}
+
+/*
+ * Allocates a handle for an ACL wrapper
+ *
+ * This wrapper is just used for ACL list creation. It's a way of
+ * linking ACLs into a list. This is an internal function.
+ */
+
+static ACLWrapper_t *
+acl_wrapper_new(void)
+{
+ACLWrapper_t *handle;
+
+ handle = ( ACLWrapper_t * ) PERM_CALLOC ( sizeof(ACLWrapper_t) );
+ return(handle);
+}
+
+/*
+ * Description
+ *
+ * This function destroys an entry a symbol table entry for an
+ * ACL.
+ *
+ * Arguments:
+ *
+ * sym - pointer to Symbol_t for an ACL entry
+ * argp - unused (must be zero)
+ *
+ * Returns:
+ *
+ * The return value is SYMENUMREMOVE.
+ */
+
+static
+int acl_hash_entry_destroy(Symbol_t * sym, void * argp)
+{
+ if (sym != 0) {
+
+ /* Free the acl name string if any */
+ if (sym->sym_name != 0) {
+ PERM_FREE(sym->sym_name);
+ }
+
+ /* Free the Symbol_t structure */
+ PERM_FREE(sym);
+ }
+
+ /* Indicate that the symbol table entry should be removed */
+ return SYMENUMREMOVE;
+}
+
+
+/*
+ * LOCAL FUNCTION
+ *
+ * Create a new symbol with the sym_name equal to the
+ * acl->tag value. Attaches the acl to the sym_data
+ * pointer.
+ */
+
+static Symbol_t *
+acl_sym_new(ACLHandle_t *acl)
+{
+ Symbol_t *sym;
+ /* It's not there, so add it */
+ sym = (Symbol_t *) PERM_MALLOC(sizeof(Symbol_t));
+ if ( sym == NULL )
+ return(NULL);
+
+ sym->sym_name = PERM_STRDUP(acl->tag);
+ if ( sym->sym_name == NULL ) {
+ PERM_FREE(sym);
+ return(NULL);
+ }
+
+ sym->sym_type = ACLSYMACL;
+ sym->sym_data = (void *) acl;
+ return(sym);
+
+}
+
+/*
+ * LOCAL FUNCTION
+ *
+ * Add a acl symbol to an acl_list's symbol table.
+ *
+ * Each acl list has a symbol table. the symbol table
+ * is a quick qay to reference named acl's
+ */
+
+static int
+acl_sym_add(ACLListHandle_t *acl_list, ACLHandle_t *acl)
+{
+Symbol_t *sym;
+int rv;
+
+ if ( acl->tag == NULL )
+ return(ACLERRUNDEF);
+
+ rv = symTableFindSym(acl_list->acl_sym_table,
+ acl->tag,
+ ACLSYMACL,
+ (void **)&sym);
+ if ( rv == SYMERRNOSYM ) {
+ sym = acl_sym_new(acl);
+ if ( sym )
+ rv = symTableAddSym(acl_list->acl_sym_table, sym, (void *)sym);
+ }
+
+ if ( sym == NULL || rv < 0 )
+ return(ACLERRUNDEF);
+
+ return(0);
+}
+
+/*
+ * LOCAL FUNCTION
+ *
+ * Destroy an acl_list's symbol table and all memory referenced
+ * by the symbol table. This does not destroy an acl_list.
+ */
+
+static void
+acl_symtab_destroy(ACLListHandle_t *acl_list)
+{
+ /* Destroy each entry in the symbol table */
+ symTableEnumerate(acl_list->acl_sym_table, 0, acl_hash_entry_destroy);
+ /* Destory the hash table itself */
+ symTableDestroy(acl_list->acl_sym_table, 0);
+ acl_list->acl_sym_table = NULL;
+ return;
+}
+
+
+/*
+ * Appends to a specified ACL
+ *
+ * This function appends a specified ACL to the end of a given ACL list.
+ *
+ * Input:
+ * errp The error stack
+ * flags should always be zero now
+ * acl_list target ACL list
+ * acl new acl
+ * Returns:
+ * > 0 The number of acl's in the current list
+ * < 0 failure
+ */
+
+NSAPI_PUBLIC int
+ACL_ListAppend( NSErr_t *errp, ACLListHandle_t *acl_list, ACLHandle_t *acl,
+ int flags )
+{
+ ACLWrapper_t *wrapper;
+ ACLHandle_t *tmp_acl;
+
+ if ( acl_list == NULL || acl == NULL )
+ return(ACLERRUNDEF);
+
+ if ( acl_list->acl_sym_table == NULL &&
+ acl_list->acl_count == ACL_TABLE_THRESHOLD ) {
+
+ /*
+ * The symbol table isn't really critical so we don't log
+ * an error if its creation fails.
+ */
+
+ symTableNew(&acl_list->acl_sym_table);
+ if ( acl_list->acl_sym_table ) {
+ for (wrapper = acl_list->acl_list_head; wrapper;
+ wrapper = wrapper->wrap_next ) {
+ tmp_acl = wrapper->acl;
+ if ( acl_sym_add(acl_list, tmp_acl) ) {
+ acl_symtab_destroy(acl_list);
+ break;
+ }
+ }
+ }
+ }
+
+ wrapper = acl_wrapper_new();
+ if ( wrapper == NULL )
+ return(ACLERRNOMEM);
+
+ wrapper->acl = acl;
+
+ if ( acl_list->acl_list_head == NULL ) {
+ acl_list->acl_list_head = wrapper;
+ acl_list->acl_list_tail = wrapper;
+ } else {
+ acl_list->acl_list_tail->wrap_next = wrapper;
+ acl_list->acl_list_tail = wrapper;
+ }
+
+ acl->ref_count++;
+
+ acl_list->acl_count++;
+
+
+ if ( acl_list->acl_sym_table ) {
+ /*
+ * If we fail to insert the ACL then we
+ * might as well destroy this hash table since it is
+ * useless.
+ */
+ if ( acl_sym_add(acl_list, acl) ) {
+ acl_symtab_destroy(acl_list);
+ }
+ }
+
+
+ return(acl_list->acl_count);
+}
+
+/*
+ * Concatenates two ACL lists
+ *
+ * Attaches all ACLs in acl_list2 to the end of acl_list1. acl_list2
+ * is left unchanged.
+ *
+ * Input:
+ * errp pointer to the error stack
+ * acl_list1 target ACL list
+ * acl_list2 source ACL list
+ * Output:
+ * acl_list1 list contains the concatenation of acl_list1
+ * and acl_list2.
+ * Returns:
+ * > 0 Number of ACLs in acl_list1 after concat
+ * < 0 failure
+ */
+
+NSAPI_PUBLIC int
+ACL_ListConcat( NSErr_t *errp, ACLListHandle_t *acl_list1,
+ ACLListHandle_t *acl_list2, int flags )
+{
+ACLWrapper_t *wrapper;
+int rv;
+
+ if ( acl_list1 == NULL || acl_list2 == NULL )
+ return(ACLERRUNDEF);
+
+ for ( wrapper = acl_list2->acl_list_head;
+ wrapper != NULL; wrapper = wrapper->wrap_next )
+ if ( (rv = ACL_ListAppend ( errp, acl_list1, wrapper->acl, 0 )) < 0 )
+ return(rv);
+
+ return(acl_list1->acl_count);
+}
+
+/*
+ * LOCAL FUNCTION
+ *
+ * Free up memory associated with and ACLExprEntry. Probably
+ * only useful internally since we aren't exporting
+ * this structure.
+ */
+
+static void
+ACL_ExprEntryDestroy( ACLExprEntry_t *entry )
+{
+ LASFlushFunc_t flushp;
+
+ if ( entry == NULL )
+ return;
+
+ if ( entry->las_cookie )
+/* freeLAS(NULL, entry->attr_name, &entry->las_cookie); */
+ {
+ ACL_LasFindFlush( NULL, entry->attr_name, &flushp );
+ if ( flushp )
+ ( *flushp )( &entry->las_cookie );
+ }
+
+ if ( entry->attr_name )
+ PERM_FREE( entry->attr_name );
+
+ if ( entry->attr_pattern )
+ PERM_FREE( entry->attr_pattern );
+
+ return;
+}
+
+/*
+ * LOCAL FUNCTION
+ *
+ * This function is used to free all the pvalue memory
+ * in a plist.
+ */
+
+static void
+acl_expr_auth_destroy(char *pname, const void *pvalue, void *user_data)
+{
+ PERM_FREE((char *) pvalue);
+ return;
+}
+
+/*
+ * Free up memory associated with and ACLExprHandle.
+ *
+ * Input:
+ * expr expression handle to free up
+ */
+
+NSAPI_PUBLIC void
+ACL_ExprDestroy( ACLExprHandle_t *expr )
+{
+int ii;
+
+ if ( expr == NULL )
+ return;
+
+ if ( expr->expr_tag )
+ PERM_FREE( expr->expr_tag );
+
+ if ( expr->expr_argv ) {
+ for ( ii = 0; ii < expr->expr_argc; ii++ )
+ if ( expr->expr_argv[ii] )
+ PERM_FREE( expr->expr_argv[ii] );
+ PERM_FREE( expr->expr_argv );
+ }
+
+ for ( ii = 0; ii < expr->expr_term_index; ii++ )
+ ACL_ExprEntryDestroy( &expr->expr_arry[ii] );
+
+ if ( expr->expr_auth ) {
+ PListEnumerate(expr->expr_auth, acl_expr_auth_destroy, NULL);
+ PListDestroy(expr->expr_auth);
+ }
+
+ PERM_FREE( expr->expr_arry );
+ PERM_FREE( expr->expr_raw );
+
+ PERM_FREE( expr );
+
+ return;
+}
+
+/*
+ * Free up memory associated with and ACLHandle.
+ *
+ * Input:
+ * acl target acl
+ */
+
+NSAPI_PUBLIC void
+ACL_AclDestroy(NSErr_t *errp, ACLHandle_t *acl )
+{
+ACLExprHandle_t *handle;
+ACLExprHandle_t *tmp;
+
+ if ( acl == NULL )
+ return;
+
+ acl->ref_count--;
+
+ if ( acl->ref_count )
+ return;
+
+ if ( acl->tag )
+ PERM_FREE( acl->tag );
+
+ if ( acl->las_name )
+ PERM_FREE( acl->las_name );
+
+ if ( acl->attr_name )
+ PERM_FREE( acl->attr_name );
+
+ handle = acl->expr_list_head;
+ while ( handle ) {
+ tmp = handle;
+ handle = handle->expr_next;
+ ACL_ExprDestroy( tmp );
+ }
+
+ PERM_FREE(acl);
+
+ return;
+}
+
+/*
+ * Destorys a input ACL List
+ *
+ * Input:
+ * acl_list target list
+ * Output:
+ * none target list is freed
+ */
+
+NSAPI_PUBLIC void
+ACL_ListDestroy(NSErr_t *errp, ACLListHandle_t *acl_list )
+{
+ ACLWrapper_t *wrapper;
+ ACLWrapper_t *tmp_wrapper;
+ ACLHandle_t *tmp_acl;
+
+
+ if ( acl_list == NULL )
+ return;
+
+ if ( acl_list->acl_sym_table ) {
+ /* Destroy each entry in the symbol table */
+ symTableEnumerate(acl_list->acl_sym_table, 0, acl_hash_entry_destroy);
+ /* Destory the hash table itself */
+ symTableDestroy(acl_list->acl_sym_table, 0);
+ }
+
+ ACL_EvalDestroyContext( (ACLListCache_t *)acl_list->cache );
+
+ wrapper = acl_list->acl_list_head;
+
+ while ( wrapper ) {
+ tmp_acl = wrapper->acl;
+ tmp_wrapper = wrapper;
+ wrapper = wrapper->wrap_next;
+ PERM_FREE( tmp_wrapper );
+ ACL_AclDestroy(errp, tmp_acl );
+ }
+
+ PERM_FREE( acl_list );
+
+ return;
+}
+
+/*
+ * FUNCTION: ACL_ListGetFirst
+ *
+ * DESCRIPTION:
+ *
+ * This function is used to start an enumeration of an
+ * ACLListHandle_t. It returns an ACLHandle_t* for the first
+ * ACL on the list, and initializes a handle supplied by the
+ * caller, which is used to track the current position in the
+ * enumeration. This function is normally used in a loop
+ * such as:
+ *
+ * ACLListHandle_t *acl_list = <some ACL list>;
+ * ACLHandle_t *cur_acl;
+ * ACLListEnum_t acl_enum;
+ *
+ * for (cur_acl = ACL_ListGetFirst(acl_list, &acl_enum);
+ * cur_acl != 0;
+ * cur_acl = ACL_ListGetNext(acl_list, &acl_enum)) {
+ * ...
+ * }
+ *
+ * The caller should guarantee that no ACLs are added or removed
+ * from the ACL list during the enumeration.
+ *
+ * ARGUMENTS:
+ *
+ * acl_list - handle for the ACL list
+ * acl_enum - pointer to uninitialized enumeration handle
+ *
+ * RETURNS:
+ *
+ * As described above. If the acl_list argument is null, or the
+ * referenced ACL list is empty, the return value is null.
+ */
+
+NSAPI_PUBLIC ACLHandle_t *
+ACL_ListGetFirst(ACLListHandle_t *acl_list, ACLListEnum_t *acl_enum)
+{
+ ACLWrapper_t *wrapper;
+ ACLHandle_t *acl = 0;
+
+ *acl_enum = 0;
+
+ if (acl_list) {
+
+ wrapper = acl_list->acl_list_head;
+ *acl_enum = (ACLListEnum_t)wrapper;
+
+ if (wrapper) {
+ acl = wrapper->acl;
+ }
+ }
+
+ return acl;
+}
+
+NSAPI_PUBLIC ACLHandle_t *
+ACL_ListGetNext(ACLListHandle_t *acl_list, ACLListEnum_t *acl_enum)
+{
+ ACLWrapper_t *wrapper = (ACLWrapper_t *)(*acl_enum);
+ ACLHandle_t *acl = 0;
+
+ if (wrapper) {
+
+ wrapper = wrapper->wrap_next;
+ *acl_enum = (ACLListEnum_t)wrapper;
+
+ if (wrapper) acl = wrapper->acl;
+ }
+
+ return acl;
+}
+
+/*
+ * FUNCTION: ACL_AclGetTag
+ *
+ * DESCRIPTION:
+ *
+ * Returns the tag string associated with an ACL.
+ *
+ * ARGUMENTS:
+ *
+ * acl - handle for an ACL
+ *
+ * RETURNS:
+ *
+ * The return value is a pointer to the ACL tag string.
+ */
+
+NSAPI_PUBLIC const char *
+ACL_AclGetTag(ACLHandle_t *acl)
+{
+ return (acl) ? (const char *)(acl->tag) : 0;
+}
+
+/*
+ * Finds a named ACL in an input list.
+ *
+ * Input:
+ * acl_list a list of ACLs to search
+ * acl_name the name of the ACL to find
+ * flags e.g. ACL_CASE_INSENSITIVE
+ * Returns:
+ * NULL No ACL found
+ * acl A pointer to an ACL with named acl_name
+ */
+
+NSAPI_PUBLIC ACLHandle_t *
+ACL_ListFind (NSErr_t *errp, ACLListHandle_t *acl_list, char *acl_name, int flags )
+{
+ACLHandle_t *result = NULL;
+ACLWrapper_t *wrapper;
+Symbol_t *sym;
+
+ if ( acl_list == NULL || acl_name == NULL )
+ return( result );
+
+ /*
+ * right now the symbol table exists if there hasn't been
+ * any collisions based on using case insensitive names.
+ * if there are any collisions then the table will be
+ * deleted and we will look up using list search.
+ *
+ * we should probably create two hash tables, one for case
+ * sensitive lookups and the other for insensitive.
+ */
+ if ( acl_list->acl_sym_table ) {
+ if ( symTableFindSym(acl_list->acl_sym_table,
+ acl_name, ACLSYMACL, (void **) &sym) >= 0 ) {
+ result = (ACLHandle_t *) sym->sym_data;
+ if ( result && (flags & ACL_CASE_SENSITIVE) &&
+ strcmp(result->tag, acl_name) ) {
+ result = NULL; /* case doesn't match */
+ }
+ }
+ return( result );
+ }
+
+ if ( flags & ACL_CASE_INSENSITIVE ) {
+ for ( wrapper = acl_list->acl_list_head; wrapper != NULL;
+ wrapper = wrapper->wrap_next ) {
+ if ( wrapper->acl->tag &&
+ strcasecmp( wrapper->acl->tag, acl_name ) == 0 ) {
+ result = wrapper->acl;
+ break;
+ }
+ }
+ } else {
+ for ( wrapper = acl_list->acl_list_head; wrapper != NULL;
+ wrapper = wrapper->wrap_next ) {
+ if ( wrapper->acl->tag &&
+ strcmp( wrapper->acl->tag, acl_name ) == 0 ) {
+ result = wrapper->acl;
+ break;
+ }
+ }
+ }
+
+ return( result );
+}
+
+/*
+ * Function parses an input ACL file and resturns an
+ * ACLListHandle_t pointer that represents the entire
+ * file without the comments.
+ *
+ * Input:
+ * filename the name of the target ACL text file
+ * errp a pointer to an error stack
+ *
+ * Returns:
+ * NULL parse failed
+ *
+ */
+
+NSAPI_PUBLIC ACLListHandle_t *
+ACL_ParseFile( NSErr_t *errp, char *filename )
+{
+ACLListHandle_t *handle = NULL;
+int eid = 0;
+int rv = 0;
+char *errmsg;
+
+ ACL_InitAttr2Index();
+
+ if ( acl_parse_crit == NULL )
+ acl_parse_crit = crit_init();
+
+ crit_enter( acl_parse_crit );
+
+ if ( acl_InitScanner( errp, filename, NULL ) < 0 ) {
+ rv = ACLERROPEN;
+ eid = ACLERR1900;
+ errmsg = system_errmsg();
+ nserrGenerate(errp, rv, eid, ACL_Program, 2, filename, errmsg);
+ } else {
+
+ handle = ACL_ListNew(errp);
+ if ( handle == NULL ) {
+ rv = ACLERRNOMEM;
+ eid = ACLERR1920;
+ nserrGenerate(errp, rv, eid, ACL_Program, 0);
+ } else if ( acl_PushListHandle( handle ) < 0 ) {
+ rv = ACLERRNOMEM;
+ eid = ACLERR1920;
+ nserrGenerate(errp, rv, eid, ACL_Program, 0);
+ } else if ( acl_Parse() ) {
+ rv = ACLERRPARSE;
+ eid = ACLERR1780;
+ }
+
+ if ( acl_EndScanner() < 0 ) {
+ rv = ACLERROPEN;
+ eid = ACLERR1500;
+ errmsg = system_errmsg();
+ nserrGenerate(errp, rv, eid, ACL_Program, 2, filename, errmsg);
+ }
+
+ }
+
+ if ( rv || eid ) {
+ ACL_ListDestroy(errp, handle);
+ handle = NULL;
+ }
+
+ crit_exit( acl_parse_crit );
+ return(handle);
+
+}
+
+/*
+ * Function parses an input ACL string and returns an
+ * ACLListHandle_t pointer that represents the entire
+ * file without the comments.
+ *
+ * Input:
+ * buffer the target ACL buffer
+ * errp a pointer to an error stack
+ *
+ * Returns:
+ * NULL parse failed
+ *
+ */
+
+NSAPI_PUBLIC ACLListHandle_t *
+ACL_ParseString( NSErr_t *errp, char *buffer )
+{
+ACLListHandle_t *handle = NULL;
+int eid = 0;
+int rv = 0;
+char *errmsg;
+
+ ACL_InitAttr2Index();
+
+ if ( acl_parse_crit == NULL )
+ acl_parse_crit = crit_init();
+
+ crit_enter( acl_parse_crit );
+
+ if ( acl_InitScanner( errp, NULL, buffer ) < 0 ) {
+ rv = ACLERRNOMEM;
+ eid = ACLERR1920;
+ nserrGenerate(errp, rv, eid, ACL_Program, 0);
+ } else {
+
+ handle = ACL_ListNew(errp);
+ if ( handle == NULL ) {
+ rv = ACLERRNOMEM;
+ eid = ACLERR1920;
+ nserrGenerate(errp, rv, eid, ACL_Program, 0);
+ } else if ( acl_PushListHandle( handle ) < 0 ) {
+ rv = ACLERRNOMEM;
+ eid = ACLERR1920;
+ nserrGenerate(errp, rv, eid, ACL_Program, 0);
+ } else if ( acl_Parse() ) {
+ rv = ACLERRPARSE;
+ eid = ACLERR1780;
+ }
+
+ if ( acl_EndScanner() < 0 ) {
+ rv = ACLERROPEN;
+ eid = ACLERR1500;
+ errmsg = system_errmsg();
+ nserrGenerate(errp, rv, eid, ACL_Program, 2, "buffer", errmsg);
+ }
+
+ }
+
+ if ( rv || eid ) {
+ ACL_ListDestroy(errp, handle);
+ handle = NULL;
+ }
+
+ crit_exit( acl_parse_crit );
+ return(handle);
+
+}
+
+/*
+ * LOCAL FUNCTION
+ *
+ * Convert sub-expression to string.
+ */
+
+static int
+acl_expr_string( ACLExprOp_t logical, ACLExprStack_t *expr_stack )
+{
+char **expr_text;
+char **prev_expr_text;
+char *tmp;
+
+ switch (logical) {
+ case ACL_EXPR_OP_NOT:
+ if ( expr_stack->stack_index < 1 ) {
+ printf("expression stack underflow.\n");
+ return(ACLERRINTERNAL);
+ }
+
+ expr_text = &expr_stack->expr_text[expr_stack->stack_index - 1];
+ tmp = (char *) PERM_MALLOC(strlen(*expr_text) + 7);
+ if ( tmp == NULL )
+ return(ACLERRNOMEM);
+
+ if ( expr_stack->found_subexpression ) {
+ sprintf(tmp, "not (%s)", *expr_text);
+ expr_stack->found_subexpression = 0;
+ expr_stack->last_subexpression = expr_stack->stack_index - 1;
+ } else {
+ sprintf(tmp, "not %s", *expr_text);
+ }
+
+ PERM_FREE(*expr_text);
+ *expr_text = tmp;
+ return(0);
+
+ case ACL_EXPR_OP_AND:
+ case ACL_EXPR_OP_OR:
+ if ( expr_stack->stack_index < 2 ) {
+ printf("expression stack underflow.\n");
+ return(ACLERRINTERNAL);
+ }
+
+ expr_stack->stack_index--;
+ prev_expr_text = &expr_stack->expr_text[expr_stack->stack_index];
+ expr_stack->stack_index--;
+ expr_text = &expr_stack->expr_text[expr_stack->stack_index];
+
+ tmp = (char *) PERM_MALLOC (strlen(*expr_text)
+ + strlen(*prev_expr_text) + 15);
+ if ( tmp == NULL )
+ return(ACLERRNOMEM);
+
+ if ( expr_stack->found_subexpression &&
+ expr_stack->stack_index == expr_stack->last_subexpression &&
+ logical == ACL_EXPR_OP_AND ) {
+ sprintf(tmp, "%s and\n (%s)", *expr_text, *prev_expr_text);
+ } else if ( expr_stack->found_subexpression &&
+ expr_stack->stack_index == expr_stack->last_subexpression ) {
+ sprintf(tmp, "%s or\n (%s)", *expr_text, *prev_expr_text);
+ } else if ( logical == ACL_EXPR_OP_AND ) {
+ sprintf(tmp, "%s and\n %s", *expr_text, *prev_expr_text);
+ } else {
+ sprintf(tmp, "%s or\n %s", *expr_text, *prev_expr_text);
+ }
+
+ expr_stack->found_subexpression++;
+ expr_stack->stack_index++;
+ PERM_FREE(*expr_text);
+ PERM_FREE(*prev_expr_text);
+ *expr_text = tmp;
+ *prev_expr_text = NULL;
+ return(0);
+
+ default:
+ printf("Bad boolean logic value.\n");
+ return(ACLERRINTERNAL);
+ }
+
+}
+
+/*
+ * LOCAL FUNCTION
+ *
+ * Reduce all sub-expressions to a single string.
+ */
+
+static int
+acl_reduce_expr_logic( ACLExprStack_t *expr_stack, ACLExprRaw_t *expr_raw )
+{
+char **expr_text;
+char **prev_expr_text;
+char *tmp;
+
+ if (expr_raw->attr_name) {
+ if (expr_stack->stack_index >= ACL_EXPR_STACK ) {
+ printf("expression stack overflow.");
+ return(ACLERRINTERNAL);
+ }
+
+ if ( expr_stack->found_subexpression && expr_stack->stack_index > 0 ) {
+ prev_expr_text = &expr_stack->expr_text[expr_stack->stack_index-1];
+ tmp = (char *) PERM_MALLOC(strlen(*prev_expr_text) + 3);
+ sprintf(tmp, "(%s)", *prev_expr_text);
+ PERM_FREE(*prev_expr_text);
+ *prev_expr_text = tmp;
+ expr_stack->found_subexpression = 0;
+ expr_stack->last_subexpression = expr_stack->stack_index - 1;
+ }
+
+ expr_stack->expr[expr_stack->stack_index] = expr_raw;
+ expr_text = &expr_stack->expr_text[expr_stack->stack_index];
+ *expr_text = (char *) PERM_MALLOC(strlen(expr_raw->attr_name)
+ + strlen(expr_raw->attr_pattern)
+ + 7);
+ if ( *expr_text == NULL )
+ return(ACLERRNOMEM);
+
+ sprintf(*expr_text, "%s %s \"%s\"", expr_raw->attr_name,
+ acl_comp_string(expr_raw->comparator),
+ expr_raw->attr_pattern);
+
+ expr_stack->stack_index++;
+ expr_stack->expr_text[expr_stack->stack_index] = NULL;
+ } else {
+ return(acl_expr_string(expr_raw->logical, expr_stack));
+ }
+ return(0);
+}
+
+/*
+ * LOCAL FUNCTION
+ *
+ * Appends str2 to str1.
+ *
+ * Input:
+ * str1 an existing dynamically allocated string
+ * str2 a text string
+ * Returns:
+ * 0 success
+ * < 0 failure
+ */
+
+static int
+acl_to_str_append(acl_string_t * p_aclstr, const char *str2)
+{
+ int str2len, newlen;
+
+ if (p_aclstr == NULL || str2 == NULL)
+ return (ACLERRINTERNAL);
+ if (p_aclstr->str == NULL) {
+ p_aclstr->str = (char *) PERM_MALLOC(4096);
+ if (p_aclstr->str == NULL)
+ return (ACLERRNOMEM);
+ p_aclstr->str_size = 4096;
+ p_aclstr->str_len = 0;
+ }
+
+ str2len = strlen(str2);
+ newlen = p_aclstr->str_len + str2len;
+ if (newlen >= p_aclstr->str_size) {
+ p_aclstr->str_size = str2len > 4095 ? str2len+p_aclstr->str_size+1 : 4096+p_aclstr->str_size ;
+ p_aclstr->str = (char *) PERM_REALLOC(p_aclstr->str, p_aclstr->str_size);
+ if (p_aclstr->str == NULL)
+ return (ACLERRNOMEM);
+ }
+ memcpy((void *)&(p_aclstr->str[p_aclstr->str_len]), (void *) str2, str2len+1);
+ p_aclstr->str_len += str2len;
+ return 0;
+}
+
+/*
+ * LOCAL FUNCTION
+ *
+ * Output Authorization Expression type either "Allow" or "Deny"
+ */
+
+static int
+acl_to_str_expr_type( acl_string_t *str_t, ACLExprHandle_t *expr )
+{
+ switch (expr->expr_type) {
+ case ACL_EXPR_TYPE_ALLOW:
+ acl_to_str_append(str_t, "allow ");
+ if ( IS_ABSOLUTE(expr->expr_flags) )
+ acl_to_str_append(str_t, "absolute ");
+ return(0);
+ case ACL_EXPR_TYPE_DENY:
+ acl_to_str_append(str_t, "deny ");
+ if ( IS_ABSOLUTE(expr->expr_flags) )
+ acl_to_str_append(str_t, "absolute ");
+ return(0);
+ case ACL_EXPR_TYPE_AUTH:
+ acl_to_str_append(str_t, "authenticate ");
+ if ( IS_ABSOLUTE(expr->expr_flags) )
+ acl_to_str_append(str_t, "absolute ");
+ return(0);
+ case ACL_EXPR_TYPE_RESPONSE:
+ acl_to_str_append(str_t, "deny with ");
+ return(0);
+ default:
+ return(ACLERRINTERNAL);
+ }
+}
+
+/*
+ * LOCAL FUNCTION
+ *
+ * Output Authorization Expression Rights "(right, right)"
+ */
+
+static int
+acl_to_str_expr_arg( acl_string_t *str_t, ACLExprHandle_t *expr )
+{
+int ii;
+
+ if ( expr->expr_argc <= 0 ) {
+ return(ACLERRINTERNAL);
+ }
+
+ if ( expr->expr_type == ACL_EXPR_TYPE_RESPONSE ) {
+ acl_to_str_append(str_t, expr->expr_argv[0]);
+ acl_to_str_append(str_t, "=\"");
+ acl_to_str_append(str_t, expr->expr_argv[1]);
+ acl_to_str_append(str_t, "\";\n");
+ return(0);
+ }
+
+ acl_to_str_append(str_t, "(");
+ for (ii = 0; ii < expr->expr_argc; ii++) {
+ acl_to_str_append(str_t, expr->expr_argv[ii]);
+ if ( ii < expr->expr_argc - 1 ) {
+ acl_to_str_append(str_t, ",");
+ }
+ }
+ acl_to_str_append(str_t, ") ");
+
+ return(0);
+}
+
+/*
+ * LOCAL FUNCTION
+ *
+ * Walks through the authentication statement PList_t and
+ * prints the structure to a string.
+ */
+
+static void
+acl_to_str_auth_expr(char *lval, const void *rval, void *user_data)
+{
+ // ###### char **str = (char **) user_data;
+ acl_string_t * p_aclstr = (acl_string_t *) user_data;
+
+ acl_to_str_append(p_aclstr, "\t");
+ acl_to_str_append(p_aclstr, lval);
+ acl_to_str_append(p_aclstr, " = \"");
+ acl_to_str_append(p_aclstr, (char *) rval);
+ acl_to_str_append(p_aclstr, "\";\n");
+
+ return;
+}
+
+/*
+ * LOCAL FUNCTION
+ *
+ * Output the logic part of the authencation statement to a string.
+ */
+
+static int
+acl_to_str_auth_logic( acl_string_t *str_t, ACLExprHandle_t *expr)
+{
+
+ if ( expr->expr_auth == NULL ) {
+ acl_to_str_append(str_t, "{\n");
+ acl_to_str_append(str_t, "# Authenticate statement with no body?\n");
+ acl_to_str_append(str_t, "\tnull=null;\n");
+ acl_to_str_append(str_t, "};\n");
+ return(0);
+ }
+
+ acl_to_str_append(str_t, "{\n");
+ PListEnumerate(expr->expr_auth, acl_to_str_auth_expr, (void *) str_t);
+ acl_to_str_append(str_t, "};\n");
+
+ return(0);
+}
+
+
+/*
+ * LOCAL FUNCTION
+ *
+ * Output the logic part of the authorization statement to a string.
+ */
+
+static int
+acl_to_str_expr_logic( acl_string_t *str_t, ACLExprHandle_t *expr, ACLExprStack_t *expr_stack)
+{
+int rv = 0;
+int ii;
+
+ expr_stack->stack_index = 0;
+ expr_stack->found_subexpression = 0;
+ expr_stack->last_subexpression = -1;
+
+ for (ii = 0; ii < expr->expr_raw_index; ii++) {
+ rv = acl_reduce_expr_logic(expr_stack, &expr->expr_raw[ii]);
+ if (rv) break;
+ }
+
+ if (!rv && expr_stack->expr_text[0]) {
+ acl_to_str_append(str_t, "\n ");
+ acl_to_str_append(str_t, expr_stack->expr_text[0]);
+ acl_to_str_append(str_t, ";\n");
+ PERM_FREE(expr_stack->expr_text[0]);
+ }
+
+ return(rv);
+}
+
+/*
+ * LOCAL FUNCTION
+ *
+ * Output an ACL list to a string.
+ */
+
+static int
+acl_to_str_create( acl_string_t *str_t, ACLListHandle_t *acl_list )
+{
+ACLWrapper_t *wrap;
+ACLHandle_t *acl;
+ACLExprHandle_t *expr;
+int rv = 0;
+ACLExprStack_t *expr_stack;
+
+ expr_stack = (ACLExprStack_t *) PERM_MALLOC(sizeof(ACLExprStack_t));
+ if ( expr_stack == NULL )
+ return(ACLERRNOMEM);
+
+ acl_to_str_append(str_t, "# File automatically written\n");
+ acl_to_str_append(str_t, "#\n");
+ acl_to_str_append(str_t, "# You may edit this file by hand\n");
+ acl_to_str_append(str_t, "#\n\n");
+ if ( acl_list->acl_list_head == NULL ) {
+ PERM_FREE(expr_stack);
+ return(0);
+ }
+
+ acl_to_str_append(str_t, "version 3.0;\n");
+ for (wrap = acl_list->acl_list_head; wrap && !rv;
+ wrap = wrap->wrap_next ) {
+ acl = wrap->acl;
+ if ( acl->tag ) {
+ acl_to_str_append(str_t, "\nacl \"");
+ acl_to_str_append(str_t, acl->tag);
+ acl_to_str_append(str_t, "\";\n");
+ } else {
+ acl_to_str_append(str_t, "\nacl;\n");
+ }
+
+ for (expr = acl->expr_list_head; expr && rv == 0;
+ expr = expr->expr_next ) {
+
+ if ( (rv = acl_to_str_expr_type(str_t, expr)) < 0 )
+ break;
+
+ if ( (rv = acl_to_str_expr_arg(str_t, expr)) < 0)
+ break;
+
+ switch (expr->expr_type) {
+ case ACL_EXPR_TYPE_DENY:
+ case ACL_EXPR_TYPE_ALLOW:
+ rv = acl_to_str_expr_logic(str_t, expr, expr_stack);
+ break;
+ case ACL_EXPR_TYPE_AUTH:
+ rv = acl_to_str_auth_logic(str_t, expr);
+ break;
+ case ACL_EXPR_TYPE_RESPONSE:
+ break;
+ }
+
+ }
+ }
+
+ PERM_FREE(expr_stack);
+ return(rv);
+}
+
+
+/*
+ * Creates an ACL text string from an ACL handle
+ *
+ * Input:
+ * errp error stack
+ * acl target text string pointer
+ * acl_list Source ACL list handle
+ * Ouput:
+ * acl a chunk of dynamic memory pointing to ACL text
+ * Returns:
+ * 0 success
+ * < 0 failure
+ */
+
+NSAPI_PUBLIC int
+ACL_WriteString(NSErr_t *errp, char **acl, ACLListHandle_t *acl_list)
+{
+ int rv;
+ acl_string_t str_t = {NULL,0,0};
+
+ if ( acl_list == NULL || acl == NULL )
+ return(ACLERRUNDEF);
+
+ rv = acl_to_str_create(&str_t, acl_list);
+ *acl = str_t.str;
+
+ return ( rv );
+}
+
+/*
+ * Write an ACL text file from an input ACL list structure.
+ *
+ * Input:
+ * filename name for the output text file
+ * acl_list a list of ACLs to convert to text
+ * Output:
+ * errp an error stack, set if there are errors
+ * to report
+ * Returns:
+ * 0 success
+ * ACLERROPEN,
+ * ACLERRNOMEM on failure
+ */
+
+NSAPI_PUBLIC int
+ACL_WriteFile( NSErr_t *errp, char *filename, ACLListHandle_t *acl_list )
+{
+int rv;
+int eid;
+char *errmsg;
+#ifdef UTEST
+FILE *ofp;
+#else
+SYS_FILE ofp;
+#endif
+acl_string_t aclstr = {NULL,0,0};
+char *acl_text = NULL;
+
+ if ( filename == NULL || acl_list == NULL ) {
+ rv = ACLERROPEN;
+ eid = ACLERR1900;
+ errmsg = system_errmsg();
+ nserrGenerate(errp, rv, eid, ACL_Program, 2, filename, errmsg);
+ return(ACLERROPEN);
+ }
+
+#ifdef UTEST
+ ofp = fopen(filename, "w");
+ if ( ofp == NULL ) {
+#else
+ ofp = system_fopenWT(filename);
+ if ( ofp == SYS_ERROR_FD ) {
+#endif
+ rv = ACLERROPEN;
+ eid = ACLERR1900;
+ errmsg = system_errmsg();
+ nserrGenerate(errp, rv, eid, ACL_Program, 2, filename, errmsg);
+ return(ACLERROPEN);
+ }
+
+ rv = acl_to_str_create(&aclstr, acl_list);
+ acl_text = aclstr.str;
+
+ if ( rv ) {
+ eid = ACLERR3000;
+ rv = ACLERRNOMEM;
+ nserrGenerate(errp, rv, eid, ACL_Program, 0);
+ } else {
+#ifdef UTEST
+ if (fputs(acl_text, ofp) == 0) {
+#else
+ if (system_fwrite_atomic(ofp, acl_text, strlen(acl_text))==IO_ERROR) {
+#endif
+ eid = ACLERR3200;
+ rv = ACLERRIO;
+ errmsg = system_errmsg();
+ nserrGenerate(errp, rv, eid, ACL_Program, 2, filename, errmsg);
+ }
+ }
+
+ if ( acl_text )
+ PERM_FREE(acl_text);
+
+#ifdef UTEST
+ fclose(ofp);
+#else
+ system_fclose(ofp);
+#endif
+
+ return(rv);
+}
+
+/*
+ * Delete a named ACL from an ACL list
+ *
+ * Input:
+ * acl_list Target ACL list handle
+ * acl_name Name of the target ACL
+ * Returns:
+ * 0 success
+ * < 0 failure
+ */
+
+NSAPI_PUBLIC int
+ACL_ListAclDelete(NSErr_t *errp, ACLListHandle_t *acl_list, char *acl_name, int flags )
+{
+ACLHandle_t *acl = NULL;
+ACLWrapper_t *wrapper;
+ACLWrapper_t *wrapper_prev = NULL;
+Symbol_t *sym;
+
+ if ( acl_list == NULL || acl_name == NULL )
+ return(ACLERRUNDEF);
+
+ if ( flags & ACL_CASE_INSENSITIVE ) {
+ for ( wrapper = acl_list->acl_list_head; wrapper != NULL;
+ wrapper = wrapper->wrap_next ) {
+ if ( wrapper->acl->tag &&
+ strcasecmp( wrapper->acl->tag, acl_name ) == 0 ) {
+ acl = wrapper->acl;
+ break;
+ }
+ wrapper_prev = wrapper;
+ }
+ } else {
+ for ( wrapper = acl_list->acl_list_head; wrapper != NULL;
+ wrapper = wrapper->wrap_next ) {
+ if ( wrapper->acl->tag &&
+ strcmp( wrapper->acl->tag, acl_name ) == 0 ) {
+ acl = wrapper->acl;
+ break;
+ }
+ wrapper_prev = wrapper;
+ }
+ }
+
+ if ( acl ) {
+
+ if ( wrapper_prev ) {
+ wrapper_prev->wrap_next = wrapper->wrap_next;
+ } else {
+ acl_list->acl_list_head = wrapper->wrap_next;
+ }
+
+ if ( acl_list->acl_list_tail == wrapper ) {
+ acl_list->acl_list_tail = wrapper_prev;
+ }
+
+ acl = wrapper->acl;
+ acl_list->acl_count--;
+ PERM_FREE(wrapper);
+
+ if ( acl_list->acl_sym_table ) {
+ if ( symTableFindSym(acl_list->acl_sym_table,
+ acl->tag, ACLSYMACL, (void **) &sym) < 0 ) {
+
+ /* not found, this is an error of some sort */
+
+ } else {
+ symTableRemoveSym(acl_list->acl_sym_table, sym);
+ acl_hash_entry_destroy(sym, 0);
+ }
+ }
+
+ ACL_AclDestroy(errp, acl);
+ return(0);
+ }
+
+ return(ACLERRUNDEF);
+}
+
+/*
+ * local function: translate string to lower case
+ * return <0: fail
+ * 0: succeed
+ */
+int
+open_file_buf(FILE ** file, char * filename, char *mode, char ** buf, long * size)
+{
+ int rv = 0;
+ long cur = 0;
+ long in = 0;
+ struct stat fi;
+
+ if (filename==NULL || mode==NULL) {
+ rv = ACLERROPEN;
+ goto open_cleanup;
+ }
+
+ if ((*file=fopen(filename,mode))==NULL) {
+ rv = ACLERROPEN;
+ goto open_cleanup;
+ }
+
+ if (system_stat(filename, &fi)==-1) {
+ rv = ACLERROPEN;
+ goto open_cleanup;
+ }
+
+ *size = fi.st_size;
+
+ if ((*buf=(char *)PERM_MALLOC(*size+1))==NULL) {
+ rv = ACLERRNOMEM;
+ goto open_cleanup;
+ }
+
+
+ rv = 0;
+ while (cur<*size) {
+ in=fread(&(*buf)[cur], 1, *size, *file);
+ cur = cur+in;
+ if (feof(*file)) {
+ break;
+ }
+ if (ferror(*file)) {
+ rv = ACLERRIO;
+ break;
+ }
+ }
+ if (rv==0)
+ (*buf)[cur] = 0;
+
+open_cleanup:
+ if (rv<0) {
+ if (*file)
+ fclose(*file);
+ if (*buf)
+ PERM_FREE(*buf);
+ }
+ return rv;
+}
+
+
+/*
+ * local function: writes buf to disk and close the file
+ */
+void
+close_file_buf(FILE * file, char * filename, char * mode, char * buf)
+{
+ if (file==NULL)
+ return;
+ fclose(file);
+ if (strchr(mode, 'w')!=NULL || strchr(mode, 'a')!=NULL) {
+ file = fopen(filename, "wb");
+ fwrite(buf,1,strlen(buf),file);
+ fclose(file);
+ }
+ PERM_FREE(buf);
+}
+
+
+/*
+ * local function: translate string to lower case
+ */
+char *
+str_tolower(char * string)
+{
+ register char * p = string;
+ for (; *p; p++)
+ *p = tolower(*p);
+ return string;
+}
+
+/*
+ * local function: get the first name appear in block
+ * return: 0 : not found,
+ * 1 : found
+ */
+int
+acl_get_first_name(char * block, char ** name, char ** next)
+{
+ char bounds[] = "\t \"\';";
+ char boundchar;
+ char *p=NULL, *q=NULL, *start=NULL, *end=NULL;
+
+ if (block==NULL)
+ return 0;
+try_next:
+ if ((p=strstr(block, "acl"))!=NULL) {
+
+ // check if this "acl" is the first occurance in this line.
+ for (q=p-1; ((q>=block) && *q!='\n'); q--) {
+ if (strchr(" \t",*q)==NULL) {
+ // if not, try next;
+ block = p+3;
+ goto try_next;
+ }
+ }
+
+ p+=3;
+ while (strchr(bounds,*p)&&(*p!=0))
+ p++;
+ if (*p==0)
+ return 0;
+ boundchar = *(p-1);
+ start = p;
+ while ((boundchar!=*p)&&(*p!=0)&&(*p!=';'))
+ p++;
+ if (*p==0)
+ return 0;
+ end = p;
+ *name = (char *)PERM_MALLOC(end-start+1);
+ strncpy(*name, start, (end-start));
+ (*name)[end-start]=0;
+ *next = end;
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * local function: find the pointer to acl string from the given block
+ */
+char *
+acl_strstr(char * block, char * aclname)
+{
+ const char set[] = "\t \"\';";
+ char * name, * rstr = NULL;
+ char * lowerb = block;
+ int found = 0;
+
+ if (block==NULL||aclname==NULL)
+ return NULL;
+
+ while ((name = strstr(block, aclname))!=NULL && !found) {
+ if (name>lowerb) { // This should be true, just in case
+ if ((strchr(set,name[-1])!=0) && (strchr(set,name[strlen(aclname)])!=0)) {
+ // the other 2 sides are in boundary set, that means, this is an exact match.
+ while (&name[-1]>=lowerb) {
+ name --;
+ if (strchr(set, *name)==0)
+ break; // should point to 'l'
+ }
+
+ if (name==lowerb)
+ return NULL;
+
+ if ((name-2)>=lowerb)
+ if ((name[-2]=='a') && (name[-1]=='c') && (*name=='l')) {
+ name -= 2; // name point to 'a'
+ rstr = name;
+ while (TRUE) {
+ if (name==lowerb) {
+ found = 1;
+ break;
+ }
+ else if (name[-1]==' '||name[-1]=='\t')
+ name --;
+ else if (name[-1]=='\n') {
+ found = 1;
+ break;
+ }
+ else
+ break; // acl is not at the head, there are other chars.
+ }
+ }
+ }
+ block = name + strlen(aclname);
+ }
+ }
+ return rstr;
+}
+
+
+
+/*
+ * local function: find the acl string from mapfile and return its acl structure
+ */
+int
+get_acl_from_file(char * filename, char * aclname, ACLListHandle_t ** acllist_pp)
+{
+ int rv = 0;
+ char * pattern=NULL;
+ char header[] = "version 3.0;\n";
+ int headerlen = strlen(header);
+ long filesize;
+ FILE * file;
+ char * mirror=NULL, * text=NULL, *nextname=NULL;
+ char * block=NULL, * aclhead=NULL, * aclend=NULL;
+
+ *acllist_pp = NULL;
+
+ // build the acl name pattern, which should be acl "..."
+ // the ".." is built by acl_to_str_create
+
+ if (aclname==NULL) {
+ rv = ACLERRUNDEF;
+ goto get_cleanup;
+ }
+
+ if ((pattern=(char *)PERM_MALLOC(strlen(aclname) + 1))==NULL) {
+ rv = ACLERRNOMEM;
+ goto get_cleanup;
+ }
+ else {
+ sprintf(pattern,"%s", aclname);
+ str_tolower(pattern);
+ }
+
+ /* get the acl text from the mapfile */
+ if ((rv=open_file_buf(&file, filename, "rb", &block, &filesize))<0)
+ goto get_cleanup;
+
+ if ((mirror = (char *) PERM_MALLOC(filesize+1))==NULL) {
+ rv = ACLERRNOMEM;
+ goto get_cleanup;
+ }
+
+ memcpy(mirror, block, filesize);
+ mirror[filesize]=0;
+ str_tolower(mirror);
+
+ if ((aclhead = acl_strstr(mirror, pattern))!=NULL) {
+ // use mirror to search, then transfer to work on block;
+ aclhead = block + (aclhead - mirror);
+ acl_get_first_name(aclhead+3, &nextname, &aclend);
+ aclend = acl_strstr(aclhead+3, nextname);
+ if (aclend == NULL) {
+ // this is the last acl in the file
+ aclend = &aclhead[strlen(aclhead)];
+ }
+
+ int len = aclend - aclhead;
+ text = (char *) PERM_MALLOC(len + headerlen + 1);
+ sprintf(text, "%s", header);
+ memcpy(&text[headerlen], aclhead, len);
+ text[headerlen + len] = 0;
+
+ if ((*acllist_pp=ACL_ParseString(NULL, text))==NULL) {
+ rv = ACLERRPARSE;
+ }
+ }
+
+get_cleanup:
+ if (pattern)
+ PERM_FREE(pattern);
+ if (file)
+ close_file_buf(file, filename, "rb", block);
+ if (mirror)
+ PERM_FREE(mirror);
+ if (text)
+ PERM_FREE(text);
+ if (nextname)
+ PERM_FREE(nextname);
+ return rv;
+}
+
+
+/*
+ * local function: delete the acl string from mapfile
+ */
+int
+delete_acl_from_file(char * filename, char * aclname)
+{
+ char * pattern=NULL;
+ char header[] = "version 3.0;\n";
+ int headerlen = strlen(header);
+ int rv = ACLERRUNDEF;
+ long filesize;
+ FILE * file;
+ char * mirror=NULL, * text=NULL, * nextname=NULL;
+ char * block=NULL, * aclhead=NULL, * aclend=NULL;
+ int remain;
+
+ // build the acl name pattern, which should be acl "..."
+ // the ".." is built by acl_to_str_create
+
+ if (aclname==NULL) {
+ rv = ACLERRUNDEF;
+ goto delete_cleanup;
+ }
+
+ if ((pattern=(char *)PERM_MALLOC(strlen(aclname) + 10))==NULL) {
+ rv = ACLERRNOMEM;
+ goto delete_cleanup;
+ }
+ else {
+ sprintf(pattern,"%s", aclname);
+ str_tolower(pattern);
+ }
+
+ /* file the acl text from the mapfile */
+ if ((rv=open_file_buf(&file, filename, "rb", &block, &filesize))<0)
+ goto delete_cleanup;
+
+ if ((mirror = (char *) PERM_MALLOC(filesize+1))==NULL) {
+ rv = ACLERRNOMEM;
+ goto delete_cleanup;
+ }
+
+ memcpy(mirror, block, filesize);
+ mirror[filesize]=0;
+ str_tolower(mirror);
+
+ if ((aclhead = acl_strstr(mirror, pattern))!=NULL) {
+ // use mirror to search, then transfer to work on block;
+ aclhead = block + (aclhead - mirror);
+ acl_get_first_name(aclhead+3, &nextname, &aclend);
+ aclend = acl_strstr(aclhead+3, nextname);
+ if (aclend == NULL) {
+ // this is the last acl in the file
+ aclend = &aclhead[strlen(aclhead)];
+ }
+
+ int len = aclend - aclhead;
+ text = (char *) PERM_MALLOC(len + headerlen + 1);
+ sprintf(text, "%s", header);
+ memcpy(&text[headerlen], aclhead, len);
+ text[headerlen + len] = 0;
+
+ if (ACL_ParseString(NULL, text)==NULL) {
+ rv = ACLERRPARSE;
+ goto delete_cleanup;
+ }
+ }
+
+ if (aclhead!=NULL) { // found the acl in the map file
+
+ // int filesize = mpfile->Size();
+
+ remain = strlen(aclend);
+ if (memcpy(aclhead, aclend, remain)!=NULL)
+ rv = 0;
+ else
+ rv = ACLERRIO;
+
+ aclhead[remain]=0;
+
+ block = (char *) PERM_REALLOC(block, strlen(block)+1);
+ }
+ else
+ rv = ACLERRUNDEF;
+
+delete_cleanup:
+ if (pattern)
+ PERM_FREE(pattern);
+ if (text)
+ PERM_FREE(text);
+ if (mirror)
+ PERM_FREE(mirror);
+ if (nextname)
+ PERM_FREE(nextname);
+ if (file)
+ close_file_buf(file, filename, "wb", block);
+ return rv;
+}
+
+/*
+ * local function: append the acl string to file
+ */
+int
+append_acl_to_file(char * filename, char * aclname, char * acltext)
+{
+ int rv;
+ /* acltext has been parsed to verify syntax up to this point */
+ char * pattern=NULL;
+ char * start=NULL;
+ char * block;
+ long filesize;
+ FILE * file;
+ long len;
+
+ if ((pattern=(char *)PERM_MALLOC(strlen(aclname) + 10))==NULL) {
+ rv = ACLERRNOMEM;
+ goto append_cleanup;
+ }
+ else {
+ sprintf(pattern,"%s", aclname);
+ }
+
+ if ((rv=open_file_buf(&file, filename, "rb", &block, &filesize))<0)
+ goto append_cleanup;
+
+ // find the begining of acl, skip the version part
+
+ len = strlen(block);
+ start = acl_strstr(acltext, pattern);
+ if ((block=(char *)PERM_REALLOC(block, len+strlen(start)+1))==NULL) {
+ rv = ACLERRNOMEM;
+ goto append_cleanup;
+ }
+ strcat(block, start);
+
+append_cleanup:
+ if (pattern)
+ PERM_FREE(pattern);
+ if (file)
+ close_file_buf(file, filename, "wb", block);
+
+ return rv;
+}
+
+
+
+/*
+ * local function: rename the acl name in the file
+ */
+int
+rename_acl_in_file(char * filename, char * aclname, char * newname)
+{
+ ACLListHandle_t * racllist=NULL;
+ char * pattern=NULL;
+ char header[] = "version 3.0;\n";
+ int headerlen = strlen(header);
+ int rv = 0;
+ long filesize;
+ FILE * file;
+ int remain;
+ long len;
+ char * text=NULL, * mirror=NULL, * nextname=NULL;
+ char * block=NULL, * aclhead=NULL, * aclend=NULL;
+ char * cut=NULL;
+ acl_string_t str_t = {NULL,0,0};
+
+ // build the acl name pattern, which should be acl "..."
+ // the ".." is built by acl_to_str_create
+
+ if (aclname==NULL || newname==NULL) {
+ rv = ACLERRUNDEF;
+ goto rename_cleanup;
+ }
+
+ if ((pattern=(char *)PERM_MALLOC(strlen(aclname) + 10))==NULL) {
+ rv = ACLERRNOMEM;
+ goto rename_cleanup;
+ }
+ else {
+ sprintf(pattern,"%s", aclname);
+ str_tolower(pattern);
+ }
+
+ // file the acl text from the mapfile
+ if ((rv=open_file_buf(&file, filename, "rb", &block, &filesize))<0)
+ goto rename_cleanup;
+
+ if ((mirror = (char *) PERM_MALLOC(filesize+1))==NULL) {
+ rv = ACLERRNOMEM;
+ goto rename_cleanup;
+ }
+
+ memcpy(mirror, block, filesize);
+ mirror[filesize]=0;
+ str_tolower(mirror);
+
+ if ((aclhead = acl_strstr(mirror, pattern))!=NULL) {
+ // use mirror to search, then transfer to work on block;
+ aclhead = block + (aclhead - mirror);
+ acl_get_first_name(aclhead+3, &nextname, &aclend);
+ aclend = acl_strstr(aclhead+3, nextname);
+ if (aclend == NULL) {
+ // this is the last acl in the file
+ aclend = &aclhead[strlen(aclhead)];
+ }
+
+ len = aclend - aclhead;
+ text = (char *) PERM_MALLOC(len + headerlen + 1);
+ sprintf(text, "%s", header);
+ memcpy(&text[headerlen], aclhead, len);
+ text[headerlen + len] = 0;
+
+ if ((racllist=ACL_ParseString(NULL, text))==NULL) {
+ rv = ACLERRPARSE;
+ goto rename_cleanup;
+ }
+ }
+
+ if (aclhead!=NULL) { // found the acl in the map file
+
+ remain = strlen(aclend);
+ // delete the acltext from where it is
+ if (memcpy(aclhead, aclend, remain)!=NULL)
+ rv = 0;
+ else
+ rv = ACLERRUNDEF;
+
+ aclhead[remain] = 0;
+ len = strlen(block);
+
+ /* establish the renamed the acl */
+ acl_to_str_append(&str_t, "acl \"");
+ acl_to_str_append(&str_t, newname);
+ acl_to_str_append(&str_t, "\";");
+ /* skip acl "..."; the semicollon in the last counts for the +1
+ add the rest acl text to str_t */
+ cut = strchr(text, ';'); // skip version ...;
+ cut = strchr(cut+1, ';') + 1; // skip acl ...;
+ if (cut==NULL) {
+ rv = ACLERRUNDEF;
+ goto rename_cleanup;
+ }
+ acl_to_str_append(&str_t, cut);
+ // acl_to_str_append(&str_t, "\n");
+
+ if ((block=(char *) PERM_REALLOC(block, len + strlen(str_t.str) + 1))==NULL) {
+ rv = ACLERRNOMEM;
+ goto rename_cleanup;
+ }
+ // strcat(block, "\n");
+ strcat(block, str_t.str);
+ }
+ else
+ rv = ACLERRUNDEF;
+
+rename_cleanup:
+ if (pattern)
+ PERM_FREE(pattern);
+ if (text)
+ PERM_FREE(text);
+ if (mirror)
+ PERM_FREE(mirror);
+ if (nextname)
+ PERM_FREE(nextname);
+ if (str_t.str)
+ PERM_FREE(str_t.str);
+ if (file)
+ close_file_buf(file, filename, "wb", block);
+ return rv;
+}
+
+
+/*
+ * Retrieves the definition of a named ACL
+ *
+ * Input:
+ * errp a error stack
+ * filename Target ACL file
+ * acl_name Name of the target ACL
+ * acl_text a dynmaically allocated text (result)
+ * Output:
+ * errp error stack is set on error
+ * Returns:
+ * 0 success
+ * <0 failure
+ */
+NSAPI_PUBLIC int
+ACL_FileGetAcl(NSErr_t *errp,
+ char *filename,
+ char *acl_name,
+ // ACLListHandle_t **acllist_p,
+ char ** acltext,
+ int flags)
+{
+ int rv;
+ ACLListHandle_t * acllist_p;
+
+ if (acl_parse_crit == NULL)
+ acl_parse_crit = crit_init();
+
+ crit_enter( acl_parse_crit );
+
+ rv = get_acl_from_file(filename, acl_name, &acllist_p);
+
+ if (acllist_p == NULL) {
+ *acltext = NULL;
+ goto get_cleanup;
+ }
+
+ /*
+ if ((rv=ACL_Decompose(errp, acltext, acllist_p))<0) {
+ *acltext = NULL;
+ goto get_cleanup;
+ }
+ */
+ if ((rv=ACL_WriteString(errp, acltext, acllist_p))<0) {
+ *acltext = NULL;
+ goto get_cleanup;
+ }
+
+
+get_cleanup:
+
+ crit_exit( acl_parse_crit );
+
+ return rv;
+}
+
+
+
+/*
+ * Delete a named ACL from an ACL file
+ *
+ * Input:
+ * errp a error stack
+ * filename Target ACL file
+ * acl_name Name of the target ACL
+ * Output:
+ * errp error stack is set on error
+ * Returns:
+ * 0 success
+ * < 0 failure
+ */
+
+NSAPI_PUBLIC int
+ACL_FileDeleteAcl(NSErr_t *errp,
+ char *filename,
+ char *acl_name,
+ int flags)
+{
+ int rv = 0;
+
+ if ( acl_parse_crit == NULL )
+ acl_parse_crit = crit_init();
+
+ crit_enter( acl_parse_crit );
+
+ rv = delete_acl_from_file(filename, acl_name);
+
+ crit_exit( acl_parse_crit );
+ return(rv);
+}
+
+
+/*
+ * Sets the definition of an ACL in an ACL file
+ *
+ * Input:
+ * errp a error stack
+ * filename Target ACL file
+ * acl_name Name of the target ACL
+ * acl_text a string that defines the new ACL
+ * Output:
+ * errp error stack is set on error
+ * Returns:
+ * 0 success
+ * < 0 failure
+ */
+
+NSAPI_PUBLIC int
+ACL_FileSetAcl(NSErr_t *errp,
+ char *filename,
+ char *acl_text,
+ int flags)
+{
+ int rv = 0;
+ ACLListHandle_t *new_acl_list = NULL;
+ char **acl_name_list = NULL;
+
+ if ( acl_parse_crit == NULL )
+ acl_parse_crit = crit_init();
+
+ crit_enter( acl_parse_crit );
+
+ // get the acl name.
+ new_acl_list = ACL_ParseString(errp, acl_text);
+ if ( new_acl_list == NULL ) {
+ rv = ACLERRPARSE;
+ goto set_cleanup;
+ }
+
+ if ( ACL_ListGetNameList(errp, new_acl_list, &acl_name_list) < 0 ) {
+ rv = ACLERRNOMEM;
+ goto set_cleanup;
+ }
+
+
+ delete_acl_from_file(filename, acl_name_list[0]);
+ rv = append_acl_to_file(filename, acl_name_list[0], acl_text);
+
+set_cleanup:
+
+ crit_exit( acl_parse_crit );
+ if (new_acl_list)
+ ACL_ListDestroy(errp, new_acl_list);
+ if (acl_name_list)
+ free(acl_name_list);
+ return(rv);
+}
+
+
+/*
+ * Rename a named ACL in ACL text file
+ *
+ * Input:
+ * errp a error stack
+ * filename Target ACL file
+ * acl_name Name of the target ACL
+ * new_acl_name New ACL name
+ * Output:
+ * errp error stack is set on error
+ * Returns:
+ * 0 success
+ * < 0 failure
+ */
+
+NSAPI_PUBLIC int
+ACL_FileRenameAcl(NSErr_t *errp,
+ char *filename,
+ char *aclname,
+ char *newname,
+ int flags)
+{
+ int rv = 0;
+
+ if ( acl_parse_crit == NULL )
+ acl_parse_crit = crit_init();
+
+ crit_enter( acl_parse_crit );
+
+ rv = rename_acl_in_file(filename, aclname, newname);
+
+ crit_exit( acl_parse_crit );
+ return(rv);
+
+}
+
+
+//
+// Merge a list of ACLs into one ACL
+//
+// Input:
+// filename the target acl file
+// acl_list ACLs to merge
+// new_acl_name resultant ACL
+// flags currently ignored
+// Returns:
+// 0 success
+// < 0 failure
+//
+
+NSAPI_PUBLIC int
+ACL_FileMergeAcl(NSErr_t *errp,
+ char *filename,
+ char **acl_name_list,
+ char *new_acl_name,
+ int flags)
+{
+ ACLListHandle_t *new_acl_list = NULL;
+ ACLListHandle_t *tmp_acl_list = NULL;
+ int ii;
+ int rv;
+ ACLHandle_t *tmp_acl;
+ ACLHandle_t *new_acl;
+ ACLExprHandle_t *expr;
+
+
+ tmp_acl_list = ACL_ParseFile(errp, filename);
+ if ( tmp_acl_list == NULL ) {
+ rv = ACLERRPARSE;
+ goto cleanup;
+ }
+
+ new_acl_list = ACL_ParseFile(errp, filename);
+ if ( new_acl_list == NULL ) {
+ rv = ACLERRPARSE;
+ goto cleanup;
+ }
+
+ // first get rid of all the ACLs that will be merged
+
+ for (ii = 0; acl_name_list[ii]; ii++) {
+ rv = ACL_ListAclDelete(errp, new_acl_list, acl_name_list[ii], flags);
+ if ( rv < 0 )
+ goto cleanup;
+ }
+
+ // now create ACL to house the merged result
+ new_acl = ACL_AclNew(errp, new_acl_name);
+ if ( new_acl == NULL ) {
+ rv = ACLERRNOMEM;
+ goto cleanup;
+ }
+
+ rv = ACL_ListAppend(errp, new_acl_list, new_acl, flags);
+ if ( rv < 0 )
+ goto cleanup;
+
+ for (ii = 0; acl_name_list[ii]; ii++) {
+ tmp_acl = ACL_ListFind(errp, tmp_acl_list, acl_name_list[ii], flags);
+ if ( tmp_acl == NULL ) {
+ rv = ACLERRUNDEF;
+ goto cleanup;
+ }
+ for (expr = tmp_acl->expr_list_head; expr; expr = expr->expr_next) {
+ // This call can't really fail unless we pass it a NULL
+ // or some memory is corrupt.
+ rv = ACL_ExprAppend(errp, new_acl, expr);
+ if ( rv < 0 )
+ goto cleanup;
+ tmp_acl->expr_list_head = expr->expr_next;
+ tmp_acl->expr_count--;
+ }
+
+ // Last bit of clean up so the destroy routine isn't confused.
+
+ tmp_acl->expr_list_tail = NULL;
+ tmp_acl->expr_count = 0;
+ }
+
+ rv = ACL_WriteFile(errp, filename, new_acl_list);
+
+cleanup:
+ if ( new_acl_list )
+ ACL_ListDestroy(errp, new_acl_list);
+ if ( tmp_acl_list )
+ ACL_ListDestroy(errp, tmp_acl_list);
+ return(rv);
+}
+
+//
+// Merge a list of ACL files into one ACL file
+//
+// Input:
+// filename the target acl file
+// file_list ACL files to merge
+// flags currently ignored
+// Returns:
+// 0 success
+// < 0 failure
+//
+
+NSAPI_PUBLIC int
+ACL_FileMergeFile(NSErr_t *errp,
+ char *filename,
+ char **file_list,
+ int flags)
+{
+ ACLListHandle_t *new_acl_list = NULL;
+ ACLListHandle_t *tmp_acl_list = NULL;
+ int ii;
+ int rv;
+
+ // we don't care if they have nothing to do
+
+ if ( filename == NULL || file_list == NULL )
+ return(0);
+
+ new_acl_list = ACL_ListNew(errp);
+ if (new_acl_list == NULL)
+ return(ACLERRNOMEM);
+
+ for (ii = 0; file_list[ii]; ii++) {
+ tmp_acl_list = ACL_ParseFile(errp, file_list[ii]);
+ if (tmp_acl_list == NULL) {
+ rv = ACLERRPARSE;
+ goto cleanup;
+ }
+ rv = ACL_ListConcat(errp, new_acl_list, tmp_acl_list, flags);
+ if ( rv < 0 )
+ goto cleanup;
+ ACL_ListDestroy(errp, tmp_acl_list);
+ tmp_acl_list = NULL;
+ }
+
+ rv = ACL_WriteFile(errp, filename, new_acl_list);
+
+cleanup:
+ if ( new_acl_list )
+ ACL_ListDestroy(errp, new_acl_list);
+ if ( tmp_acl_list )
+ ACL_ListDestroy(errp, tmp_acl_list);
+ return(rv);
+}
+
+/*
+ * Destroy a NameList
+ *
+ * Input:
+ * name_list a dynamically allocated array of strings
+ * Returns:
+ * 0 success
+ * < 0 failure
+ */
+
+NSAPI_PUBLIC int
+ACL_NameListDestroy(NSErr_t *errp, char **name_list)
+{
+ int list_index;
+
+ if ( name_list == NULL )
+ return(ACLERRUNDEF);
+
+ for ( list_index = 0; name_list[list_index]; list_index++ ) {
+ PERM_FREE(name_list[list_index]);
+ }
+ PERM_FREE(name_list);
+ return(0);
+}
+
+
+/*
+ * Gets a name list of consisting of all ACL names for input list.
+ *
+ * Input:
+ * acl_list an ACL List handle
+ * name_list pointer to a list of string pointers
+ * Returns:
+ * 0 success
+ * < 0 failure
+ */
+NSAPI_PUBLIC int
+ACL_ListGetNameList(NSErr_t *errp, ACLListHandle_t *acl_list, char ***name_list)
+{
+ const int block_size = 50;
+ ACLWrapper_t *wrapper;
+ int list_index;
+ int list_size;
+ char **tmp_list;
+ char **local_list;
+ char *name;
+
+
+ if ( acl_list == NULL )
+ return(ACLERRUNDEF);
+
+ list_size = block_size;
+ local_list = (char **) PERM_MALLOC(sizeof(char *) * list_size);
+ if ( local_list == NULL )
+ return(ACLERRNOMEM);
+ list_index = 0;
+ local_list[list_index] = NULL;
+
+ for ( wrapper = acl_list->acl_list_head; wrapper != NULL;
+ wrapper = wrapper->wrap_next ) {
+ if ( wrapper->acl->tag )
+ name = wrapper->acl->tag;
+ else
+ name = "noname";
+ if ( list_index + 2 > list_size ) {
+ list_size += block_size;
+ tmp_list = (char **) PERM_REALLOC(local_list,
+ sizeof(char *) * list_size);
+ if ( tmp_list == NULL ) {
+ ACL_NameListDestroy(errp, local_list);
+ return(ACLERRNOMEM);
+ }
+ local_list = tmp_list;
+ }
+ local_list[list_index] = PERM_STRDUP(name);
+ if ( local_list[list_index] == NULL ) {
+ ACL_NameListDestroy(errp, local_list);
+ return(ACLERRNOMEM);
+ }
+ list_index++;
+ local_list[list_index] = NULL;
+ }
+ *name_list = local_list;
+ return(0);
+}
+
+/*
+ * Gets a name list of consisting of all ACL names from the input aclfile
+ *
+ * Input:
+ * filename acl file
+ * name_list pointer to a list of string pointers
+ * Returns:
+ * 0 success
+ * < 0 failure
+ */
+
+NSAPI_PUBLIC int
+ACL_FileGetNameList(NSErr_t *errp, char * filename, char ***name_list)
+{
+
+ const int block_size = 50;
+ int rv, list_size, list_index;
+ char ** local_list;
+ char * block ;
+ char * name;
+ char * next;
+ long filesize;
+ FILE * file;
+ char * head;
+
+ if ((rv=open_file_buf(&file, filename, "rb", &block, &filesize))<0)
+ goto list_cleanup;
+
+ list_size = block_size;
+ local_list = (char **) PERM_MALLOC(sizeof(char *) * list_size);
+ if ( local_list == NULL ) {
+ rv = ACLERRNOMEM;
+ goto list_cleanup;
+ }
+ list_index = 0;
+ local_list[list_index] = NULL;
+
+ head = block;
+ while ((acl_get_first_name(head, &name, &next))) {
+
+ if (list_index+2 > list_size) {
+ list_size += block_size;
+ char ** tmp_list = (char **) PERM_REALLOC(local_list, sizeof(char *) * list_size);
+ if ( tmp_list == NULL ) {
+ rv = ACLERRNOMEM;
+ goto list_cleanup;
+ }
+ local_list = tmp_list;
+ }
+ // local_list[list_index] = PERM_STRDUP(name);
+ local_list[list_index] = name;
+ if ( local_list[list_index] == NULL ) {
+ rv = ACLERRNOMEM;
+ goto list_cleanup;
+ }
+ list_index++;
+ local_list[list_index] = NULL;
+ head = next;
+ }
+
+ rv = 0;
+ *name_list = local_list;
+
+list_cleanup:
+ if (local_list && rv<0)
+ ACL_NameListDestroy(errp, local_list);
+ if (file)
+ close_file_buf(file, filename, "rb", block);
+
+ return rv;
+}
+
+/*
+ * Changes method to method plus DBTYPE, and registers
+ * databases.
+ *
+ * Input:
+ * errp error stack
+ * acl_list Target ACL list handle
+ * Returns:
+ * 0 success
+ * < 0 failure
+ */
+
+NSAPI_PUBLIC int
+ACL_ListPostParseForAuth(NSErr_t *errp, ACLListHandle_t *acl_list )
+{
+ ACLHandle_t *acl;
+ ACLWrapper_t *wrap;
+ ACLExprHandle_t *expr;
+ char *method;
+ char *database;
+ int rv;
+ ACLDbType_t *dbtype;
+ ACLMethod_t *methodtype;
+
+ if ( acl_list == NULL )
+ return(0);
+
+ for ( wrap = acl_list->acl_list_head; wrap; wrap = wrap->wrap_next ) {
+
+ acl = wrap->acl;
+ if ( acl == NULL )
+ continue;
+
+ for ( expr = acl->expr_list_head; expr; expr = expr->expr_next ) {
+
+ if ( expr->expr_type != ACL_EXPR_TYPE_AUTH ||
+ expr->expr_auth == NULL)
+ continue;
+
+ rv = PListGetValue(expr->expr_auth, ACL_ATTR_METHOD_INDEX,
+ (void **) &method, NULL);
+ if ( rv >= 0 ) {
+ methodtype = (ACLMethod_t *)PERM_MALLOC(sizeof(ACLMethod_t));
+ rv = ACL_MethodFind(errp, method, methodtype);
+ if (rv) {
+ nserrGenerate(errp, ACLERRUNDEF, ACLERR3800, ACL_Program,
+ 3, acl->tag, "method", method);
+ PERM_FREE(methodtype);
+ return(ACLERRUNDEF);
+ }
+
+ rv = PListSetValue(expr->expr_auth, ACL_ATTR_METHOD_INDEX,
+ methodtype, NULL);
+ if ( rv < 0 ) {
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR3810, ACL_Program,
+ 0);
+ return(ACLERRNOMEM);
+ }
+ PERM_FREE(method);
+ }
+
+ rv = PListGetValue(expr->expr_auth, ACL_ATTR_DATABASE_INDEX,
+ (void **) &database, NULL);
+
+ if (rv < 0) continue;
+
+ /* The following function lets user use databases which are
+ * not registered by their administrators. This also fixes
+ * the backward compatibility.
+ */
+ dbtype = (ACLDbType_t *)PERM_MALLOC(sizeof(ACLDbType_t));
+ rv = ACL_RegisterDbFromACL(errp, (const char *) database,
+ dbtype);
+
+ if (rv < 0) {
+ nserrGenerate(errp, ACLERRUNDEF, ACLERR3800, ACL_Program,
+ 3, acl->tag, "database", database);
+ PERM_FREE(dbtype);
+ return(ACLERRUNDEF);
+ }
+
+ rv = PListInitProp(expr->expr_auth, ACL_ATTR_DBTYPE_INDEX, ACL_ATTR_DBTYPE,
+ dbtype, NULL);
+ if ( rv < 0 ) {
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR3810, ACL_Program,
+ 0);
+ return(ACLERRNOMEM);
+ }
+
+ }
+
+ }
+
+ return(0);
+
+}
+
+/*
+ * LOCAL FUNCTION
+ *
+ * Output Authorization Expression Rights "right, right"
+ */
+
+static int
+acl_decompose_expr_arg( acl_string_t *str_t, ACLExprHandle_t *expr )
+{
+int ii;
+
+ if ( expr->expr_argc <= 0 ) {
+ return(ACLERRINTERNAL);
+ }
+
+ if ( expr->expr_type == ACL_EXPR_TYPE_RESPONSE ) {
+ acl_to_str_append(str_t, expr->expr_argv[0]);
+ acl_to_str_append(str_t, " \"");
+ acl_to_str_append(str_t, expr->expr_argv[1]);
+ acl_to_str_append(str_t, "\";\n");
+ return(0);
+ }
+
+ for (ii = 0; ii < expr->expr_argc; ii++) {
+ acl_to_str_append(str_t, expr->expr_argv[ii]);
+ if ( ii < expr->expr_argc - 1 ) {
+ acl_to_str_append(str_t, ",");
+ }
+ }
+ acl_to_str_append(str_t, ";\n");
+
+ return(0);
+}
+
+/*
+ * LOCAL FUNCTION
+ *
+ * Walks through the authentication statement PList_t and
+ * prints the structure to a string.
+ */
+
+static void
+acl_decompose_auth_expr(char *lval, const void *rval, void *user_data)
+{
+ acl_string_t * p_aclstr = (acl_string_t *) user_data;
+ // ####
+
+ acl_to_str_append(p_aclstr, " ");
+ acl_to_str_append(p_aclstr, lval);
+ acl_to_str_append(p_aclstr, "=\"");
+ acl_to_str_append(p_aclstr, (char *) rval);
+ acl_to_str_append(p_aclstr, "\"");
+
+ return;
+}
+
+/*
+ * LOCAL FUNCTION
+ *
+ * Output the logic part of the authencation statement to a string.
+ */
+
+static int
+acl_decompose_auth_logic( acl_string_t * str_t, ACLExprHandle_t *expr)
+{
+
+ if ( expr->expr_auth == NULL )
+ return(0);
+
+ acl_to_str_append(str_t, "exprs");
+ PListEnumerate(expr->expr_auth, acl_decompose_auth_expr, (void *) str_t);
+ acl_to_str_append(str_t, ";\n");
+
+ return(0);
+}
+
+/*
+ * LOCAL FUNCTION
+ *
+ * Output the logic part of the authorization statement to a string.
+ */
+
+static int
+acl_decompose_expr_logic( acl_string_t *str_t, ACLExprHandle_t *expr, ACLExprStack_t *expr_stack)
+{
+int rv = 0;
+int ii;
+
+ expr_stack->stack_index = 0;
+ expr_stack->found_subexpression = 0;
+ expr_stack->last_subexpression = -1;
+
+ for (ii = 0; ii < expr->expr_raw_index; ii++) {
+ rv = acl_reduce_expr_logic(expr_stack, &expr->expr_raw[ii]);
+ if (rv) break;
+ }
+
+ if (!rv && expr_stack->expr_text[0]) {
+ acl_to_str_append(str_t, "exprs ");
+ acl_to_str_append(str_t, expr_stack->expr_text[0]);
+ acl_to_str_append(str_t, ";\n");
+ PERM_FREE(expr_stack->expr_text[0]);
+ }
+
+ return(rv);
+}
+
+static int
+acl_decompose(acl_string_t *str_t, ACLListHandle_t *acl_list)
+{
+ACLWrapper_t *wrap;
+ACLHandle_t *acl;
+ACLExprHandle_t *expr;
+int rv = 0;
+ACLExprStack_t *expr_stack;
+
+ expr_stack = (ACLExprStack_t *) PERM_MALLOC(sizeof(ACLExprStack_t));
+ if ( expr_stack == NULL )
+ return(ACLERRNOMEM);
+
+ if ( acl_list->acl_list_head == NULL ) {
+ PERM_FREE(expr_stack);
+ return(0);
+ }
+
+ acl_to_str_append(str_t, "version 3.0;");
+ for (wrap = acl_list->acl_list_head; wrap && !rv;
+ wrap = wrap->wrap_next ) {
+ acl = wrap->acl;
+ if ( acl->tag ) {
+ acl_to_str_append(str_t, "\nname \"");
+ acl_to_str_append(str_t, acl->tag);
+ acl_to_str_append(str_t, "\";\n");
+ } else {
+ acl_to_str_append(str_t, "\nname;\n");
+ }
+
+ for (expr = acl->expr_list_head; expr && rv == 0;
+ expr = expr->expr_next ) {
+
+ switch (expr->expr_type) {
+ case ACL_EXPR_TYPE_DENY:
+ acl_to_str_append(str_t, "type deny;\nrights ");
+ if ( (rv = acl_decompose_expr_arg(str_t, expr)) < 0 )
+ break;
+ if ( IS_ABSOLUTE(expr->expr_flags) )
+ acl_to_str_append(str_t, "absolute true;\n");
+ rv = acl_decompose_expr_logic(str_t, expr, expr_stack);
+ break;
+ case ACL_EXPR_TYPE_ALLOW:
+ acl_to_str_append(str_t, "type allow;\nrights ");
+ if ( (rv = acl_decompose_expr_arg(str_t, expr)) < 0 )
+ break;
+ if ( IS_ABSOLUTE(expr->expr_flags) )
+ acl_to_str_append(str_t, "absolute true;\n");
+ rv = acl_decompose_expr_logic(str_t, expr, expr_stack);
+ break;
+ case ACL_EXPR_TYPE_AUTH:
+ acl_to_str_append(str_t, "type authenticate;\nattrs ");
+ if ( (rv = acl_decompose_expr_arg(str_t, expr)) < 0 )
+ break;
+ if ( IS_ABSOLUTE(expr->expr_flags) )
+ acl_to_str_append(str_t, "absolute true;\n");
+ rv = acl_decompose_auth_logic(str_t, expr);
+ break;
+ case ACL_EXPR_TYPE_RESPONSE:
+ acl_to_str_append(str_t, "type response;\nattrs ");
+ rv = acl_decompose_expr_arg(str_t, expr);
+ break;
+ }
+ }
+ }
+
+ PERM_FREE(expr_stack);
+ return(rv);
+}
+
+/*
+ * Converts an ACLListHandle_t to a parameter list suitable for passing
+ * to the ACL UI.
+ *
+ * Input:
+ * errp error stack
+ * acl a pointer to a string, holds the result of the
+ * decomposition.
+ * acl_list Target ACL list handle
+ * Returns:
+ * 0 success
+ * < 0 failure
+ */
+
+NSAPI_PUBLIC int
+ACL_Decompose(NSErr_t *errp, char **acl, ACLListHandle_t *acl_list)
+{
+ int rv ;
+ acl_string_t aclstr={NULL,0,0};
+
+ if ( acl_list == NULL || acl == NULL )
+ return(ACLERRUNDEF);
+
+ rv = acl_decompose(&aclstr, acl_list);
+ *acl = aclstr.str;
+
+ return ( rv );
+}
+
+/*
+ * The following routines are used to validate input parameters. They always
+ * return 1, or cause an NS_ASSERT failure. The proper way to use them is
+ * with an NS_ASSERT in the calling function. E.g.
+ * NS_ASSERT(ACL_AssertAcllist(acllist));
+ */
+
+int
+ACL_AssertAcllist(ACLListHandle_t *acllist)
+{
+ ACLWrapper_t *wrap;
+
+ if (acllist == ACL_LIST_NO_ACLS) return 1;
+ NS_ASSERT(acllist);
+ NS_ASSERT(acllist->acl_list_head);
+ NS_ASSERT(acllist->acl_list_tail);
+ NS_ASSERT(acllist->acl_count);
+ NS_ASSERT(acllist->ref_count > 0);
+
+ for (wrap=acllist->acl_list_head; wrap; wrap=wrap->wrap_next) {
+ NS_ASSERT(ACL_AssertAcl(wrap->acl));
+ }
+
+ /* Artificially limit ACL lists to 10 ACLs for now */
+ NS_ASSERT(acllist->acl_count < 10);
+
+ return 1;
+}
+
+int
+ACL_AssertAcl(ACLHandle_t *acl)
+{
+ NS_ASSERT(acl);
+ NS_ASSERT(acl->ref_count);
+ NS_ASSERT(acl->expr_count);
+ NS_ASSERT(acl->expr_list_head);
+ NS_ASSERT(acl->expr_list_tail);
+
+ return 1;
+}
+
+static PList_t ACLAttr2IndexPList = NULL;
+
+int
+ACL_InitAttr2Index(void)
+{
+ int i;
+
+ if (ACLAttr2IndexPList) return 0;
+
+ ACLAttr2IndexPList = PListNew(NULL);
+ for (i = 1; i < ACL_ATTR_INDEX_MAX; i++) {
+ PListInitProp(ACLAttr2IndexPList, NULL, ACLAttrTable[i], (const void *)i, NULL);
+ }
+
+ return 0;
+}
+
+/*
+ * Attempt to locate the index number for one of the known attribute names
+ * that are stored in plists. If we can't match it, just return 0.
+ */
+int
+ACL_Attr2Index(const char *attrname)
+{
+ int index = 0;
+
+ if ( ACLAttr2IndexPList ) {
+ PListFindValue(ACLAttr2IndexPList, attrname, (void **)&index, NULL);
+ if (index < 0) index = 0;
+ }
+ return index;
+}